CF1689C Infected Tree
题面翻译
给定一棵以 \(1\) 号节点为根的二叉树,总节点个数为 \(n\)。
现在 \(1\) 号节点感染了病毒,病毒每一回合都会去感染与该节点直接相连的节点,而你在这一回合里可以选择删除任意一个没有被病毒感染(尚未被删除)的点,这样就断开了它与其直接相连的点得关系.
询问最多可以有多少不被病毒感染的点,被删除的点不算做不被病毒感染的点
样例 #1
样例输入 #1
4
2
1 2
4
1 2
2 3
2 4
7
1 2
1 5
2 3
2 4
5 6
5 7
15
1 2
2 3
3 4
4 5
4 6
3 7
2 8
1 9
9 10
9 11
10 12
10 13
11 14
11 15
样例输出 #1
0
2
2
10
提示
In the first test case, the only possible action is to delete vertex \(2\) , after which we save \(0\) vertices in total.
In the second test case, if we delete vertex \(2\) , we can save vertices \(3\) and \(4\) .

分析
对于这种子树相关的问题,考虑树形DP
设 \(dp_i\) 表示节点 \(i\) 被感染,所能保护的最大节点数,设 \(siz_i\) 为以 \(i\) 为根的子树。
则 \(dp_i=\max(dp_j+siz_k-1,dp_k+siz_j-1)\),其中 \(j\) 为 \(i\) 的左儿子,\(k\) 为 \(i\) 的右儿子
注意多测清空
#include<bits/stdc++.h>
using namespace std;
int t,n,tot,siz[300005],dp[300005];
struct node{int to,nxt;}e[600005];
int h[300005];
void add_edge(int x,int y){
e[++tot].to=y,e[tot].nxt=h[x];
h[x]=tot;
}
void dfs(int now,int fa,int sum=0){
dp[now]=0,siz[now]=1;
for(int i=h[now];i;i=e[i].nxt){
int v=e[i].to;
if(v^fa){
dfs(v,now);
sum+=dp[v],siz[now]+=siz[v];
}
}
for(int i=h[now];i;i=e[i].nxt){
int v=e[i].to;
if(v^fa)dp[now]=max(dp[now],sum-dp[v]+siz[v]-1);
}
}
int main(){
cin>>t;
while(t--){
cin>>n;tot=0;
for(int i=1;i<=n;i++)h[i]=0;
for(int i=1,x,y;i<n;i++)cin>>x>>y,add_edge(x,y),add_edge(y,x);
dfs(1,0);
cout<<dp[1]<<endl;
}
return 0;
}

浙公网安备 33010602011771号