POJ 3468 A Simple Problem with Integers(线段树区间更新)
这个真费劲。。。其实我也不懂 为什么。。。大体思想是,如果把区间更新了,开始的时候只把用懒惰标记标记那个区间,而不更新底层元素,而如果查询的时候顺带着把lz标记给消除。。。多敲几遍,多调试一下,看看中间过程,就应该理解了。
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #define N 100001 5 #define ll __int64 6 ll p[4*N],lz[4*N]; 7 void pushup(int rt) 8 { 9 p[rt] = p[rt<<1]+p[rt<<1|1]; 10 } 11 void pushdown(int rt,int m)//消除懒惰标记,m记录区间长度 12 { 13 if(lz[rt]) 14 { 15 lz[rt<<1] += lz[rt];//把他传递给儿子们 16 lz[rt<<1|1] += lz[rt]; 17 p[rt<<1] += lz[rt]*(m - (m>>1));//更新线段树上的元素,注意位运算优先级的比较低啊!! 18 p[rt<<1|1] += lz[rt]*(m>>1); 19 lz[rt] = 0;//消除标记 20 } 21 } 22 void build(int l,int r,int rt)//建树 23 { 24 int m; 25 lz[rt] = 0; 26 if(l == r) 27 { 28 scanf("%I64d%*c",&p[rt]); 29 return ; 30 } 31 m = (l+r)>>1; 32 build(l,m,rt<<1); 33 build(m+1,r,rt<<1|1); 34 pushup(rt); 35 } 36 ll query(int L,int R,int l,int r,int rt)//L,R表示最后查询的区间。l,r表示中间过程历遍的区间。 37 { 38 int m; 39 ll sum = 0; 40 if(l >= L&&r <= R) 41 { 42 return p[rt];//如果l-r在L-R之间的话,直接返回 43 } 44 pushdown(rt,r - l + 1);//消除懒惰标记 45 m = (l + r) >> 1; 46 if(L <= m)//查找 47 sum += query(L,R,l,m,rt<<1); 48 if(R > m) 49 sum += query(L,R,m+1,r,rt<<1|1); 50 return sum; 51 } 52 void update(int L,int R,int l,int r,int rt,int sc) 53 { 54 int m; 55 if(l >= L&&r <= R) 56 { 57 lz[rt] += sc;//标记懒惰 58 p[rt] += sc*(r - l + 1); 59 return ; 60 } 61 pushdown(rt,r-l+1); 62 m = (l + r) >> 1; 63 if(L <= m) update(L,R,l,m,rt<<1,sc); 64 if(R > m) update(L,R,m+1,r,rt<<1|1,sc); 65 pushup(rt); 66 } 67 int main() 68 { 69 int n,m,i,x,y,z; 70 char str[10]; 71 scanf("%d%d",&n,&m); 72 build(1,n,1); 73 for(i = 1; i <= m; i ++) 74 { 75 scanf("%s%d%d%*c",str,&x,&y); 76 if(str[0] == 'Q') 77 { 78 printf("%I64d\n",query(x,y,1,n,1)); 79 } 80 else if(str[0] == 'C') 81 { 82 scanf("%d%*c",&z); 83 update(x,y,1,n,1,z); 84 } 85 } 86 return 0; 87 }