洛谷 P3372 【模板】线段树 1 题解
题目描述
如题,已知一个数列,你需要进行下面两种操作:
1.将某区间每一个数加上 k。
2.求出某区间每一个数的和。
输入格式
第一行包含两个整数 n, m 分别表示该数列数字的个数和操作的总个数。
第二行包含 n 个用空格分隔的整数,其中第 i 个数字表示数列第 i 项的初始值。
接下来 m 行每行包含 3 或 4 个整数,表示一个操作,具体如下:
1.1 x y k:将区间 [x, y] 内每个数加上 k。
2.2 x y:输出区间 [x, y] 内每个数的和。
输出格式
输出包含若干行整数,即为所有操作 2 的结果。
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int n,m,a[500001],add[500001]; 5 long long sum[500001]; 6 7 void build(int k,int l,int r) //建树 8 { 9 if (l==r) //当前为叶节点 10 { 11 sum[k]=a[l]; 12 return ; 13 } 14 int mid=(l+r)>>1; 15 build(k*2,l,mid); //左子树 16 build(k*2+1,mid+1,r); //右子树 17 sum[k]=sum[k*2]+sum[k*2+1]; 18 } 19 20 void Add(int k,int l,int r,int v) //区间加值并更新 21 { 22 add[k]+=v; //打标记 23 sum[k]+=(long long)v*(r-l+1); //维护区间和 24 } 25 26 void pushdown(int k,int l,int r,int mid) //标记下放 27 { 28 if (add[k]==0) //没有标记 29 return ; 30 else 31 { 32 Add(k*2,l,mid,add[k]); //下传到左子树 33 Add(k*2+1,mid+1,r,add[k]); //下传到右子树 34 add[k]=0; //清零标记 35 } 36 } 37 38 long long query(int k,int l,int r,int x,int y) //询问 39 { 40 if (x<=l&&r<=y) 41 return sum[k]; 42 int mid=(l+r)>>1; 43 long long ans=0; 44 pushdown(k,l,r,mid); //下传标记 45 if (x<=mid) 46 ans+=query(k*2,l,mid,x,y); 47 if (mid<y) 48 ans+=query(k*2+1,mid+1,r,x,y); 49 return ans; 50 } 51 52 void modify(int k,int l,int r,int x,int y,int v) //区间和 53 { 54 if (x<=l&&r<=y) 55 return Add(k,l,r,v); 56 int mid=(l+r)>>1; 57 pushdown(k,l,r,mid); //到达每一个结点都要下传标记 58 if (x<=mid) 59 modify(k*2,l,mid,x,y,v); 60 if (mid<y) 61 modify(k*2+1,mid+1,r,x,y,v); 62 sum[k]=sum[k*2]+sum[k*2+1]; //更新下传之后的最新值 63 } 64 65 int main() 66 { 67 scanf("%d%d",&n,&m); 68 for (int i=1;i<=n;i++) 69 scanf("%d",&a[i]); 70 build(1,1,n); //建树 71 while (m--) 72 { 73 int op,x,y,v; 74 scanf("%d",&op); 75 if (op==1) //在x到y的区间内每个数加上v 76 { 77 scanf("%d%d%d",&x,&y,&v); 78 modify(1,1,n,x,y,v); 79 } 80 if (op==2) //查询x到y的区间和 81 { 82 scanf("%d%d",&x,&y); 83 printf("%lld\n",query(1,1,n,x,y)); 84 } 85 } 86 return 0; 87 }
再附一份没有注释的代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int n,m,a[500001],add[500001]; 5 long long sum[500001]; 6 7 void build(int k,int l,int r) 8 { 9 if (l==r) 10 { 11 sum[k]=a[l]; 12 return ; 13 } 14 int mid=(l+r)>>1; 15 build(k*2,l,mid); 16 build(k*2+1,mid+1,r); 17 sum[k]=sum[k*2]+sum[k*2+1]; 18 } 19 20 void Add(int k,int l,int r,int v) 21 { 22 add[k]+=v; 23 sum[k]+=(long long)v*(r-l+1); 24 } 25 26 void pushdown(int k,int l,int r,int mid) 27 { 28 if (add[k]==0) 29 return ; 30 else 31 { 32 Add(k*2,l,mid,add[k]); 33 Add(k*2+1,mid+1,r,add[k]); 34 add[k]=0; 35 } 36 } 37 38 long long query(int k,int l,int r,int x,int y) 39 { 40 if (x<=l&&r<=y) 41 return sum[k]; 42 int mid=(l+r)>>1; 43 long long ans=0; 44 pushdown(k,l,r,mid); 45 if (x<=mid) 46 ans+=query(k*2,l,mid,x,y); 47 if (mid<y) 48 ans+=query(k*2+1,mid+1,r,x,y); 49 return ans; 50 } 51 52 void modify(int k,int l,int r,int x,int y,int v) 53 { 54 if (x<=l&&r<=y) 55 return Add(k,l,r,v); 56 int mid=(l+r)>>1; 57 pushdown(k,l,r,mid); 58 if (x<=mid) 59 modify(k*2,l,mid,x,y,v); 60 if (mid<y) 61 modify(k*2+1,mid+1,r,x,y,v); 62 sum[k]=sum[k*2]+sum[k*2+1]; 63 } 64 65 int main() 66 { 67 scanf("%d%d",&n,&m); 68 for (int i=1;i<=n;i++) 69 scanf("%d",&a[i]); 70 build(1,1,n); 71 while (m--) 72 { 73 int op,x,y,v; 74 scanf("%d",&op); 75 if (op==1) 76 { 77 scanf("%d%d%d",&x,&y,&v); 78 modify(1,1,n,x,y,v); 79 } 80 if (op==2) 81 { 82 scanf("%d%d",&x,&y); 83 printf("%lld\n",query(1,1,n,x,y)); 84 } 85 } 86 return 0; 87 }

浙公网安备 33010602011771号