1 #define ls l,m,rt<<1 2 #define rs m+1,r,rt<<1|1 3 using namespace std; 4 const int maxn=100005; 5 int sum[maxn<<2],add[maxn<<2];//sum求和,add懒惰标记 6 int a[maxn],n;//存原数组数据下标[1,n] 7 //更新节点信息,这里是求和 8 void pushup(int rt) 9 { 10 sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 11 } 12 //建树 13 void build(int l,int r,int rt)//rt表示当前节点编号 14 { 15 if(l==r) 16 { 17 sum[rt]=a[l]; 18 return; 19 } 20 int m=(l+r)>>1; 21 build(l,m,rt<<1); 22 build(m+1,r,rt<<1|1); 23 pushup(rt); 24 } 25 26 //点修改a[L]+=c; 27 void update(int L,int c,int l,int r,int rt) 28 {//l,r当前节点区间,rt当前节点编号,L需要修改的节点,c修改的值 29 if(l==r) 30 { 31 sum[rt]+=c; 32 return; 33 } 34 int m=(l+r)>>1; 35 //根据条件判断调用左子树还是右子树 36 if(L<=m) 37 update(L,c,l,m,rt<<1); 38 else 39 update(L,c,m+1,r,rt<<1|1); 40 pushup(rt);//子节点更新,所以本节点也需要更新 41 } 42 43 //区间修改a[r,t]+=c 44 void update_(int L,int R,int c,int l,int r,int rt) 45 {//L,R表示操作区间,l,r表示当前节点区间,rt表示当前节点编号 46 if(L<=l&&r<=R)//遍历的区间在操作区间内 47 { 48 sum[rt]+=c*(r-l+1); 49 add[rt]+=c; 50 return; 51 } 52 int m=(l+r)>>1; 53 pushdown(rt,m-l+1,r-m); 54 if(L<=m) 55 update_(L,R,c,l,m,rt<<1); 56 if(R>m) 57 update_(L,R,c,m+1,r,rt<<1|1); 58 pushup(rt); 59 } 60 //区间查询 a[l,r]的和 61 //下推标记函数 62 void pushdown(int rt,int ln,int rn) 63 {//ln,rn为左子树,右子树的数量 64 if(add[rt])//下推标记 65 { 66 add[rt<<1]+=add[rt]; 67 add[rt<<1|1]+=add[rt]; 68 sum[rt<<1]+=add[rt]*ln; 69 sum[rt<<1|1]+=add[rt]*rn; 70 add[rt]=0;//清除本节点标记 71 } 72 } 73 int query(int L,int R,int l,int r,int rt) 74 { 75 if(L<=l&&r<=R) 76 { 77 return sum[rt]; 78 } 79 int m=(l+r)>>1; 80 pushdown(rt,m-l+1,r-m); 81 int ans=0; 82 if(L<=m) 83 ans+=query(L,R,l,m,rt<<1); 84 if(R>m) 85 ans+=query(L,R,m+1,r,rt<<1|1); 86 return ans; 87 }
理解参考: