原题链接
考察:树状数组+差分

上一道题的加强版,但还是结合差分数组
思路:
  操作一:"C a b c"表示给[a, b]区间中的值全部增加c (-10000 ≤ c ≤ 10000)。
  这里还是得用到差分,设b数组为原数组的差分数组,那么此操作就转化为单点修改
  操作二:"Q a b" 询问[a, b]区间中所有值的和。
  这里就不是差分数组了,而是原数组的前缀和.但是如果我们同时维护两个数组:差分数组和原数组是不可能的,这两个操作在差分数组和原数组必然有时间复杂度的冲突.因此考虑其他做法.
  我们不考虑[l,r]区间的和,直接考虑前缀和更为方便.那么就是求\(\sum_{i=1}^r\) \(\sum_{j=1}^i\)b[j] = \(\sum_{i=1}^r\)a[i]
  而这个式子等价于 \(\sum_{i=1}^r\)(r-i+1)b[i].
这个式子很难求前缀和,因为r与i都是不确定的数.而树状数组只能维护b[i],b[i]+c,b[i]*c这种已确定的常量的前缀和.
  但如果我们把(r+1)
b[i]提取出来,即(r+1)b[i]-ib[i]的前缀和.每次操作r都是常数,i是在变化的,所以还需要维护一个i*b[i]的前缀和.

注意一下long long

#include <iostream> 
#include <cstring>
using namespace std;
typedef long long LL;
const int N = 100010,M = 3;//维护b[i],i*b[i] 
int n,m;
LL tr[2][N],b[N];
char s[M];
void insert(int l,int r,int x)
{
	b[l]+=x,b[r+1]-=x;
}
int lowbit(int x)
{
	return x&-x;
}
void add(int k,int idx,LL x)
{
	for(int i=idx;i<=n;i+=lowbit(i)) tr[k][i]+=x;
}
LL ask(int k,int r)
{
	LL res = 0;
	for(int i=r;i;i-=lowbit(i)) res+=tr[k][i];
	return res;
}
LL get(int l,int r)
{
	LL a = (r+1ll)*ask(0,r)-ask(1,r);
	LL b = l*ask(0,l-1)-ask(1,l-1);
	return a-b;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		int x; scanf("%d",&x);
		insert(i,i,x);
	}
	for(int i=1;i<=n;i++)
		add(0,i,b[i]),add(1,i,(LL)i*b[i]);
	while(m--)
	{
		int r,l,x;
		scanf("%s%d%d",s,&l,&r);
		if(s[0]=='Q')
		{
			printf("%lld\n",get(l,r));
			continue;
		}
		scanf("%d",&x);
		add(0,l,x); add(0,r+1,-x);
		add(1,l,(LL)x*l); add(1,r+1,-(LL)x*(r+1));
	}
	return 0;
}






  到这里可以再补一个解法二.即线段树的区间修改.涉及懒标记.懒标记是标记当前结点的子节点的值需要+tag.
  我们只要三个地方需要加懒标记.

  • 修改区间时,如果当前区间完全被修改区间覆盖,则需要加懒标记
  • 修改区间时,当前区间没有被完全覆盖.这时需要修改子结点区间的值再给子节点加懒标记.懒标记的作用范围是整个区间.不允许部分+-x的情况存在.
  • 查询区间时,当前区间没有被完全覆盖.同上步骤.
    以下为code:
#include <iostream> 
#include <cstring>
using namespace std;
typedef long long LL;
const int N = 100010;
int n,m,a[N];
char s[3];
struct Node{
	int l,r;
	LL val,tag;
}tr[N<<2];
void push_up(int u)
{
	tr[u].val = tr[u<<1].val+tr[u<<1|1].val;
}
void push_down(int u)
{
	LL& tag = tr[u].tag;
	if(!tag) return;
	tr[u<<1].tag +=tag;
	tr[u<<1].val += (tr[u<<1].r-tr[u<<1].l+1)*tag;
	tr[u<<1|1].tag += tag;
	tr[u<<1|1].val += (tr[u<<1|1].r-tr[u<<1|1].l+1)*tag;
	tr[u].tag = 0;
}
void build(int u,int l,int r)
{
	tr[u].l = l,tr[u].r = r;
	if(l==r) {tr[u] = {l,r,a[l],0}; return;} 
	int mid = l+r>>1;
	build(u<<1,l,mid); build(u<<1|1,mid+1,r);
	push_up(u);
}
void modify(int u,int l,int r,int x)
{
	if(tr[u].l>=l&&tr[u].r<=r)
	{
		tr[u].val += (LL)(tr[u].r-tr[u].l+1)*x;
		tr[u].tag+=x;
		return;
	}
	push_down(u);//add 全部区间10与add 部分区间5不能混合 
	int mid = tr[u].l+tr[u].r>>1;
	if(l<=mid) modify(u<<1,l,r,x);
	if(mid<r)  modify(u<<1|1,l,r,x);
	push_up(u);
}
LL query(int u,int l,int r)
{
	if(tr[u].l>=l&&tr[u].r<=r) return tr[u].val;
	int mid = tr[u].l+tr[u].r>>1;
	push_down(u);
	LL res = 0;
	if(l<=mid) res+=query(u<<1,l,r);
	if(mid<r) res+=query(u<<1|1,l,r);
	return res;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	build(1,1,n);
	while(m--)
	{
		int l,r; LL d;
		scanf("%s%d%d",s,&l,&r);
		if(s[0]=='Q') {printf("%lld\n",query(1,l,r));continue;} 
		scanf("%lld",&d);
		modify(1,l,r,d);
	}
	return 0;
}