题解 | CF1689C Infected Tree
树形 DP。
\(size_v\) 为以 \(v\) 为根的子树大小。
设 \(dp_x\) 为 \(x\) 被感染时其子树能留下几个点。
对于一个被感染的点 \(x\) 的孩子的点 \(v\)(未被感染),作如下考虑:
-
删除 \(v\),则它的子树全部都得以保存。\(dp_x\) 不能加上 \(dp_v\),但可以加上 \(size_v-1\)(\(v\) 本身不能算)。
-
不删除它,\(dp_x\) 直接加上 \(dp_v\)。
这样,对于每个 \(x\),枚举删除哪个孩子即可。
又因为原图是一颗二叉树,可以记一个 \(sum\) 为 \(x\) 所有孩子的 \(dp\) 值之和,以快速求出另一个子树的 \(dp\) 值。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int t, n, sz[300005], dp[300005];
vector<int> vc[300005];
int dfs(int x, int fa){
sz[x] = 1;
dp[x] = 0;
int sum = 0;
for(int i = 0; i < vc[x].size(); i++){
int v = vc[x][i];
if(v == fa) continue;
sz[x] += dfs(v, x);
sum += dp[v];
}
for(int i = 0; i < vc[x].size(); i++){
int v = vc[x][i];
if(v == fa) continue;
dp[x] = max(sum - dp[v] + sz[v] - 1, dp[x]);
}
return sz[x];
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cin >> t;
while(t--){
cin >> n;
for(int i = 1; i <= n; i++) vc[i].clear();
for(int i = 1; i <= n - 1; i++){
int a, b;
cin >> a >> b;
vc[a].push_back(b);
vc[b].push_back(a);
}
dfs(1, 0);
cout << dp[1] << '\n';
}
return 0;
}
本文来自博客园,作者:KukCair,转载请注明原文链接:https://www.cnblogs.com/KukCair/p/18995584

浙公网安备 33010602011771号