线段树的lazy(poj3468)

A Simple Problem with Integers
Time Limit: 5000MS   Memory Limit: 131072K
Total Submissions: 73163   Accepted: 22585
Case Time Limit: 2000MS

Description

You have N integers, A1A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.

Input

The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"C a b c" means adding c to each of AaAa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of AaAa+1, ... , Ab.

Output

You need to answer all Q commands in order. One answer in a line.

Sample Input

10 5

1 2 3 4 5 6 7 8 9 10

Q 4 4

Q 1 10

Q 2 4

C 3 6 3

Q 2 4

Sample Output

4

55

9

15

Hint

The sums may exceed the range of 32-bit integers.

Source

 
  最裸的线段树lazy标记
 
 1 #include <iostream>

 2 #include <cstdio>

 3 using namespace std;  4 const int N = 100005;  5 typedef  long long LL;  6 LL sum[N<<2]; //sum用来存储每个节点的子节点数值的总和

 7 LL add[N<<2];//add用来记录该节点的每个数值应该加多少

 8 struct Node{  9     int l,r;//表示改点的左右区间 

10     int mid(){//结构体函数 

11         return (l+r)>>1; 12  } 13 } tree[N<<2]; 14 

15 void PushUp(int rt){//算某一节点的左右孩子值的和 

16     sum[rt] = sum[rt<<1] + sum[rt<<1|1]; 17 } 18 

19 void PushDown(int rt,int m){//rt当前节点 m此节点的区间长度 

20     if(add[rt]!=0){//如果当前节点lazy标记不为 0 

21         add[rt<<1] += add[rt];//左右孩子lazy累加 

22         add[rt<<1|1] += add[rt]; 23         sum[rt<<1] += add[rt]*(m-(m>>1));//更新计算左右孩子 

24         sum[rt<<1|1] += add[rt] * (m>>1); 25         add[rt] = 0;//小细节,但很重要,不能忘记lazy用过后清零 

26  } 27 } 28 

29 void build(int l,int r,int rt){ 30     tree[rt].l = l; 31     tree[rt].r = r; 32     add[rt] = 0;//lazy标记记为0 

33     if(l == r){ 34         scanf("%lld",&sum[rt]);//把子节点信息记录在sum里 

35         return ; 36  } 37     int m = tree[rt].mid(); 38     build(l,m,rt<<1);//建立左右孩子,这时编号是按照类似“宽搜”来编的 

39     build(m+1,r,rt<<1|1); 40     

41     PushUp(rt);//算出此节点的权值 

42 } 43 

44 void update(int c,int l,int r,int rt){//当前节点rt,在l和r区间上加上c 

45     if(l<=tree[rt].l&&tree[rt].r<=r){//当前节点所表示的区间完全被所要更新的区间包含 

46         add[rt]+=c;//lazy累加,add[i]数组是针对i左右孩子的 

47         sum[rt]+=(LL)c*(tree[rt].r-tree[rt].l+1);//这句话很重要和下面的PushUP()类似 

48         return; 49  } 50     PushDown(rt,tree[rt].r - tree[rt].l + 1);//用rt的lazy更新其子节点 

51     int m = tree[rt].mid(); 52     if(l<=m) update(c,l,r,rt<<1); 53     if(m+1<=r) update(c,l,r,rt<<1|1); 54  PushUp(rt); 55 } 56 

57 LL query(int l,int r,int rt){//当前节点为rt,求l,到r的和 

58     if(l<=tree[rt].l&&tree[rt].r<=r){//区间完全包含,可以直接返回 

59         return sum[rt]; 60  } 61     //因为此时用到rt节点,所以才更新lazy 

62     PushDown(rt,tree[rt].r-tree[rt].l + 1); 63     

64     int m = tree[rt].mid(); 65     LL res = 0; 66     

67     if(l<= m)//要求的区间有一部分在mid的左边 

68         res += query(l,r,rt<<1); 69     if(m+1<=r) 70         res += query(l,r,rt<<1|1); 71     return res; 72 } 73 

74 int main(){ 75 

76     int n,m; 77     

78     scanf("%d %d",&n,&m); 79     build(1,n,1); 80        

81     while(m--){ 82     char ch[2]; 83     scanf("%s",ch); 84     int a,b,c; 85     if(ch[0] == 'Q'){ 86         scanf("%d %d", &a,&b); 87         printf("%lld\n",query(a,b,1)); 88  } 89     else{ 90         scanf("%d %d %d",&a,&b,&c); 91         cin>>a>>b>>c; 92         update(c,a,b,1); 93  } 94  } 95     

96     return 0; 97 }

