题目链接:点我啊╭(╯^╰)╮
题目大意:
n
n
n 个点,
n
−
1
n-1
n−1 条边,
m
m
m 次操作
每个点有一个集合,
s
e
t
set
set 里最初只有自己
每次操作将第
p
i
p_i
pi 条边的两个点的
s
e
t
set
set 合并
合并后两个点的
s
e
t
set
set 为合并后的
s
e
t
set
set
最后问每个点被几个
s
e
t
set
set 包含
解题思路:
f
[
u
]
、
f
[
v
]
f[u]、f[v]
f[u]、f[v] 表示
u
u
u 与
v
v
v 的
s
e
t
set
set 大小,合并后:
f
[
u
]
=
f
[
v
]
=
f
[
u
]
+
f
[
v
]
−
f
[
u
]
⋂
f
[
v
]
f[u] = f[v] = f[u] + f[v] - f[u] \bigcap f[v]
f[u]=f[v]=f[u]+f[v]−f[u]⋂f[v]
f
[
u
]
⋂
f
[
v
]
f[u] \bigcap f[v]
f[u]⋂f[v] 表示两个集合交,也就是上次合并的大小
问题来了,怎么求每个点去过几个
s
e
t
set
set 呢???
题解说倒过来求就是了
我的理解是倒过来的意义在于每次操作都是对后缀处理
f
[
u
]
、
f
[
v
]
f[u]、f[v]
f[u]、f[v] 表示
u
u
u 与
v
v
v 的能去多少个
s
e
t
set
set,合并后:
f
[
u
]
=
f
[
v
]
=
f
[
u
]
+
f
[
v
]
−
f
[
u
]
⋂
f
[
v
]
f[u] = f[v] = f[u] + f[v] - f[u] \bigcap f[v]
f[u]=f[v]=f[u]+f[v]−f[u]⋂f[v]
f
[
u
]
⋂
f
[
v
]
f[u] \bigcap f[v]
f[u]⋂f[v] 表示两个点都能去的
s
e
t
set
set 个数
因为是倒过来求
f
[
u
]
+
f
[
v
]
−
f
[
u
]
⋂
f
[
v
]
f[u] + f[v] - f[u] \bigcap f[v]
f[u]+f[v]−f[u]⋂f[v] 表示的就是完成后缀操作后
两者能去的
s
e
t
set
set 个数
我还能说什么
核心:正难则反
#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
using pii = pair <int,int>;
const int maxn = 5e5 + 5;
int n, m, p[maxn], f[maxn];
int gu[maxn], gv[maxn], g[maxn];
int main() {
scanf("%d%d", &n, &m);
for(int i=1; i<n; i++) scanf("%d%d", gu+i, gv+i);
for(int i=1; i<=m; i++) scanf("%d", p+i);
for(int i=1; i<=n; i++) f[i] = 1;
for(int i=m, u, v; i; i--){
u = gu[p[i]], v = gv[p[i]];
f[u] = f[v] = f[u] + f[v] - g[p[i]];
g[p[i]] = f[u];
}
for(int i=1; i<=n; i++) printf("%d%c", f[i], "\n "[i<n]);
}