标签:
Time Limit: 5000MS | Memory Limit: 131072K | |
Total Submissions: 73163 | Accepted: 22585 | |
Case Time Limit: 2000MS |
Description
You have N integers, A1, A2, ... , 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 A1, A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"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.
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
Source
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”,这个题耗了我一天加一上午,但也让我对线段树更加深入了解,试遍了各种错误,模板更加完善,,,也不错。。。。
标签:
原文地址:http://www.cnblogs.com/CXCXCXC/p/4626597.html