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; }