题目连接:http://poj.org/problem?id=3468
题目大意:给出一个100000的序列,进行100000次操作,操作"C l r v"表示将区间[l,r]内的所有元素的值加上v;操作"Q l r"表示查询区间[l,r]的元素的和。
实现代码如下:
//线段树成段更新:每次更新一个区间[l,r] #include <cstdio> using namespace std; const int maxn=100005; typedef long long ll; ll num[maxn]; //纪录每个数的初始值 struct segment { int l,r; int mid() { return (l+r)>>1; } ll sum; //纪录该区间原来的和 ll add; //纪录区间的增量 }tree[maxn<<2]; //区间和为sum+add*(r-l+1); void build(int root,int l,int r) { tree[root].l=l; tree[root].r=r; tree[root].add=0; if(l==r) { tree[root].sum=num[l]; return ; } int mid=tree[root].mid(); build(root<<1,l,mid); build(root<<1|1,mid+1,r); tree[root].sum=tree[root<<1].sum+tree[root<<1|1].sum; } void update(int root,int l,int r,int v) { if(tree[root].l==l&&tree[root].r==r) { tree[root].add+=v; return ; } tree[root].sum+=(ll)v*(r-l+1); int mid=tree[root].mid(); if(r<=mid) update(root<<1,l,r,v); else if(l>mid) update(root<<1|1,l,r,v); else { update(root<<1,l,mid,v); update(root<<1|1,mid+1,r,v); } } ll query(int root,int l,int r) { if(tree[root].l==l&&tree[root].r==r) return tree[root].sum+tree[root].add*(r-l+1); tree[root].sum+=tree[root].add*(tree[root].r-tree[root].l+1); int mid=tree[root].mid(); update(root<<1,tree[root].l,mid,tree[root].add); update(root<<1|1,mid+1,tree[root].r,tree[root].add); tree[root].add=0; if(r<=mid) return query(root<<1,l,r); else if(l>mid) return query(root<<1|1,l,r); else return query(root<<1,l,mid)+query(root<<1|1,mid+1,r); } int main() { int n,m; char ch[5]; while(scanf("%d%d",&n,&m)!=-1) { for(int i=1;i<=n;i++) scanf("%lld",&num[i]); build(1,1,n); while(m--) { int l,r,v; scanf("%s",ch); if(ch[0]=='C') //更新区间[l,r] { scanf("%d%d%d",&l,&r,&v); update(1,l,r,v); } else //查询区间[l,r] { scanf("%d%d",&l,&r); printf("%lld\n",query(1,l,r)); } } } return 0; }