给定序列,给M次询问,两种操作,C L,R,X,在[l,r]每个数增加X,Q L,R 询问[l,r]总和。
注意两点,在update 和 query的时候都是需要push_down的。然后是,注意每个push_down子树增加的量是vis[rt]不是vis[rt<<1]。因为vis[rt]是表示往子区间传递的值,而不是本身需要更新的增量。
#include <stdio.h> //HDU 3468
#define llt long long
#define maxn 100010
llt sum[maxn<<2],a[maxn],vis[maxn<<2];
void create(llt l,llt r,llt rt)
{
sum[rt]=0;vis[rt]=0;
if(l==r) {sum[rt]=a[l];return;}
llt mid=(l+r)>>1;
create(l,mid,rt<<1);create(mid+1,r,rt<<1|1);
sum[rt]=sum[rt<<1|1]+sum[rt<<1];
;
}
void pushdown(llt rt,llt d)
{
if(vis[rt])
{
vis[rt<<1]+=vis[rt];
vis[rt<<1|1]+=vis[rt];
sum[rt<<1]+=vis[rt]*(d-(d>>1)); //注意这里是vis[rt]不是vis[rt<<1]
sum[rt<<1|1]+=vis[rt]*(d>>1);
vis[rt]=0;
}
}
llt query(llt ll,llt rr,llt l,llt r,llt rt)
{
if(l==ll&&rr==r)
return sum[rt];
pushdown(rt,r-l+1); //注意这里也要push_down
llt ans=0;
llt mid=(l+r)>>1;
if(rr<=mid) ans=query(ll,rr,l,mid,rt<<1);
else if(ll>mid) ans=query(ll,rr,mid+1,r,rt<<1|1);
else
{
ans=query(ll,mid,l,mid,rt<<1);
ans+=query(mid+1,rr,mid+1,r,rt<<1|1);
}
//sum[rt]=sum[rt<<1]+sum[rt<<1|1];
return ans;
}
void update(llt ll,llt rr,llt l,llt r,llt rt,llt c)
{
if(ll==l&&rr==r)
{
vis[rt]+=c;sum[rt]+=(r-l+1)*c;
return;
}
pushdown(rt,r-l+1); //这里也要push_down
llt mid=(l+r)>>1;
if(rr<=mid) update(ll,rr,l,mid,rt<<1,c);
else if(ll>mid) update(ll,rr,mid+1,r,rt<<1|1,c);
else
{
update(ll,mid,l,mid,rt<<1,c);update(mid+1,rr,mid+1,r,rt<<1|1,c);
}
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
int main()
{
llt n,m;
scanf("%lld%lld",&n,&m);
for(llt i=1;i<=n;i++) scanf("%lld",&a[i]);
create(1,n,1);
while(m--)
{
char s[5];
llt l,r;
scanf("%s",s);
if(s[0]=='Q')
{
scanf("%lld%lld",&l,&r);
printf("%lld\n",query(l,r,1,n,1));
}
else if(s[0]=='C')
{
llt c;
scanf("%lld%lld%lld",&l,&r,&c);
update(l,r,1,n,1,c);
}
}
return 0;
}