BZOJ 4034 [HAOI2015]T2(树链剖分)
【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=4034
【题目大意】
有一棵点数为 N 的树,以点 1 为根,且树点有边权。
有 M 个 操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
【题解】
树链剖分之后变成简单的线段树区间和维护。
【代码】
#include <cstdio> #include <algorithm> using namespace std; const int N=200005; typedef long long LL; int x,y,d[N],num[N],ed=0,u,w,n,m,i,v[N],vis[N],f[N],g[N]; int nxt[N],size[N],son[N],st[N],en[N],dfn,top[N],t,a[N]; void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;} void dfs(int x){ size[x]=1; for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]){ f[v[i]]=x,d[v[i]]=d[x]+1; dfs(v[i]),size[x]+=size[v[i]]; if(size[v[i]]>size[son[x]])son[x]=v[i]; } } void dfs2(int x,int y){ if(x==-1)return; st[x]=++dfn;top[x]=y; if(son[x])dfs2(son[x],y); for(int i=g[x];i;i=nxt[i])if(v[i]!=son[x]&&v[i]!=f[x])dfs2(v[i],v[i]); en[x]=dfn; } struct node{LL l,r,a,b,tag,sum;}T[N*4]; int tot=0; void addtag(LL x,LL tag){ T[x].tag+=tag; T[x].sum+=(T[x].b-T[x].a+1)*tag; } void pb(LL x){ if(T[x].l){addtag(T[x].l,T[x].tag);addtag(T[x].r,T[x].tag);} T[x].tag=0; } void up(LL x){T[x].sum=T[T[x].l].sum+T[T[x].r].sum;} void build(int l,int r){ int x=++tot; T[x].a=l;T[x].b=r;T[x].tag=T[x].l=T[x].r=T[x].sum=0; if(l==r){return;} LL mid=(l+r)>>1; T[x].l=tot+1;build(l,mid); T[x].r=tot+1;build(mid+1,r); up(x); } void change(LL x,LL a,LL b,LL p){ if(T[x].a>=a&&T[x].b<=b){addtag(x,p);return;} if(T[x].tag)pb(x); LL mid=(T[x].a+T[x].b)>>1; if(mid>=a&&T[x].l)change(T[x].l,a,b,p); if(mid<b&&T[x].r)change(T[x].r,a,b,p);up(x); } LL query(LL x,LL a,LL b){ if(T[x].a>=a&&T[x].b<=b)return T[x].sum; if(T[x].tag)pb(x);LL mid=(T[x].a+T[x].b)>>1,res=0; if(mid>=a&&T[x].l)res+=query(T[x].l,a,b); if(mid<b&&T[x].r)res+=query(T[x].r,a,b); return res; } LL chain(int x,int y){ LL res=0; for(;top[x]!=top[y];x=f[top[x]]){ if(d[top[x]]<d[top[y]]){int z=x;x=y;y=z;} res+=query(1,st[top[x]],st[x]); }if(d[x]<d[y]){int z=x;x=y;y=z;} res+=query(1,st[y],st[x]); return res; } int op; int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%d",a+i); for(int i=1;i<n;i++){ scanf("%d%d",&x,&y); add(x,y);add(y,x); }dfs(1);dfs2(1,1); build(1,dfn); for(int i=1;i<=n;i++)change(1,st[i],st[i],a[i]); for(int i=1;i<=m;i++){ scanf("%d",&op); if(op==1){ scanf("%d%d",&x,&y); change(1,st[x],st[x],y); }else if(op==2){ scanf("%d%d",&x,&y); change(1,st[x],en[x],y); }else{ scanf("%d",&x); printf("%lld\n",chain(1,x)); } }return 0; }
愿你出走半生,归来仍是少年