原题连接:http://poj.org/problem?id=3468
题意:略……
思路:注意 区间值改变时 有负数,数据范围比较大,int 会溢出。。这题就是一个入门的线段数 插线问线问题。刚学习线段数 WR 了很久……
代码:
#include<stdio.h> #include<string.h> #define Max 4*100000 #define Mid(x,y) (x+y)>>1 //(x+y)/2 __int64 A[Max],cnt; __int64 ans; struct hello { int l; int r; __int64 loop; //注意,int就错了!!!! __int64 sum; }tree[Max]; void Build_tree(int l,int r,int t) // l,r 表示区间,t表示 区间节点 { int x; tree[t].l=l; tree[t].r=r; tree[t].loop=0; tree[t].sum=0; if(l==r) { while(t) { tree[t].sum+=A[l]; t/=2; } return ; } x=Mid(l,r); Build_tree(l,x,2*t); Build_tree(x+1,r,2*t+1); } void Updata_tree(int l,int r,int t) { if(tree[t].l==l&&tree[t].r==r) { tree[t].loop+=cnt; int y=cnt*(tree[t].r-tree[t].l+1); while(t) { tree[t].sum+=y; t/=2; } return ; } int x=Mid(tree[t].l,tree[t].r); if(tree[t].loop) { tree[t*2].loop+=tree[t].loop; //更新标记,向下传递!! tree[t*2+1].loop+=tree[t].loop; tree[t*2].sum+=tree[t].loop*(tree[2*t].r-tree[t*2].l+1); tree[t*2+1].sum+=tree[t].loop*(tree[t*2+1].r-tree[t*2+1].l+1); tree[t].loop=0; } if(x>=r) Updata_tree(l,r,2*t); else if(x+1<=l) Updata_tree(l,r,2*t+1); else { Updata_tree(l,x,2*t); Updata_tree(x+1,r,2*t+1); } } void Query_tree(int l,int r,int t) { if(tree[t].l==l&&tree[t].r==r) { ans+=tree[t].sum; return ; } if(tree[t].loop) { tree[t*2].loop+=tree[t].loop; //更新标记,向下传递!! tree[t*2+1].loop+=tree[t].loop; tree[t*2].sum+=tree[t].loop*(tree[2*t].r-tree[t*2].l+1); tree[t*2+1].sum+=tree[t].loop*(tree[t*2+1].r-tree[t*2+1].l+1); tree[t].loop=0; } int x=Mid(tree[t].l,tree[t].r); if(x>=r) Query_tree(l,r,2*t); else if(x+1<=l) Query_tree(l,r,2*t+1); else { Query_tree(l,x,2*t); Query_tree(x+1,r,2*t+1); } } int main() { int i,j,n,m,ncase,q; while(~scanf("%d%d",&n,&q)) { for(i=1;i<=n;i++) scanf("%I64d",&A[i]); Build_tree(1,n,1); while(q--) { char ch[10]; scanf("%s",ch); if(ch[0]=='C') { scanf("%d%d%I64d",&i,&j,&cnt);//i,j 区间增加每点 cnt; Updata_tree(i,j,1); } else if(ch[0]=='Q') { ans=0; scanf("%d%d",&i,&j); Query_tree(i,j,1); printf("%I64d\n",ans); } } } }