https://ac.nowcoder.com/acm/contest/5672/C
难点就是把操作1的式子变形到最后,w-dep(x)-dep(y)很好维护,2*dep(lca)用树链剖分来维护,好像是比较经典的,把一堆【x到根每个点的权】更新,然后查询y到根的权和,就是y与前面每一个x的lca的深度之和。
#include
using namespace std;
#define maxn (100000+100)
#define ll long long
int n,m,root=1,dfs_clock,op;
vector<int> G[maxn];
int fa[maxn],son[maxn],sz[maxn],deep[maxn],id[maxn],id2[maxn],top[maxn];
ll w[maxn],ver_w[maxn],delta[maxn],sum,c1;
//多组数据则G[],son[],dfs_clock,和线段树维护部分需要初始化
int ql,qr,val;
ll sumv[maxn*4],addv[maxn*4];
ll _sum;
ll build(int o,int l,int r)
{
int mid=(l+r)/2;
if(l==r)return sumv[o]=addv[o]=w[l];
return sumv[o]=(build(o*2,l,mid)+build(o*2+1,mid+1,r));
}
void maintain(int o,int l,int r)
{
if(l==r)sumv[o]=addv[o];
else sumv[o]=(sumv[o*2]+sumv[o*2+1]+(ll)addv[o]*(r-l+1));
}
void query(int o,int l,int r,ll add)
{
if(ql<=l&&qr>=r)_sum=(_sum+add*(r-l+1)+sumv[o]);
else
{
int mid=(l+r)/2;
if(ql<=mid)query(o*2,l,mid,(add+addv[o]));
if(qr>mid)query(o*2+1,mid+1,r,(add+addv[o]));
}
}
void update(int o,int l,int r)
{
if(ql<=l&&qr>=r)addv[o]=(addv[o]+val);
else
{
int mid=(l+r)/2;
if(ql<=mid)update(o*2,l,mid);
if(qr>mid)update(o*2+1,mid+1,r);
}
maintain(o,l,r);
}
void dfs1(int u,int f)
{
deep[u]=deep[f]+1;
sz[u]=1;
fa[u]=f;
int maxx=0;
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(v==f)continue;
dfs1(v,u);
sz[u]+=sz[v];
if(sz[v]>maxx){maxx=sz[v];son[u]=v;}
}
}
void dfs2(int u,int up)
{
id[u]=id2[u]=++dfs_clock;
top[u]=up;
if(son[u]){dfs2(son[u],up);id2[u]=id2[son[u]];}
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(v==fa[u] || v==son[u])continue;
dfs2(v,v);
id2[u]=id2[v];
}
}
void Update1(int u,int v,int z)
{
int tpu=top[u],tpv=top[v];
while(tpu!=tpv)
{
if(deep[tpu]<deep[tpv]){swap(tpu,tpv);swap(u,v);}
ql=id[tpu],qr=id[u],val=z;
update(1,1,n);
u=fa[tpu];
tpu=top[u];
}
if(deep[u]>deep[v])swap(u,v);
ql=id[u],qr=id[v],val=z;
update(1,1,n);
}
ll Query1(int u,int v)
{
_sum=0;
int tpu=top[u],tpv=top[v];
while(tpu!=tpv)
{
if(deep[tpu]<deep[tpv]){swap(tpu,tpv);swap(u,v);}
ql=id[tpu],qr=id[u];
query(1,1,n,0);
u=fa[tpu];
tpu=top[u];
}
if(deep[u]>deep[v])swap(u,v);
ql=id[u],qr=id[v];
query(1,1,n,0);
return _sum;
}
int main()
{
//freopen("input.in","r",stdin);
int T;
cin>>T;
while(T--)
{
cin>>n>>m;
int x,y,z;
for(int i=1;i<=n;i++)w[i]=delta[i]=son[i]=0,G[i].clear();
dfs_clock=c1=sum=0;
memset(addv,0,sizeof(addv));
memset(sumv,0,sizeof(sumv));
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
dfs1(root,0);
dfs2(root,root);
ll num;
for(int i=1;i<=m;i++)
{
scanf("%d",&op);
switch(op)
{
case 1:
scanf("%d%d",&x,&y);
c1++;
sum+=y-deep[x];
Update1(x,1,2);
break;
case 2:
scanf("%d",&x);
num=delta[x]+sum-deep[x]*c1+Query1(x,1);
if(num>0)delta[x]+= -num;
break;
case 3:
scanf("%d",&x);
printf("%lld\n",delta[x]+sum-deep[x]*c1+Query1(x,1));
break;
}
}
}
return 0;
}