线段树支持区间修改和区间查询,以v变量表示当前一段区间的总值,tag为懒标记,记录修改操作,在查询子节点时,由父节点下传,记录修改值的大小,并在子节点加入懒标记
l和r分别表示当前节点所包含的最左区间端点和最右区间端点,ls和rs分别代表当前节点的左子树和右子树
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<math.h> 6 #define ll long long 7 using namespace std; 8 9 const ll maxn=1e5+10; 10 ll n,m; 11 ll a[maxn]; 12 13 struct node 14 { 15 ll v,tag;//权值与懒标记 16 ll l,r;//左右两个端点 17 node *ls,*rs;//左右两个子树 18 19 inline void maketag(ll w)//修改节点值,打懒标记 20 { 21 v+=(r-l+1)*w; 22 tag+=w; 23 } 24 inline void pushup()//权值上传(由子节点更新父节点) 25 { 26 v=ls->v+rs->v; 27 } 28 inline void pushdown()//下传(由父节点更新子节点) 29 { 30 if(tag==0) return ; 31 else 32 { 33 if(ls==NULL)//无左子树 34 { 35 node(l,(l+r)>>1);//动态开点 36 } 37 if(rs==NULL)//无右子树 38 { 39 node(((l+r)>>1)+1,r);//动态开点 40 } 41 ls->maketag(tag); 42 rs->maketag(tag); 43 tag=0; 44 } 45 } 46 node(const ll L,const ll R)//建树 47 { 48 l=L,r=R; 49 if(l==r)//当前节点为叶子结点,无左右子树 50 { 51 tag=0; 52 v=a[l]; 53 ls=rs=NULL; 54 } 55 else 56 { 57 tag=0; 58 ll M=(l+r)>>1; 59 ls=new node(L,M); 60 rs=new node(M+1,R); 61 pushup(); 62 } 63 } 64 inline bool inrange(const ll L,const ll R)//在查询区间以内 65 { 66 return (L<=l)&&(r<=R); 67 } 68 inline bool outrange(const ll L,const ll R)//在查询区间以外 69 { 70 return (l>R)||(r<L); 71 } 72 inline void upd(const ll L,const ll R,const ll w)//区间修改 73 { 74 if(inrange(L,R)) 75 { 76 maketag(w); 77 } 78 else if(!outrange(L,R)) 79 { 80 pushdown(); 81 ls->upd(L,R,w); 82 rs->upd(L,R,w); 83 pushup(); 84 } 85 } 86 inline ll qry(const ll L,const ll R)//区间查询 87 { 88 if(inrange(L,R)) return v; 89 if(outrange(L,R)) return 0; 90 pushdown(); 91 return ls->qry(L,R)+rs->qry(L,R); 92 } 93 }; 94 95 int main(void) 96 { 97 scanf("%lld%lld",&n,&m); 98 for(int i=1;i<=n;i++) scanf("%lld",a+i); 99 node *rot=new node(1,n);//建树 100 101 for(ll f,x,y,z;m;m--) 102 { 103 scanf("%lld",&f); 104 105 if(f==1) 106 { 107 scanf("%lld%lld%lld",&x,&y,&z); 108 rot->upd(x,y,z);//更新操作 109 } 110 if(f==2) 111 { 112 scanf("%lld%lld",&x,&y); 113 printf("%lld ",rot->qry(x,y));//查询操作 114 } 115 } 116 return 0; 117 }