线段树模板
区间修改/区间查询
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e5+10,inf = 0x3f3f3f3f; int n,m,a[N],add[N * 4]; ll sum[N * 4]; void build(int k,int l,int r) //建树 { if(l == r) { sum[k] = a[l];return ; } int mid = (l + r) / 2; build(k * 2,l,mid); build(k * 2 + 1,mid + 1,r); sum[k] = sum[k * 2] + sum[k * 2 + 1]; } void Add(int k,int l,int r,int v) //区间加并更新 { add[k] += v; sum[k] += ll(v) * (r - l + 1); } void pushdown(int k,int l,int r,int mid) //标记下传 { if(add[k] == 0)return; Add(k * 2,l,mid,add[k]); Add(k * 2 + 1,mid + 1,r,add[k]); add[k] = 0; } ll query(int k,int l,int r,int x,int y) //查询x到y区间的和 { if(l >= x && r <= y)return sum[k]; int mid = (l + r) / 2; ll res = 0; pushdown(k,l,r,mid); if(x <= mid)res += query(k * 2,l,mid,x,y); if(mid < y)res += query(k * 2 + 1,mid+1,r,x,y); return res; } void modify(int k,int l,int r,int x,int y,int v) //x到y的区间加v { if(l >= x && r <= y)return Add(k,l,r,v); int mid = (l + r) / 2; pushdown(k,l,r,mid); if(x <= mid)modify(k * 2,l,mid,x,y,v); if(mid < y)modify(k * 2 + 1,mid + 1,r,x,y,v); sum[k] = sum[k * 2] + sum[k * 2 + 1]; } int main() { cin >> n >> m; for(int i = 1;i <= n;i++) { scanf("%d",&a[i]); } build(1,1,n); while(m--) { char op;int x,y,z; while((op=getchar())!='Q'&&op!='C'); scanf("%d %d",&x,&y); if(op=='Q') { printf("%lld\n",query(1,1,n,x,y)); } else { scanf("%d",&z); modify(1,1,n,x,y,z); } } return 0; }
区间修改/单点查询,只需要修改query函数的传参即可
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e5+10,inf = 0x3f3f3f3f; int n,m,a[N],add[N * 4]; ll sum[N * 4]; void build(int k,int l,int r) //建树 { if(l == r) { sum[k] = a[l];return ; } int mid = (l + r) / 2; build(k * 2,l,mid); build(k * 2 + 1,mid + 1,r); sum[k] = sum[k * 2] + sum[k * 2 + 1]; } void Add(int k,int l,int r,int v) //区间加并更新 { add[k] += v; sum[k] += ll(v) * (r - l + 1); } void pushdown(int k,int l,int r,int mid) //标记下传 { if(add[k] == 0)return; Add(k * 2,l,mid,add[k]); Add(k * 2 + 1,mid + 1,r,add[k]); add[k] = 0; } ll query(int k,int l,int r,int x,int y) //查询x到y区间的和 { if(l >= x && r <= y)return sum[k]; int mid = (l + r) / 2; ll res = 0; pushdown(k,l,r,mid); if(x <= mid)res += query(k * 2,l,mid,x,y); if(mid < y)res += query(k * 2 + 1,mid+1,r,x,y); return res; } void modify(int k,int l,int r,int x,int y,int v) //x到y的区间加v { if(l >= x && r <= y)return Add(k,l,r,v); int mid = (l + r) / 2; pushdown(k,l,r,mid); if(x <= mid)modify(k * 2,l,mid,x,y,v); if(mid < y)modify(k * 2 + 1,mid + 1,r,x,y,v); sum[k] = sum[k * 2] + sum[k * 2 + 1]; } int main() { cin >> n >> m; for(int i = 1;i <= n;i++) { scanf("%d",&a[i]); } build(1,1,n); while(m--) { char op;int x,y,z; while((op=getchar())!='Q'&&op!='C'); scanf("%d",&x); if(op=='Q') { printf("%lld\n",query(1,1,n,x,x)); //单点查询,所以查询从x到x区间和 } else { scanf("%d %d",&y,&z); modify(1,1,n,x,y,z); } } return 0; }
区间乘mul/区间加add/区间查询
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e5+10,inf = 0x3f3f3f3f; int n,m; int c[N]; ll t[N * 4],add[N * 4],mul[N * 4]; //分别是线段树、加法、乘法 void build(int k,int l,int r) { add[k] = 0; mul[k] = 1; //建树顺便初始化 if(l == r) { t[k] = c[l]; return; } int mid = (l + r) / 2; build(k * 2,l,mid); build(k * 2 + 1,mid + 1,r); t[k] = t[k * 2] + t[k * 2 + 1]; } void pushdown(int k,int l,int r,int mid) { //更新顺序:树、乘、加 //左子树 = 左子树 * k层的积 + [l-mid]区间和 右子树 = 右子树 * k层的积 + [mid-r]区间和 t[k * 2] = t[k * 2] * mul[k] + (mid - l + 1) * add[k]; t[k * 2 + 1] = t[k * 2 + 1] * mul[k] + (r - mid) * add[k]; //乘法 = 左/右儿子 * 父节点mul mul[k * 2] = mul[k * 2] * mul[k]; mul[k* 2 + 1] = mul[k * 2 + 1] * mul[k]; //加法 = 左右儿子 * 父节点mul + 父节点add add[k * 2] = add[k * 2] * mul[k] + add[k]; add[k * 2 + 1] = add[k * 2 + 1] * mul[k] + add[k]; mul[k] = 1; add[k] = 0; //重置父节点 } void multiply(int k,int l,int r,int a,int b,int w) { if(l > b || r < a)return; if(l >= a && r <= b) { //乘法 : 树、乘、加都要乘w mul[k] *= w; add[k] *= w; t[k] *= w; return; } int mid = (l + r) / 2; pushdown(k,l,r,mid); multiply(k * 2,l,mid,a,b,w); multiply(k * 2 + 1,mid + 1,r,a,b,w); t[k] = t[k * 2] + t[k * 2 + 1]; } void modify(int k,int l,int r,int a,int b,int w) { if(l > b || r < a)return; if(l >= a && r <= b) { t[k] += w * (r - l + 1); //k层 的[l-r]区间和都加上w add[k] += w; return; } int mid = (l + r) / 2; pushdown(k,l,r,mid); modify(k * 2,l,mid,a,b,w); modify(k * 2 + 1,mid + 1,r,a,b,w); t[k] = t[k * 2] + t[k * 2 + 1]; } ll query(int k,int l,int r,int a,int b) { if(l > b || r < a)return 0; if(l >= a && r <= b)return t[k]; int mid = (l + r) / 2; pushdown(k,l,r,mid); ll res = 0; res += query(k * 2,l,mid,a,b); res += query(k * 2 + 1,mid + 1,r,a,b); return res; } int main() { cin >> n >> m; for(int i = 1;i <= n;i++)scanf("%d",&c[i]); build(1,1,n); int x,y,z; char op; while(m--) { getchar(); scanf("%c",&op); if(op == 'M') { scanf("%d %d %d",&x,&y,&z); multiply(1,1,n,x,y,z);//x~y乘z } else if(op == 'C') { scanf("%d %d %d",&x,&y,&z); modify(1,1,n,x,y,z);//x~y加z } else { scanf("%d %d",&x,&y); printf("%lld\n",query(1,1,n,x,y)); //查询x~y区间和 } } return 0; }