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;
}
posted @ 2023-06-23 22:18  alex_liu09  阅读(11)  评论(0)    收藏  举报