题解:CF1984E Shuffle
E
把一个点的父亲儿子都加到
所有的叶子构成一个独立集,我们找去除根后最大的,类似上司的舞会。
枚举每个节点作为初始的根,换根 dp。如果根本身就是叶子还要在加一。
具体来说,第一次扫描以
第二次扫描求出
用
void solve() {
int n;
cin >> n;
vector<vector<int>> g(n + 1);
for(int i = 1; i < n; ++ i) {
int x, y;
cin >> x >> y;
g[x].eb(y);
g[y].eb(x);
}
vector<array<int, 2>> f(n + 1, {0, 0});
auto dfs = [&](auto &&dfs, int x, int fa) -> void {
f[x][0] = 0;
f[x][1] = 1;
for(int y : g[x]) {
if(y != fa) {
dfs(dfs, y, x);
f[x][0] += max(f[y][0], f[y][1]);
f[x][1] += f[y][0];
}
}
};
dfs(dfs, 1, 0);
vector<array<int, 2>> h(n + 1);
h[1][0] = f[1][0];
h[1][1] = f[1][1];
int ans = h[1][0] + (g[1].size() == 1);
auto dfs2 = [&](auto &&dfs2, int x, int fa) -> void {
int tmp = h[fa][0] - max(f[x][0], f[x][1]);
h[x][1] = f[x][1] + tmp;
h[x][0] = max(h[fa][1], f[x][0] + tmp);
tmp = h[x][0] + (g[x].size() == 1);
ans = max(ans, tmp);
for(int y : g[x]) {
if(y != fa) {
dfs2(dfs2, y, x);
}
}
};
for(int y : g[1]) {
dfs2(dfs2, y, 1);
}
cout << ans << '\n';
}