线段树1
#include<cstdio> using namespace std; const int maxn=1e5; typedef long long int ll; ll a[maxn]; struct node{ int v; int l,r; int tag; node *ls,*rs; inline bool maketag(const ll w){ v+=(r-l+1)*w; tag+=w; } inline void pushup(){ v=ls->v+rs->v; } inline void pushdown(){ if(tag==0) return; ls->maketag(tag); rs->maketag(tag); tag=0; } build(const int L,const int R){ l=L; r=R; if(l==r){ tag=0; v=a[l]; ls=rs=NULL; }else{ tag=0; int M=(l+r)>>1; ls=new node (l,M); rs=new node (M+1,r); pushup(); } } inline bool inrange(const int L,const int R){ return (l<=L)&&(r<=R); } inline bool outrange(const int L,const int R){ return (l>R)||(r<L); } void upd(const int L,const int R,const ll w){ if(inrange(L,R)){ maketag(tag); }else if(!outrange(L,R)){ pushdown(); ls->upd(L,R,w); rs->upd(L,R,w); pushup(); } } ll qry(const int L,const int R){ if(inrange(L,R)) return v; if(outofrange(L,R)) return 0; pushdown(); return ls->qry(L,R)+rs->qry(L,R); } }; int main() { scanf("%d%d",&n,&q); for(int i=1;i<=n;i++) scanf("%lld",a+i); node *rot=new node(1,n); for(ll o,x,y,z;q;q--) { scanf("%lld%lld%lld",&o,&x,&y); if(o==1) { scanf("%lld",&z); rot->upd(x,y,z); }else{ printf("%lld\n",rot->qry(x,y)); } } return 0; }
阿这。。。。感觉空荡荡的那我就加点解释吧。。。pushup和pushdown是对父子节点之间关系进行的操作,子节点更新父节点时需要用递归来实现,maketag涉及到一个巧妙地修改子节点的技巧,即在提供单点修改操作的线段树中,将父节点打上一个标记,表示其子节点的值需要被修改,在下一次访问到子节点的时候,再去改变子节点的值。inline bool inrange。。。。感性理解吧,没啥好说的。upd是单点修改用的函数。
build用来建立一个树,把新的点创建为叶节点。qry为区间求和的函数。