http://poj.org/problem?id=3468
题意:有n个数和两种操作,"C A B C"和" Q AB",“C A B C”表示区间A~B的数均增加C," Q AB"表示询问区间A~B的和。
思路:
是典型的线段树成段更新和区间求和问题。不过我被书上误导了,导致调试了一下午,最后搞得特晕。所以,还是要相信自己的想法,不要完全依赖别人的。。。
区间线段更新时,有向上更新(父节点)和向下更新(子节点)。一定要理解好它。当对某一区间更新时,比如更新
[1,3],同时它的父节点[1,5]也要更新。向下更新即当前区间不能被要更新区间完全覆盖,那么就要把当前区间的公共增量向左右子树传递,并把当前区间的增量改为0,同时左右子树的sum值也要改变,add的改变和sum的改变的同步的。
#include <stdio.h>
#include <string.h>
#define LL long long
const int maxn = 100005;
__int64 a[maxn];
struct line
{
int l;
int r;
LL sum,add;//增加两个区域,一个记录区间之和,一个记录区间公共增量
}tree[maxn<<2];
void build(int v, int l, int r)
{
tree[v].l = l;
tree[v].r = r;
tree[v].add = 0;
if(l == r)
{
tree[v].sum = a[r];
return;
}
int mid = (l+r)>>1;
build(v*2,l,mid);
build(v*2+1,mid+1,r);
tree[v].sum = tree[v*2].sum + tree[v*2+1].sum;
}
void update(int v, int l, int r,__int64 add) //更新区间l~r分别加上add;
{
tree[v].sum += (r-l+1)*add;//不论该区间是否是要更新区间,肯定是当前区间的子区间,所以也要更新当前区间sum值。
if(tree[v].l == l && tree[v].r == r)//如果当前区间恰好被要更新区间完全覆盖,那么用add维护当前区间公共增量,不必往下更新了。
{
tree[v].add += add; //注意是 +=,因为节点本身也有增量
return;
}
int mid = (tree[v].l + tree[v].r)>>1;
if(tree[v].add) //如果上面没有走掉,就把增量向下传递,注意传递增量的同时左右子树的sum值也要改变
{
tree[v*2].add += tree[v].add;
tree[v*2+1].add += tree[v].add;
tree[v*2].sum += tree[v].add * (tree[v*2].r-tree[v*2].l+1);
tree[v*2+1].sum += tree[v].add * (tree[v*2+1].r-tree[v*2+1].l+1);
tree[v].add = 0;
}
if(r <= mid)
update(v*2,l,r,add);
else
{
if(l > mid)
update(v*2+1,l,r,add);
else
{
update(v*2,l,mid,add);
update(v*2+1,mid+1,r,add);
}
}
}
__int64 query(int v, int l, int r)
{
if(tree[v].l == l && tree[v].r == r)
return tree[v].sum;
int mid = (tree[v].l + tree[v].r)>>1;
if(tree[v].add)//上面没走掉,同样增量向下传递,子树的sum值也在改变。
{
tree[v*2].add += tree[v].add;
tree[v*2+1].add += tree[v].add;
tree[v*2].sum += tree[v].add * (tree[v*2].r-tree[v*2].l+1);
tree[v*2+1].sum += tree[v].add * (tree[v*2+1].r-tree[v*2+1].l+1);
tree[v].add = 0;
}
if(r <= mid)
query(v*2,l,r);
else
{
if(l > mid)
return query(v*2+1,l,r);
else
return query(v*2,l,mid)+ query(v*2+1,mid+1,r);
}
}
int main()
{
int n,m;
char ch[2];
int l,r;
__int64 ans,add;
scanf("%d %d",&n,&m);
for(int i = 1; i <= n; i++)
scanf("%I64d",&a[i]);
build(1,1,n);
while(m--)
{
scanf("%s",ch);
if(ch[0] == 'C')
{
scanf("%d %d %I64d",&l,&r,&add);
update(1,l,r,add);
}
else
{
scanf("%d %d",&l,&r);
ans = query(1,l,r);
printf("%I64d\n",ans);
}
}
return 0;
}