bzoj4034: [HAOI2015]T2

dfs序+线段树.

首先生成树的出栈入栈序。

然后入栈设为a[u],出栈设为-a[u]。

子树在线段树上是一个连续的范围,所以三个操作都可以在线段树上实现了。

ps:val设成int,wa了无数发。。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long LL;
const int maxn = 800000 + 10;
const int maxm = 800000 + 10;
const int maxk = 800000 + 10;

int g[maxn],v[maxm],next[maxm],eid;
int n,m,vid;
int a[maxm],b[maxm];
int in[maxn],out[maxn];
bool down[maxn];
//int id[maxn];

void addedge(int a,int b) {
    v[eid]=b; next[eid]=g[a]; g[a]=eid++;
    v[eid]=a; next[eid]=g[b]; g[b]=eid++;
}

struct Segtree {
    #define lc(x) ((x)<<1)
    #define rc(x) (((x)<<1)|1)
    
    int l[maxk],r[maxk];
    LL sumv[maxk],addv[maxk];
    int flag[maxk];
    
    void push(int x) {
        if(!addv[x] || l[x]==r[x]) return;
        addv[lc(x)]+=addv[x];
        addv[rc(x)]+=addv[x];
        sumv[lc(x)]+=(flag[lc(x)])*addv[x];
        sumv[rc(x)]+=(flag[rc(x)])*addv[x];
        addv[x]=0;
    }
    
    inline void update(int x) {
        sumv[x]=sumv[lc(x)]+sumv[rc(x)];
    }
    
    void add(int x,int L,int R,LL val) {
        if(R<l[x] || L>r[x]) return;
        if(L<=l[x] && r[x]<=R) {
            sumv[x]+=(flag[x]*val);
            addv[x]+=val;    
            return;
        }
        push(x);
        add(lc(x),L,R,val);
        add(rc(x),L,R,val);
        update(x);
    }
    
    LL query(int x,int L,int R) {
        if(R<l[x] || L>r[x]) return 0;
        if(L<=l[x] && r[x]<=R) return sumv[x];
        push(x);
        return (query(lc(x),L,R)+query(rc(x),L,R));
    }
    
    void build(int x,int L,int R) {
        l[x]=L; r[x]=R;
        if(L==R) {
            sumv[x]=a[L];
            addv[x]=0;
            if(down[L]) flag[x]=1;
            else flag[x]=-1;    
            return;
        }
        int mid=(L+R)>>1;
        build(lc(x),L,mid);
        build(rc(x),mid+1,R);
        update(x);
        flag[x]=flag[lc(x)]+flag[rc(x)];        
    }
    
}seg;

void dfs(int u,int from) {
    a[++vid]=b[u]; down[vid]=1;
    in[u]=vid;
    for(int i=g[u];~i;i=next[i]) if(v[i]!=from) dfs(v[i],u);
    a[++vid]=-b[u];
    out[u]=vid;    down[vid]=0;
}

int main() {
    memset(g,-1,sizeof(g));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&b[i]);
    for(int i=1,x,y;i<n;i++) {
        scanf("%d%d",&x,&y);
        addedge(x,y);
    }
    dfs(1,0);
    seg.build(1,1,(n<<1));
    int p,x,a;
    while(m--) {
        scanf("%d",&p);
        if(p==1) {
            scanf("%d%d",&x,&a);
            seg.add(1,in[x],in[x],a);
            seg.add(1,out[x],out[x],a);
        }
        else if(p==2) {
            scanf("%d%d",&x,&a);
            seg.add(1,in[x],out[x],a);
        }
        else {
            scanf("%d",&x);
            printf("%lld\n",seg.query(1,1,in[x]));
        }
    }
    return 0;
}

posted @ 2016-06-29 10:29  invoid  阅读(128)  评论(0编辑  收藏  举报