poj一道区间更新的裸体,区间加值。
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace std; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 const int maxn=100010; __int64 sum[maxn<<2]; __int64 lazy[maxn<<2]; void PushUP(int rt) { sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void PushDown(int rt ,int m) { if(lazy[rt]) { lazy[rt<<1]+=lazy[rt]; lazy[rt<<1|1]+=lazy[rt]; sum[rt<<1]+=(m-(m>>1))*lazy[rt]; sum[rt<<1|1]+=(m>>1)*lazy[rt]; lazy[rt]=0; } } void build(int l,int r,int rt) { lazy[rt]=0; if(l==r) { scanf("%I64d",&sum[rt]); return ; } int m=(l+r)/2; build(lson); build(rson); PushUP(rt); } void update(int L,int R,int v,int l,int r,int rt) { if(L<=l&&r<=R) { sum[rt]+=v*(r-l+1); lazy[rt]+=v; return ; } PushDown(rt,r-l+1); int m=(l+r)/2; if(L<=m) update(L,R,v,lson); if(R>m) update(L,R,v,rson); PushUP(rt); } __int64 query(int L,int R,int l,int r,int rt) { if(L<=l&&r<=R) { return sum[rt]; } PushDown(rt,r-l+1); int m=(l+r)/2; __int64 ret=0; if(L<=m) ret+= query(L,R,lson); if(R>m) ret+= query(L,R,rson); return ret; } int main() { int n,q; while(~scanf("%d%d",&n,&q)) { build(1,n,1); char choice[2]; int a,b,c; while(q--) { scanf("%s",choice); if(choice[0]=='Q') { scanf("%d%d",&a,&b); printf("%I64d\n",query(a,b,1,n,1)); } else { scanf("%d%d%d",&a,&b,&c); update(a,b,c,1,n,1); } } } return 0; }几个细节:
1.
if(L<=m) update(L,R,v,lson); if(R>m) update(L,R,v,rson);有两种写法,也可以写成其他形式,思想就是目标区间在当前区间左边,在右边,横跨。
而我用的这个方式省略为两种,思想是一样的。
2
if(L<=l&&r<=R) { return sum[rt]; }
3.别人博客中一些其他风格的线段树用到了结构体,其实可以在query()和update()中用多传几个参数的方式代替,没必要使用结构体。
4.不要忘记每次操作后pushdown()或者pushup()的使用。
5.对于sum和lazy要用到__int64。防止有些数据超出范围,因为要用到线段树肯定是稍微大一点数据量和数据范围。