对于形如修改部分区间同时对部分区间求和一类问题,我们可以设原数组 ,差分数组为 ,有

当需要在区间 加上 时,修改 两点即可,问题是如何快速求出给定区间 的和。也即求形如

的和。将差分数组带入得

于是

  • ,
  • ,
  • ...

于是原式化为

进一步的有

到这里,我们维护两个差分数组 即可快速求出 的区间和,同时支持区间修改。

如果是修改区间 的同时求出单点 ,那就更简单了,维护一个差分数组 即可。

#include<iostream>
#define int long long

const int N = 5e5 + 10;
int d[N];
int d_i[N];

inline int lowbit(int x) { return x & -x; }

int query(int n,int d[])
{
	int sum = 0;
	while (n)
	{
		sum += d[n];
		n -= lowbit(n);
	}
	return sum;
}

void add(int n, int x,int d[])
{
	while (n < N)
	{
		d[n] += x;
		n += lowbit(n);
	}
}

signed main()
{
	std::ios::sync_with_stdio(false), std::cin.tie(nullptr);
	int n, m;
	std::cin >> n >> m;
	int pre = 0, curr = 0;
	for (int i = 1; i <= n; i++)
	{
		std::cin >> curr;
		add(i, curr-pre,d);
		add(i, i * (curr - pre), d_i);
		pre = curr;
	}
	int op, x, y, k;
	for (int i = 1; i <= m; i++)
	{
		std::cin >> op;
		if (op == 1)
		{
			std::cin >> x >> y >> k;
			add(x, k,d);
			add(y + 1, -k,d);
			add(x, x * k, d_i);
			add(y + 1, -(y + 1) * k, d_i);
		}
		else
		{
			std::cin >> x >> y;
			std::cout << (y + 1) * query(y, d) - query(y, d_i) -
				(x * query(x - 1, d) - query(x - 1, d_i)) << '\n';
		}
	}
}