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