题目大意就是给出两个操作: C:将一个区间里的都数增加c ,Q:查询区间(a,b)内的和。多次操作,很明显(原谅我用了这么罪恶的词)要用线段树来维护。
线段树的区间修改和点修改相比多了一个add数组,add数组的作用是在进行区间更新的时候不必将和该区间有关的所有线段都更新,某个线段的add数组的含义是:该线段的子线段的sum值都应该增加add[](该线段的sum值已经增加了)但现在还没增加,也就是相当于延迟的作用某个线段的add延迟信息在要去查询该线段的子区间的时候将会下推(pushdown)去更新它的子区间。
详细请看代码(?)
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = 1e6+10;
long long a[maxn],tree[4*maxn],add[4*maxn];
void build(int p,int l,int r)
{
if(l == r)
{
tree[p] = a[l];
return;
}
int mid = (l + r) / 2;
build(p * 2,l,mid);
build(p * 2 + 1,mid + 1,r);
tree[p] = tree[p * 2] + tree[p * 2 + 1];
}
void push(int p,int l,int r)
{
if(add[p])
{
int mid = (l + r) / 2;
tree[p * 2] += (mid - l + 1) * add[p];
tree[p * 2 + 1] += (r - mid) * add[p];
add[p * 2] += add[p];
add[p * 2 + 1] += add[p];
add[p] = 0;
}
}
void change(int p,int l,int r,int x,int y,long long num)
{
if(x <= l && y >= r)
{
tree[p] += (r - l + 1) * num;
add[p] += num;
return;
}
int mid = (l + r) / 2;
push(p,l,r);
if(x <= mid)
change(p * 2,l,mid,x,y,num);
if(y > mid)
change(p * 2 + 1,mid + 1,r,x,y,num);
tree[p] = tree[p * 2] + tree[p * 2 + 1];
}
long long query(int p,int l,int r,int x,int y)
{
long long ans = 0;
int mid = (l + r) / 2;
if(x <= l && y >= r)
return tree[p];
push(p,l,r);
if(x <= mid)
ans += query(p * 2,l,mid,x,y);
if(y > mid)
ans += query(p * 2 + 1,mid + 1,r,x,y);
return ans;
}
int main()
{
int n,q;
scanf("%d %d",&n,&q);
for(int i = 1;i <= n; i++)
scanf("%lld",&a[i]);
build(1,1,n);
while(q--)
{
char c;
getchar();
scanf("%c",&c);
if(c == 'C')
{
int x,y;
long long num;
scanf("%d %d %lld",&x,&y,&num);
change(1,1,n,x,y,num);
}
else if(c == 'Q')
{
int x,y;
scanf("%d %d",&x,&y);
long long ans = query(1,1,n,x,y);
printf("%lld\n",ans);
}
}
return 0;
}