Description
Solution
- 对operation-1
f ( y ) ← f ( y ) + w − dis ( x , y ) f(y) \gets f(y)+w-\operatorname{dis}(x,y) f(y)←f(y)+w−dis(x,y)
= w − ( d e p ( x ) + d e p ( y ) − 2 ∗ d e p ( l c a ( x , y ) ) ) \qquad\,\,=w-(dep(x)+dep(y)-2*dep(lca(x,y))) =w−(dep(x)+dep(y)−2∗dep(lca(x,y)))
= w − d e p ( x ) − d e p ( y ) + 2 ∗ d e p ( l c a ( x , y ) ) \qquad\,\,=w-dep(x)-dep(y)+2*dep(lca(x,y)) =w−dep(x)−dep(y)+2∗dep(lca(x,y))
每次操作记 A ← A + w − d e p ( x ) , B ← B + 1 A \gets A+w-dep(x),B \gets B+1 A←A+w−dep(x),B←B+1
∴ f ( y ) = A − B ∗ d e p ( y ) + 2 ∗ d e p ( l c a ( x , y ) ) \therefore f(y)=A-B*dep(y)+2*dep(lca(x,y)) ∴f(y)=A−B∗dep(y)+2∗dep(lca(x,y))
- 对operation-2
每次操作记 c i ← c i + min ( 0 , f ( y ) ) − f ( y ) c_i \gets c_i+\min(0,f(y))-f(y) ci←ci+min(0,f(y))−f(y),最后一起统计
- 对operation-3
容易发现 dep ( l c a ( x , y ) ) \operatorname{dep}(lca(x,y)) dep(lca(x,y))是 y y y到根的路径上与 x x x到根的路径重合的长度,因此每次把 x x x到根 + 1 +1 +1,边转点维护 f ( x ) f(x) f(x)
#include
#define ls x<<1
#define rs x<<1|1
#define ll long long
const int N=50010;
using namespace std;
int id,d[N],idx[N],son[N],sz[N],fx[N],ldfn[N],top[N],rdfn[N],tot,h[N],mp[N],A,B,c[N];
struct Edge{int v,nxt;}e[N<<1];
struct Seg{int l,r;ll val,inc;}T[N<<2];
void add(int x,int y){e[++tot].v=y,e[tot].nxt=h[x],h[x]=tot;}
void dfs1(int x)
{
sz[x]=1,son[x]=0;
for(int i=h[x],v;~i;i=e[i].nxt)if((v=e[i].v)^fx[x])
d[v]=d[x]+1,fx[v]=x,dfs1(v),sz[x]+=sz[v],son[x]=sz[v]>sz[son[x]]?v:son[x];
}
void dfs2(int x,int tp)
{
top[x]=tp,ldfn[x]=++id,idx[id]=x;
if(son[x]) dfs2(son[x],tp);
for(int i=h[x],v;~i;i=e[i].nxt)if((v=e[i].v)^fx[x]&&v^son[x]) dfs2(v,v);
rdfn[x]=id;
}
void up(int x){T[x].val=T[ls].val+T[rs].val;}
void down(int x)
{
if(T[x].inc)
{
T[x].val+=T[x].inc*(T[x].r-T[x].l+1);
T[ls].inc+=T[x].inc;
T[rs].inc+=T[x].inc;
T[x].inc=0;
}
}
void build(int x,int l,int r)
{
T[x].l=l,T[x].r=r,T[x].inc=0;
if(l==r){T[x].val=0;return ;}
int m=l+r>>1;
build(ls,l,m),build(rs,m+1,r),up(x);
}
void modify(int x,int l,int r,ll val)
{
if(T[x].l==l&&T[x].r==r){T[x].inc+=val;return ;}
T[x].val+=(r-l+1)*val;
int m=T[x].l+T[x].r>>1;
if(r<=m) modify(ls,l,r,val);
else if(l>m) modify(rs,l,r,val);
else modify(ls,l,m,val),modify(rs,m+1,r,val);
}
ll query(int x,int l,int r)
{
if(T[x].l==l&&T[x].r==r){return T[x].val+T[x].inc*(r-l+1);}
down(x);int m=T[x].l+T[x].r>>1;
if(r<=m) return query(ls,l,r);
else if(l>m) return query(rs,l,r);
else return query(ls,l,m)+query(rs,m+1,r);
}
void chain_modify(int x,int y,ll val)
{
while(top[x]^top[y]){
if(d[top[x]]>d[top[y]]) x^=y^=x^=y;
modify(1,ldfn[top[y]],ldfn[y],val),y=fx[top[y]];
}if(d[x]>d[y]) x^=y^=x^=y;
if(x==y) return ;
modify(1,ldfn[x],ldfn[y],val);
}
ll chain_query(int x,int y)
{
ll ret=A-B*d[x]+c[x];
while(top[x]^top[y]){
if(d[top[x]]>d[top[y]]) x^=y^=x^=y;
ret+=query(1,ldfn[top[y]],ldfn[y]),y=fx[top[y]];
}if(d[x]>d[y]) x^=y^=x^=y;
if(x==y) return ret;
return ret+query(1,ldfn[x]+1,ldfn[y]);
}
int main()
{
int T,cas=0,n,m,p,rt,i,u,v,k,op;
ll val;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
memset(h,-1,sizeof(h)),tot=id=A=B=0;
memset(c,0,sizeof(c));
for(i=1;i<n;++i) scanf("%d%d",&u,&v),add(u,v),add(v,u);
dfs1(1),dfs2(1,1),build(1,1,id);
while(m--)
{
scanf("%d%d",&op,&u);
if(op==1) scanf("%lld",&val),chain_modify(1,u,2ll),A+=val-d[u],++B;
if(op==2) val=chain_query(u,1),c[u]+=min(0ll,val)-val;
if(op==3) printf("%lld\n",chain_query(u,1));
}
}
}