BZOJ4034 HAOI2015 树上操作 线段树+DFS序

题意:给定一棵树,维护:1、一个节点+x  2、一个子树所有节点+x  3、求x到根的路径和

题解:先跑出DFS序,那么一个节点的子树就是这个节点在DFS序中两次出现之间的节点,设s[i],e[i]为i第一次出现和第二次出现的位置,用线段树来维护求和,借鉴差分的思想,那么线段树中s[i]所对应的节点的权值=v[i],e[i]所对应的节点的权值=-v[i]。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long

const int MAXN=3*100000+2;
struct HASH{
    int u;
    HASH *next;
    HASH(){}
    HASH(int _u,HASH *_next):u(_u),next(_next){}
}mem[MAXN];
struct NODE{
    int v;
    HASH *child;
}node[MAXN];
typedef struct TREE{
    ll s,add;
    int t,l,r;
    TREE *lchild,*rchild;
    TREE(){}
    TREE(int _l,int _r):l(_l),r(_r),add(0){}
} *ROOT;
ROOT root;
int N,M,b[MAXN],e[MAXN],cnt;
ll v[MAXN],t[MAXN];

void Insert(int u,int v){ node[u].child=&(mem[cnt++]=HASH(v,node[u].child));}

void DFS(int now,int f){
    v[++cnt]=node[now].v,t[cnt]=1,b[now]=cnt;
    for(HASH *p=node[now].child;p;p=p->next)
        if(p->u!=f) DFS(p->u,now);
    v[++cnt]=-node[now].v,t[cnt]=-1,e[now]=cnt;
}

void Pushup(ROOT &x){
    x->t=x->lchild->t+x->rchild->t;
    x->s=x->lchild->s+x->rchild->s;
}

void Pushdown(ROOT &x){
    if(x->add){
        x->lchild->s+=x->add*x->lchild->t;
        x->rchild->s+=x->add*x->rchild->t;
        x->lchild->add+=x->add,x->rchild->add+=x->add,x->add=0;
    }
}

void Build(ROOT &x,int l,int r){
    x=new TREE(l,r);
    if(l==r){
        x->s=v[l],x->t=t[l];
        return;
    }

    int m=(l+r)>>1;
    Build(x->lchild,l,m),Build(x->rchild,m+1,r);

    Pushup(x);
}

void Update(ROOT &x,int l,int r,ll v){
    if(x->l>=l && x->r<=r){
        x->s+=x->t*v,x->add+=v;
        return;
    }

    Pushdown(x);

    int m=(x->l+x->r)>>1;
    if(l<=m) Update(x->lchild,l,r,v);
    if(r>m) Update(x->rchild,l,r,v);

    Pushup(x);
}

ll Query(ROOT &x,int l,int r){
    if(x->l>=l && x->r<=r) return x->s;

    Pushdown(x);

    int m=(x->l+x->r)>>1;
    ll ret=0;
    if(l<=m) ret+=Query(x->lchild,l,r);
    if(r>m) ret+=Query(x->rchild,l,r);

    return ret;
}

int main(){
    scanf("%d %d",&N,&M);
    for(int i=1;i<=N;i++) scanf("%d",&node[i].v);
    for(int i=1,u,v;i<N;i++){
        scanf("%d %d",&u,&v);
        Insert(u,v),Insert(v,u);
    }

    cnt=0,DFS(1,1);
    Build(root,1,cnt);

    ll a;
    for(int i=1,q,x;i<=M;i++){
        scanf("%d %d",&q,&x);
        if(q==1){
            scanf("%lld",&a);
            Update(root,b[x],b[x],a),Update(root,e[x],e[x],a);
        }
        if(q==2){
            scanf("%lld",&a);
            Update(root,b[x],e[x],a);
        }
        if(q==3) printf("%lld\n",Query(root,1,b[x]));
    }

    return 0;
}
View Code

 

posted @ 2017-02-26 13:13  WDZRMPCBIT  阅读(161)  评论(0编辑  收藏  举报