BZOJ4034 HAOI2015 T2 线段树+DFS序

第一次知道了子树原来是用DFS序来维护,涨姿势了- -。

首先我们跑一边DFS序,每个点在入栈和出栈的时候分别记录一边,入栈编号为b[i],出栈标号为e[i],那么两次记录之间的所有的点就是该节点子树的DFS序,入栈为原值,出栈取负。

然后就是用线段树来维护,询问1就是更新b[x]和e[x];询问2就是更新b[x]到e[x];询问3就是询问1到b[x]

#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;
}


你可能感兴趣的:(BZOJ4034 HAOI2015 T2 线段树+DFS序)