题意:给定一颗有 n n n个结点的树,初始时所有节点都是白色的,现在要将一些节点染成黑色,要求所有叶子节点到根节点的路径中黑色节点的个数相同。问最多可以将多少个节点染成黑色。
用
(
u
,
v
)
(u,v)
(u,v)表示
u
u
u到
v
v
v的一条路径,用
w
(
u
,
v
)
w(u,v)
w(u,v)表示路径
(
u
,
v
)
(u,v)
(u,v)上的黑色节点个数。贪心地想,可以发现对于所有叶子节点
u
u
u,满足:
l
i
m
=
w
(
r
o
o
t
,
u
)
=
min
v
∈
l
e
a
v
e
s
{
d
e
p
(
v
)
}
lim = w(root, u)=\min_{v \in \mathrm{leaves}} \{dep(v)\}
lim=w(root,u)=v∈leavesmin{dep(v)}
用人话来讲,就是每个叶子节点到根的路径上的黑色节点个数由深度最小的叶子节点确定。
接着可以发现,黑色节点尽量往深度较大的位置放会比较好,也就是说,当我们dfs
到了节点
u
u
u,现在我们在
(
u
,
r
o
o
t
)
(u,root)
(u,root)上已经放了
a
a
a个黑节点,但是在
u
u
u点还没有确定放不放,那么只有当
u
u
u距离在
T
(
u
)
T(u)
T(u)内部的最近的叶子节点的距离等于
l
i
m
−
a
lim-a
lim−a才放。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
struct Edge { ... } E[maxn << 1];
int hd[maxn], tote;
void addedge(int u, int v) { ... }
int n, ans, lf[maxn], lf_sz, dep[maxn], f[maxn];
void init(int u, int fa) {
dep[u] = dep[fa] + 1, f[u] = n + 1;
bool is_leaf = true;
for (int i = hd[u]; i; i = E[i].nex) {
int v = E[i].v;
if (v == fa) continue;
init(v, u), is_leaf = false;
f[u] = min(f[u], f[v]);
}
if (is_leaf) f[u] = dep[u];
}
void calcans(int u, int fa, int cnt) {
if (f[u] - dep[u] < f[1] - cnt) ans++, cnt++;
for (int i = hd[u]; i; i = E[i].nex) {
int v = E[i].v;
if (v == fa) continue;
calcans(v, u, cnt);
}
}
int main() {
scanf("%d", &n);
for (int i = 1; i < n; i++) {
int u, v; scanf("%d%d", &u, &v);
addedge(u, v);
}
init(1, 0);
calcans(1, 0, 0);
printf("%d\n", ans);
return 0;
}