第一次知道了子树原来是用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; }