poj3468 A Simple Problem with Integers传送门
注意ans可能超出int
懒惰标记:之所以称为懒惰标记,是因为我们在区间修改时,只修该结点的值,并在节点新增加一个标记,让子节点暂时处于不更新的状态,等我们用到的时候再更新,这样当我们在查询的时候,如果我们到了一个节点p,并且决定考虑其子节点,那么我们就要看节点p是否被标记,如果有,就要按照标记一次性修改其子节点的信息,并且给子节点都标上相同的标记,同时消掉节点p的标记。
区间更新举例说明:当我们要对区间[0,2]的叶子节点增加2,利用区间查询的方法从根节点开始找到了非叶子节点[0-2],把它的值设置为1+2 = 3,并且把它的延迟标记设置为2,更新完毕;当我们要查询区间[0,1]内的最小值时,查找到区间[0,2]时,发现它的标记不为0,并且还要向下搜索,因此要把标记向下传递,把节点[0-1]的值设置为2+2 = 4,标记设置为2,节点[2-2]的值设置为1+2 = 3,标记设置为2(其实叶子节点的标志是不起作用的,这里是为了操作的一致性),然后返回查询结果:[0-1]节点的值4;当我们再次更新区间[0,1](增加3)时,查询到节点[0-1],发现它的标记值为2,因此把它的标记值设置为2+3 = 5,节点的值设置为4+3 = 7;
其实当区间更新的区间左右值相等时([i,i]),就相当于单节点更新,单节点更新只是区间更新的特例。
#include <stdio.h>
#include <string.h>
#define MAXN 100010
#define lson l,mid,now<<1
#define rson mid+1,r,now<<1|1
#define LL long long int
LL f[MAXN<<2],a[MAXN],lazy[MAXN<<2];
void build(int l,int r,int now)
{
if(l==r)
{
f[now]=a[l];
return;
}
int mid=(l+r)>>1;
build(lson);
build(rson);
f[now]=f[now<<1]+f[now<<1|1];
return;
}
void PushDown(int ln,int rn,int now)
{
if(lazy[now])//是否有使命
{
//赋予左右儿子使命(因为可能多次被赋予使命,所以"+=")
lazy[now<<1]+=lazy[now];
lazy[now<<1|1]+=lazy[now];
//左右儿子更新值
f[now<<1]+=lazy[now]*ln;
f[now<<1|1]+=lazy[now]*rn;
lazy[now]=0;//使命已经完成,收回特权
}
}
//区间修改a[l...r]+x
void Update(int L,int R,int x,int l,int r,int now)
{
if(L<=l&&R>=r)
{
f[now]+=x*(r-l+1);
lazy[now]+=x;
return;
}
int mid=(l+r)>>1;
PushDown(mid-l+1,r-mid,now);//传递使命
if(L<=mid) Update(L,R,x,lson);
if(R>mid) Update(L,R,x,rson);
f[now]=f[now<<1]+f[now<<1|1];
}
//区间查询
LL Query(int L,int R,int l,int r,int now)
{
if(L<=l&&R>=r) return f[now];
int mid=(l+r)>>1;
PushDown(mid-l+1,r-mid,now);//传递使命
LL ans=0;
if(L<=mid) ans+=Query(L,R,lson);
if(R>mid) ans+=Query(L,R,rson);
return ans;
}
int main()
{
int i,n,m,x,y;
LL num;
char ch;
while(scanf("%d %d",&n,&m)!=EOF)
{
memset(a,0,sizeof(a));
memset(f,0,sizeof(f));
memset(lazy,0,sizeof(lazy));
for(i=1;i<=n;i++)
scanf("%lld",&a[i]);
build(1,n,1);
getchar();
while(m--)
{
scanf("%c",&ch);
if(ch=='Q')
{
scanf("%d %d",&x,&y);
printf("%lld\n",Query(x,y,1,n,1));
}
else if(ch=='C')
{
scanf("%d %d %lld",&x,&y,&num);
Update(x,y,num,1,n,1);
}
getchar();
}
}
return 0;
}