这道题属于线段树的区间修改
给出一个序列,对其进行Q次操作,
"C a b c" means adding c to each of Aa, Aa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of Aa, Aa+1, ... , Ab.
注意,这道题我wa了4次,在那里查了3个小时,wa原因,一个应该是long long 型的被我写成了int ,悲剧的开始。
讲讲我对线段树区间修改的理解吧。
需要有个操作,建树,更新,维护,查询。
1.建树:首先就是把数据建起来嘛,是一个dfs的过程,对于一个节点,若该节点的区间只有一个,则为叶子节点,对该叶子进行赋值,否则建其左子树,和右子树,
然后在递归结束前进行维护,更新该节点本身的信息。
2.更新:更新的时候不断递归,直到递归边界 (L<=l&&R>=r),对于每一个递归,在递归结束之前需要重新计算本节点的附加信息。
3.维护:维护就是维护一个节点的信息,2中说要在递归 结束之前重新计算本节点的附加信息,怎么计算,就是用到维护这个操作了。
4查询:查询的时候是不断递归,直到递归边界(L<=l&&R>=r) 时,用边界区间的附加信息更新答案。
sum[i] : 维护 i 对应区间的数据的和。
addv[i] : 表示 i 对应区间的每一个数据都需要加 addv[i] ,所以每一个边界区间的结果不能直接使用,还要考虑祖先节点对她的影响。
1 #include<cstdio> 2 #include<cstring> 3 #define lson l,m,rt<<1 4 #define rson m+1,r,rt<<1|1 5 const int maxn=100000+10; 6 long long sum[maxn<<2]; 7 long long addv[maxn<<2]; 8 void maintain(int l,int r,int rt) 9 { 10 sum[rt]=0; 11 if(r>l) 12 sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 13 sum[rt]+=addv[rt]*(r-l+1); 14 } 15 void build(int l,int r,int rt) 16 { 17 if(l==r){ 18 scanf("%I64d",&addv[rt]); 19 } 20 else{ 21 int m=(l+r)>>1; 22 build(lson); 23 build(rson); 24 } 25 maintain(l,r,rt); 26 } 27 void update(int L,int R,int w,int l,int r,int rt) 28 { 29 if(L<=l&&R>=r){ 30 addv[rt]+=w; 31 } 32 else{ 33 int m=(l+r)>>1; 34 if(L<=m) 35 update(L,R,w,lson); 36 if(R>m) 37 update(L,R,w,rson); 38 } 39 maintain(l,r,rt); 40 } 41 long long _sum; 42 void query(int L,int R,int l,int r,int rt,long long add) 43 { 44 if(L<=l&&R>=r) 45 _sum+=sum[rt]+add*(r-l+1); 46 else{ 47 int m=(l+r)>>1; 48 if(L<=m) 49 query(L,R,lson,add+addv[rt]); 50 if(R>m) 51 query(L,R,rson,add+addv[rt]); 52 } 53 } 54 int main() 55 { 56 int n,q; 57 while(scanf("%d%d",&n,&q)!=EOF) 58 { 59 memset(addv,0,sizeof(addv)); 60 build(1,n,1); 61 char s[3]; 62 int u,v,w; 63 for(int i=1;i<=q;i++){ 64 scanf("%s",&s); 65 if(s[0]=='C'){ 66 scanf("%d%d%d",&u,&v,&w); 67 update(u,v,w,1,n,1); 68 } 69 else{ 70 scanf("%d%d",&u,&v); 71 _sum=0; 72 query(u,v,1,n,1,0); 73 printf("%I64d ",_sum); 74 } 75 } 76 } 77 return 0; 78 }