poj 3468
题意 两种操作 1:区间更新c
2:问区间的和
经典区间线段树
#include <iostream> #include<stdio.h> using namespace std; const int N=100011; struct Node { int l,r; __int64 s,sum; }Tree[N*4]; void Build(int root,int l,int r) { Tree[root].s=0; Tree[root].l=l;Tree[root].r=r; if(l==r) { scanf("%I64d",&Tree[root].sum);return ; } Build(root*2,l,(l+r)/2); Build(root*2+1,(l+r)/2+1,r); Tree[root].sum=Tree[root*2].sum+Tree[root*2+1].sum; } void pushdown(int root) { Tree[root].sum+=Tree[root].s*(Tree[root].r-Tree[root].l+1); Tree[root*2].s+=Tree[root].s; Tree[root*2+1].s+=Tree[root].s; Tree[root].s=0; } __int64 Query(int root,int l,int r)//查询 l-->r区间的和 { if(Tree[root].l==l&&Tree[root].r==r) return (Tree[root].r-Tree[root].l+1)*Tree[root].s+Tree[root].sum;//节点的sum值保存的是 孩子节点的所有 lazy 与sum的值 而不保存当前节点的lazy值 if(Tree[root].s)//在查询的时候向下推 pushdown(root);//查询的时候则必须pushdown与 区间覆盖恰恰相反; int mid=(Tree[root].l+Tree[root].r)/2; if(r<=mid) return Query(root*2,l,r); else if(l>mid) return Query(root*2+1,l,r); else return Query(root*2,l,mid)+Query(root*2+1,mid+1,r); } void Updata(int root,int l,int r,__int64 c) { if(Tree[root].l==l&&Tree[root].r==r) { Tree[root].s+=c; return ; } Tree[root].sum+=c*(r-l+1);//所过祖先节点 肯定包括当前要插入的区间 因此 不需要pushdown;采取了从上向下的更新方式; int mid=(Tree[root].l+Tree[root].r)/2; if(r<=mid) Updata(root*2,l,r,c); else if(l>mid) return Updata(root*2+1,l,r,c); else { Updata(root*2,l,mid,c); Updata(root*2+1,mid+1,r,c); } } int main() { char str[11]; int n,m,a,b; __int64 d; while(scanf("%d%d",&n,&m)!=EOF) { Build(1,1,n); while(m--) { scanf("%s",str); if(str[0]=='Q') { scanf("%d%d",&a,&b); printf("%I64d\n",Query(1,a,b)); } else { scanf("%d%d%I64d",&a,&b,&d); Updata(1,a,b,d); } } } return 0; }