题目链接:http://poj.org/problem?id=3468
解题思路:区间修改,区间求和
求和没问题,区间修改如果要一个个改那么复杂度又变回O(N),那么要这个线段树干嘛呢。
所以用lazy[]数组标记,当下一次要用到被标记节点维护的子区间时,lazy会被下放,保证两个子区间的区间和正确
通俗的说:用到多深,下放多深,复杂度O(logN)
代码:
#include<cstdio>
#define ll long long
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define mid int m=l+r>>1
const int N = 1e5+5;
ll tree[N<<2],lazy[N<<2];
void push_up(int rt)
{
tree[rt] = tree[rt<<1] + tree[rt<<1|1];
}
void push_down(int rt,int len)
{ ///假设区间大小为5,那么应该左子树3,右2
tree[rt<<1] += lazy[rt]*(len-len/2);///5-5/2=3
tree[rt<<1|1] += lazy[rt]*(len/2);///2
lazy[rt<<1] += lazy[rt];
lazy[rt<<1|1] += lazy[rt];
lazy[rt] = 0;
}
void update(int L,int R,ll x,int rt,int l,int r)
{
if (L<=l && r<=R){
tree[rt] += x*(r-l+1);
lazy[rt] += x;
return ;
}
if (lazy[rt]) push_down(rt,r-l+1);
mid;
if (L<=m) update(L,R,x,lson);
if (R>m) update(L,R,x,rson);
push_up(rt);
}
ll query(int L,int R,int rt,int l,int r)
{
if (L<=l && r<=R){
return tree[rt];
}
ll ans =0;
if (lazy[rt]) push_down(rt,r-l+1);
mid;
if (L<=m) ans += query(L,R,lson);
if (R>m) ans += query(L,R,rson);
return ans;
}
void build(int rt,int l,int r)
{
if (l==r){
scanf("%lld",tree+rt);
return ;
}
mid;
build(lson);
build(rson);
push_up(rt);
}
int main()
{
int n,m;
scanf("%d %d",&n,&m);
build(1,1,n);
char op[2];
int x,y;
ll z;
while (m--){
scanf("%s %d %d",op,&x,&y);
if (op[0]=='Q'){
printf("%lld\n",query(x,y,1,1,n));
}
else{
scanf("%lld",&z);
update(x,y,z,1,1,n);
}
}
return 0;
}