还有一种较好理解的方法:

 1 #include<iostream>

 2 #include<cstdio>

 3 #include<cstdlib>

 4 #include<cmath>

 5 #include<cstring>

 6 #include<algorithm>

 7 using namespace std;  8 typedef long long LL;  9 const LL NN=100005;  10 LL a[NN];  11 LL N,tot,T,M;  12 struct node{  13  LL num;  14  LL lc,rc;  15  LL l,r;  16  LL sum;  17  LL lazy;  18 };  19 

 20 node segtree[2000000];  21 

 22 void Build(LL root,LL l,LL r){  23     segtree[root].l=l;  24     segtree[root].r=r;  25     segtree[root].lazy=0;  26     segtree[root].num=tot;  27     if(l==r){  28         segtree[root].sum=a[l];  29         return ;  30  }  31     

 32     LL mid=(l+r)>>1;  33     

 34     segtree[root].lc=++tot;  35     segtree[segtree[root].lc].num=tot;  36  Build(tot,l,mid);  37     

 38     segtree[root].rc=++tot;  39     segtree[segtree[root].rc].num=tot;  40     Build(tot,mid+1,r);  41     segtree[root].sum=segtree[segtree[root].lc].sum+

 42  segtree[segtree[root].rc].sum;  43 

 44 }  45 

 46 void updatason(LL root){  47     LL d=segtree[root].lazy;  48     if(d!=0){  49         segtree[segtree[root].lc].lazy+=(LL)d;  50         segtree[segtree[root].rc].lazy+=(LL)d;  51         

 52         segtree[segtree[root].lc].sum+=(LL)d*(segtree[segtree[root].lc].r  53                             -segtree[segtree[root].lc].l+1);  54         segtree[segtree[root].rc].sum+=(LL)d*(segtree[segtree[root].rc].r  55                             -segtree[segtree[root].rc].l+1);  56         segtree[root].lazy=0;  57  }  58 }  59 

 60 LL query(LL root,LL l,LL r){  61     if(l<=segtree[root].l&&segtree[root].r<=r){  62         return segtree[root].sum;  63  }  64  updatason(root);  65     LL ans=0;  66     LL mid=(segtree[root].r+segtree[root].l)>>1;  67     if(l<=mid) ans+=(LL)query(segtree[root].lc,l,r);  68     if(mid+1<=r) ans+=(LL)query(segtree[root].rc,l,r);  69     return ans;  70 }  71 

 72 void changesect(LL root,LL l,LL r,LL d){  73     if(l<=segtree[root].l&&segtree[root].r<=r){  74         segtree[root].sum+=(LL)(segtree[root].r-segtree[root].l+1)*d;  75         segtree[root].lazy+=(LL)d;  76         return ;  77  }  78  updatason(root);  79     LL mid=(segtree[root].r+segtree[root].l)>>1;  80     if(l<=mid) changesect(segtree[root].lc,l,r,d);  81     if(mid+1<=r) changesect(segtree[root].rc,l,r,d);  82     segtree[root].sum=(LL)segtree[segtree[root].lc].sum+

 83  (LL)segtree[segtree[root].rc].sum;  84 }  85 int main(){  86 

 87     scanf("%d%d",&N,&M);  88     for(LL i=1;i<=N;i++)  89         scanf("%lld",&a[i]);  90     tot++;  91     Build(1,1,N);  92  LL ll,rr,de;  93     char x[2];  94     for(LL i=1;i<=M;i++){  95         scanf("%s",x);  96         if(x[0]=='C'){  97             cin>>ll>>rr>>de;  98             changesect(1,ll,rr,de);  99             continue; 100  } 101         if(x[0]=='Q'){ 102             cin>>ll>>rr; 103             printf("%lld\n",query(1,ll,rr)); 104  } 105  } 106     return 0; 107 }

  由于此题数据较大,所以要将int 都改为long long 。但这也给了我一个惨痛的教训,如果要在定义变量的时候该类型,千万不要忘记改变函数返回值的类型和输入改成“lld”,这个题耗了我一天加一上午,但也让我对线段树更加深入了解,试遍了各种错误,模板更加完善,,,也不错。。。。

 

 

你可能感兴趣的:(lazy)