线段树成段增减,区间求和模板
线段树区间增减,区间求和用到了延迟标记。延迟标记是为了节省时间。比如要更新某段区间,只需更新能覆盖该段区间的最少结点的那些结点的sumv和addv数组。addv数组是延迟标记数组。只有需要更新到某个结点时,它的父亲结点需要先将延迟向子结点推,即PushDown操作。
/*
线段树区间增减,区间求和。
*/
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define LL long long
#define mid (L+R)/2
#define lson rt*2,L,mid
#define rson rt*2+1,mid+1,R
const int maxn=101000;
LL sumv[maxn*4];
LL addv[maxn*4];
void PushUP(int rt){ //向上更新
sumv[rt]=sumv[rt*2]+sumv[rt*2+1];
}
void PusDown(int rt,int len){ //向下更新,延迟标记
if(addv[rt]){
addv[rt*2]+=addv[rt];
addv[rt*2+1]+=addv[rt];
sumv[rt*2]+=addv[rt]*(len-len/2);
sumv[rt*2+1]+=addv[rt]*(len/2);
addv[rt]=0;
}
}
void build(int rt,int L,int R){
if(L==R){
scanf("%lld",&sumv[rt]);
return ;
}
build(lson);
build(rson);
PushUP(rt);
}
void update(int rt,int L,int R,int l_ran,int r_ran,LL val){
if(l_ran<=L&&R<=r_ran){
sumv[rt]+=val*(R-L+1);
addv[rt]+=val;
return ;
}
PusDown(rt,(R-L+1)); //延迟向子结点推,并且更新子结点
if(l_ran<=mid){
update(lson,l_ran,r_ran,val);
}
if(r_ran>mid){
update(rson,l_ran,r_ran,val);
}
PushUP(rt); //回溯向上更新
}
LL query(int rt,int L,int R,int l_ran,int r_ran){
if(l_ran<=L&&R<=r_ran){
return sumv[rt];
}
PusDown(rt,(R-L+1)); //延迟向子结点推,并且更新子结点
LL ret=0;
if(l_ran<=mid){
ret+=query(lson,l_ran,r_ran);
}
if(r_ran>mid){
ret+=query(rson,l_ran,r_ran);
}
return ret;
}
int main(){
int n,m;
char tm[5];
while(scanf("%d%d",&n,&m)!=EOF){
//如果不清空延迟标记数组,可能对下组测试数据产生影响
memset(addv,0,sizeof(addv));
build(1,1,n);
for(int i=0;i<m;i++){
scanf("%s",tm);
if(tm[0]=='Q'){
int ta,tb;
scanf("%d%d",&ta,&tb);
printf("%lld\n", query(1,1,n,ta,tb));
}else{
int ta,tb;
LL tc;
scanf("%d%d%lld",&ta,&tb,&tc);
update(1,1,n,ta,tb,tc);
}
}
}
return 0;
}
/*
10 5
1 2 3 4 5 6 7 8 9 10
C 3 6 3
Q 3 6
Q 1 10
Q 1 3
Q 6 8
10 5
1 2 3 4 5 6 7 8 9 10
C 3 6 3
Q 4 4
*/
学学学 练练练 刷刷刷

浙公网安备 33010602011771号