题面:
题意:
给定一棵
n
,
n
≤
5
e
4
n,n\le5e4
n,n≤5e4 个节点的树,初始时节点权值均为0。
有
m
,
m
≤
5
e
4
m,m\le5e4
m,m≤5e4个操作。
每个操作可以:
(1)选择一个中心节点
x
x
x,并将所有的节点
y
y
y 的权值加上
w
−
d
i
s
(
x
,
y
)
w-dis(x,y)
w−dis(x,y)
(2)将
x
x
x 节点的
v
a
l
(
x
)
=
m
i
n
(
v
a
l
(
x
)
,
0
)
val(x)=min(val(x),0)
val(x)=min(val(x),0)
(3)查询节点
x
x
x 的权值
v
a
l
(
x
)
val(x)
val(x)
题解:
①、
对于操作(2),我们可以维护一个增量数组
d
e
l
t
a
delta
delta 。
通俗的说,如果当前
x
x
x 节点的权值
v
a
l
(
x
)
<
=
0
val(x)<=0
val(x)<=0,那么
d
e
l
t
a
(
x
)
delta(x)
delta(x) 不变。
如果当前的
x
x
x 节点的权值
v
a
l
(
x
)
>
0
val(x)>0
val(x)>0,那么
d
e
l
t
a
(
x
)
+
=
−
v
a
l
(
x
)
delta(x)+=-val(x)
delta(x)+=−val(x),表示
x
x
x 节点的权值应该在当前权值上再加上
d
e
l
t
a
(
x
)
delta(x)
delta(x) 才是取
m
i
n
min
min之后的值。
即:每次查询
x
x
x 节点的权值的时候,都要加上
d
e
l
t
a
(
x
)
delta(x)
delta(x)
②、
对于操作(1),我们可以发现相当于所有节点
y
y
y 都加上了
w
−
d
i
s
(
x
,
y
)
=
w
−
(
d
[
x
]
+
d
[
y
]
−
2
∗
d
[
l
c
a
(
x
,
y
)
]
)
=
w
−
d
[
x
]
−
d
[
y
]
+
2
∗
d
[
l
c
a
(
x
,
y
)
]
w-dis(x,y)=w-(d[x]+d[y]-2*d[lca(x,y)])=w-d[x]-d[y]+2*d[lca(x,y)]
w−dis(x,y)=w−(d[x]+d[y]−2∗d[lca(x,y)])=w−d[x]−d[y]+2∗d[lca(x,y)]
我们可以发现 w − d [ x ] w-d[x] w−d[x] 这一部分的贡献对于每一个点都是一样的,我们可以单独用个全局变量 a n s ans ans 记录。
我们将 x − r o o t x-root x−root 这条链上的点的权值都加上2,我们查询某一节点 y y y 时, y − r o o t y-root y−root 的权值和就是 2 ∗ d [ l c a ( x , y ) ] 2*d[lca(x,y)] 2∗d[lca(x,y)]。(相当于先标记了 x − r o o t x-root x−root 链,再去标记 y − r o o t y-root y−root 链,这样重合的节点就是 ( x , y ) (x,y) (x,y) 的公共祖先)。
最后我们还剩下一部分 − d [ y ] -d[y] −d[y] ,我们发现有多少次操作(1),那么 − d [ y ] -d[y] −d[y] 就贡献了多少次,记录一下操作(1) 的次数即可。
在询问
x
x
x 点的权值的时候。
v
a
l
(
x
)
=
a
n
s
−
d
[
x
]
∗
n
u
m
+
a
s
k
r
o
a
d
(
1
,
x
)
+
d
e
l
t
a
(
x
)
val(x)=ans-d[x]*num+askroad(1,x)+delta(x)
val(x)=ans−d[x]∗num+askroad(1,x)+delta(x)
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<string>
#include<queue>
#include<bitset>
#include<map>
#include<unordered_map>
#include<set>
#include<list>
#include<ctime>
#define ui unsigned int
#define ll long long
#define llu unsigned ll
#define ld long double
#define pr make_pair
#define pb push_back
#define lc (cnt<<1)
#define rc (cnt<<1|1)
#define len(x) (t[(x)].r-t[(x)].l+1)
#define tmid ((l+r)>>1)
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
using namespace std;
const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const double dnf=1e18;
const int mod=1e9+7;
const double eps=1e-1;
const double pi=acos(-1.0);
const int hp=13331;
const int maxn=50100;
const int maxp=400100;
const int maxm=2100;
const int up=200000;
int head[maxn],ver[maxn<<1],nt[maxn<<1],tot=1;
int f[maxn],d[maxn],si[maxn],son[maxn],cnt=0;
int rk[maxn],top[maxn],id[maxn];
ll delta[maxn],ans=0,num=0;
void init(int n)
{
tot=1,cnt=0;
for(int i=1;i<=n;i++)
delta[i]=head[i]=son[i]=0;
ans=0,num=0;
}
void add(int x,int y)
{
ver[++tot]=y,nt[tot]=head[x],head[x]=tot;
}
void dfs1(int x,int fa)
{
int maxson=0;
si[x]=1,d[x]=d[fa]+1;
for(int i=head[x];i;i=nt[i])
{
int y=ver[i];
if(y==fa) continue;
f[y]=x;
dfs1(y,x);
si[x]+=si[y];
if(si[y]>maxson) maxson=si[y],son[x]=y;
}
}
void dfs2(int x,int t)
{
top[x]=t;id[x]=++cnt;rk[cnt]=x;
if(!son[x]) return ;
dfs2(son[x],t);
for(int i=head[x];i;i=nt[i])
{
int y=ver[i];
if(y!=son[x]&&y!=f[x])
dfs2(y,y);
}
}
struct node
{
int l,r;
ll sum,laz;
}t[maxn<<2];
void pushup(int cnt)
{
t[cnt].sum=t[lc].sum+t[rc].sum;
}
void pushdown(int cnt)
{
if(t[cnt].laz)
{
t[lc].laz+=t[cnt].laz;
t[rc].laz+=t[cnt].laz;
t[lc].sum+=t[cnt].laz*len(lc);
t[rc].sum+=t[cnt].laz*len(rc);
t[cnt].laz=0;
}
}
void build(int l,int r,int cnt)
{
t[cnt].l=l,t[cnt].r=r;
t[cnt].laz=t[cnt].sum=0;
if(l==r) return ;
build(l,tmid,lc);
build(tmid+1,r,rc);
}
void change(int l,int r,int cnt,ll val)
{
if(l<=t[cnt].l&&t[cnt].r<=r)
{
t[cnt].sum+=val*len(cnt);
t[cnt].laz+=val;
return ;
}
pushdown(cnt);
if(t[lc].r>=l) change(l,r,lc,val);
if(t[rc].l<=r) change(l,r,rc,val);
pushup(cnt);
}
ll ask(int l,int r,int cnt)
{
if(l<=t[cnt].l&&t[cnt].r<=r)
{
return t[cnt].sum;
}
pushdown(cnt);
ll ans=0;
if(t[lc].r>=l) ans+=ask(l,r,lc);
if(t[rc].l<=r) ans+=ask(l,r,rc);
return ans;
}
void changeroad(int x,int y,ll val)
{
while(top[x]!=top[y])
{
if(d[top[x]]<d[top[y]])
swap(x,y);
change(id[top[x]],id[x],1,val);
x=f[top[x]];
}
if(d[x]>d[y]) swap(x,y);
change(id[x],id[y],1,val);
}
ll askroad(int x,int y)
{
ll ans=0;
while(top[x]!=top[y])
{
if(d[top[x]]<d[top[y]])
swap(x,y);
ans+=ask(id[top[x]],id[x],1);
x=f[top[x]];
}
if(d[x]>d[y]) swap(x,y);
ans+=ask(id[x],id[y],1);
return ans;
}
ll askforval(int x)
{
return ans-d[x]*num+askroad(1,x)+delta[x];
}
int main(void)
{
int tt;
scanf("%d",&tt);
while(tt--)
{
int n,m,x,y,w,op;
scanf("%d%d",&n,&m);
init(n);
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs1(1,0);
dfs2(1,1);
build(1,cnt,1);
for(int i=1;i<=m;i++)
{
scanf("%d",&op);
if(op==1)
{
scanf("%d%d",&x,&w);
ans+=w-d[x];
changeroad(1,x,2);
num++;
}
else if(op==2)
{
scanf("%d",&x);
delta[x]-=max(0,askforval(x));
}
else if(op==3)
{
scanf("%d",&x);
printf("%lld\n",askforval(x));
}
}
}
return 0;
}