线段树模板
可实现区间加法,区间求和。
具体看代码
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<algorithm> #include<queue> #define max 1000001 #define ll long long using namespace std; unsigned ll n,m,a[max],ans[max*4],tag[max*4]; inline void fix(ll p) { ans[p]=ans[p<<1]+ans[p<<1|1]; //由于是这个区间统一改变,所以ans数组要加元素个数次啦 //就是记录当前节点所代表的区间 } void build(ll p,ll l,ll r) { tag[p]=0; if(l==r) { ans[p]=a[l]; return ; } ll mid=(l+r)>>1; build(p<<1,l,mid); build(p<<1|1,mid+1,r); fix(p); } inline void f(ll p,ll l,ll r,ll k) { tag[p]+=k; ans[p]+=k*(r-l+1); } inline void pushdown(ll p,ll l,ll r) { ll mid=(l+r)>>1; f(p<<1,l,mid,tag[p]); f(p<<1|1,mid+1,r,tag[p]); tag[p]=0; } inline void update(ll nl,ll nr,ll l,ll r,ll p,ll k)//区间加法 { //nl,nr为要修改的区间 //l,r,p为当前节点所存储的区间以及节点的编号 if(nl<=l&&nr>=r) { ans[p]+=k*(r-l+1); tag[p]+=k; return ; } pushdown(p,l,r); ll mid=(l+r)>>1; if(nl<=mid) update(nl,nr,l,mid,p<<1,k); if(nr>mid) update(nl,nr,mid+1,r,p<<1|1,k); fix(p); } ll query(ll nl,ll nr,ll l,ll r,ll p)//区间查询 { //nl,nr为要修改的区间 //l,r,p为当前节点所存储的区间以及节点的编号 ll res=0; if(nl<=l&&nr>=r) return ans[p]; ll mid=(l+r)>>1; pushdown(p,l,r); if(nl<=mid) res+=query(nl,nr,l,mid,p<<1); if(nr>mid) res+=query(nl,nr,mid+1,r,p<<1|1); return res; } int main() { ll b,c,d,e,f; scanf("%lld%lld",&n,&m); for(unsigned int i=1;i<=n;i++) scanf("%lld",&a[i]); build(1,1,n); while(m--) { ll g; scanf("%lld",&g); switch(g) { case 1://区间加法 { scanf("%lld%lld%lld",&b,&c,&d); update(b,c,1,n,1,d); break; } case 2://区间求和 { scanf("%lld%lld",&e,&f); printf("%lld ",query(e,f,1,n,1)); break; } } } return 0; }
本文参考https://pks-loving.blog.luogu.org/senior-data-structure-qian-tan-xian-duan-shu-segment-tree