题目链接:http://poj.org/problem?id=3468
题意:给定一个数列,每次操作可以是将某区间数字都加上一个相同的整数,也可以是询问一个区间中所有数字的和,对每次询问输出结果。
这个线段树运用了应用了add域优化,每个节点除了用value记录当前节点对应区间元素的和之外,还要用add域记录当前节点对应区间每个元素的增量。这样,没必要每次更新都要更新value更新到最底层每一个点,只需要将增量记录在某父节点的add域中即可,如果下次查询或者更新操作的是该父节点对应区间的子区间,那么就将add域更新下去,更新子节点的value值,完成更新或查询。add域优化可以减少时间复杂度。
还有就是要注意查询或者更新的区间游客能横跨左子树和右子树,在判断的时候应该做处理。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; #define maxn 4000000 struct node { __int64 l; __int64 r; __int64 add; __int64 value; }tree[maxn]; __int64 a[maxn],n; void build( __int64 v, __int64 l,__int64 r ) //对节点v进行建立,区间为l到r { tree[v].l=l; tree[v].r=r; if( l == r ) { tree[v].value=a[r]; //完全二叉树 return; } __int64 mid=( l+r )/2; build( v*2,l,mid ); //左儿子 build( v*2+1,mid+1,r ); //右儿子 tree[v].value=tree[v*2].value+tree[v*2+1].value; //根据左右儿子更新当前节点 } void update(__int64 v,__int64 l,__int64 r,__int64 m) //更新区间l-r加上m { tree[v].value+=m*(r-l+1); //更新v点value if (tree[v].l==l && tree[v].r==r) //找到了,更新并记录增量 { tree[v].add+=m; return ; } if (tree[v].l==tree[v].r) return ; __int64 mid=(tree[v].l+tree[v].r)/2; if (tree[v].add) //下边没更新,传递增量 { tree[v*2].add+=tree[v].add; //+=注意儿子本身可能就有原来未传递的增量 tree[v*2+1].add+=tree[v].add; tree[v*2].value+=tree[v].add*(tree[v*2].r-tree[v*2].l+1); //对value更新 tree[v*2+1].value+=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,m); //只更新左儿子 return; } if (l>mid) { update(v*2+1,l,r,m); //只更新右儿子 return; } update(v*2,l,mid,m); //左右儿子都更新 update(v*2+1,mid+1,r,m); } __int64 query( __int64 v,__int64 l,__int64 r) //查询l-r上的v值 { if (l==tree[v].l&&r==tree[v].r) //找到了 return tree[v].value; __int64 mid=(tree[v].l+tree[v].r)/2; if (tree[v].add) { tree[v*2].add+=tree[v].add; tree[v*2+1].add+=tree[v].add; tree[v*2].value+=tree[v].add*(tree[v*2].r-tree[v*2].l+1); tree[v*2+1].value+=tree[v].add*(tree[v*2+1].r-tree[v*2+1].l+1); tree[v].add=0; } if (r<=mid) return query(v*2,l,r); //要查询的区间全在左儿子 if (l>mid) return query(v*2+1,l,r); //全在右边 return query(v*2,l,mid)+query(v*2+1,mid+1,r); //横跨左右边 } int main() { __int64 q,x,y,z,i; char h; scanf("%I64d%I64d",&n,&q); for (i=1;i<=n;i++) scanf("%I64d",&a[i]); build(1,1,n); for (i=1;i<=q;i++) { scanf("%s%I64d%I64d",&h,&x,&y); if (h==‘C‘) { scanf("%I64d",&z); update(1,x,y,z); } else { printf("%I64d\n",query(1,x,y)); } } return 0; }
暑假做的,又熟悉了一遍。。
时间: 2024-10-24 09:22:49