欢迎访问~原文出处——博客园-zhouzhendong
去博客园看该题解
题目传送门 - BZOJ4034
题意概括
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
题解
树链剖分。
然后对于子树修改,我们可以考虑dfs序。
树链剖分也是一种dfs序。
单点修改更简单,对于懒惰的我来说,这就是区间修改(少写了一个void 2333)
询问几乎是基础的树剖了,沿着树链往上走就可以了。
代码
#include <cstring> #include <cstdio> #include <algorithm> #include <cmath> #include <cstdlib> using namespace std; typedef long long LL; const int N=100005; struct Gragh{ int cnt,y[N*2],nxt[N*2],fst[N]; void clear(){ cnt=0; memset(fst,0,sizeof fst); } void add(int a,int b){ y[++cnt]=b,nxt[cnt]=fst[a],fst[a]=cnt; } }g; int n,m,cnp=0; int fa[N],son[N],size[N],depth[N],top[N],p[N],ap[N],outp[N]; LL v[N],t[N*4],add[N*4],w[N*4]; void Get_Gen_Info(int rt,int pre,int d){ size[rt]=1,fa[rt]=pre,depth[rt]=d,son[rt]=-1; for (int i=g.fst[rt];i;i=g.nxt[i]) if (g.y[i]!=pre){ int s=g.y[i]; Get_Gen_Info(s,rt,d+1); size[rt]+=size[s]; if (son[rt]==-1||size[s]>size[son[rt]]) son[rt]=s; } } void Get_Top(int rt,int tp){ top[rt]=tp; ap[p[rt]=++cnp]=rt; if (son[rt]==-1){ outp[rt]=cnp; return; } Get_Top(son[rt],tp); for (int i=g.fst[rt];i;i=g.nxt[i]){ int s=g.y[i]; if (s!=fa[rt]&&s!=son[rt]) Get_Top(s,s); } outp[rt]=cnp; } void pushup(int rt){ int ls=rt<<1,rs=ls|1; t[rt]=t[ls]+t[rs]; } void build(int rt,int le,int ri){ w[rt]=ri-le+1; add[rt]=0; if (le==ri){ t[rt]=v[ap[le]]; return; } int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1; build(ls,le,mid); build(rs,mid+1,ri); pushup(rt); } void pushdown(int rt){ int ls=rt<<1,rs=ls|1; LL &a=add[rt]; if (a){ t[ls]+=w[ls]*a,add[ls]+=a; t[rs]+=w[rs]*a,add[rs]+=a; a=0; } } void update(int rt,int le,int ri,int xle,int xri,LL d){ if (le>xri||ri<xle) return; if (xle<=le&&ri<=xri){ t[rt]+=w[rt]*d,add[rt]+=d; return; } pushdown(rt); int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1; update(ls,le,mid,xle,xri,d); update(rs,mid+1,ri,xle,xri,d); pushup(rt); } LL query(int rt,int le,int ri,int xle,int xri){ if (le>xri||ri<xle) return 0; if (xle<=le&&ri<=xri) return t[rt]; pushdown(rt); int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1; return query(ls,le,mid,xle,xri)+query(rs,mid+1,ri,xle,xri); } LL Tquery(int a){ int f=top[a]; LL ans=0; while (a){ ans+=query(1,1,n,p[f],p[a]); a=fa[f],f=top[a]; } return ans; } int main(){ scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%lld",&v[i]); g.clear(); for (int i=1,a,b;i<n;i++){ scanf("%d%d",&a,&b); g.add(a,b); g.add(b,a); } Get_Gen_Info(1,0,0); Get_Top(1,1); build(1,1,n); for (int i=1;i<=m;i++){ int op,a,b; scanf("%d",&op); if (op==1){ scanf("%d%d",&a,&b); update(1,1,n,p[a],p[a],b); } if (op==2){ scanf("%d%d",&a,&b); update(1,1,n,p[a],outp[a],b); } if (op==3){ scanf("%d",&a); printf("%lld ",Tquery(a)); } } return 0; }