专栏文章

CF2050G Tree Destruction 题解

CF2050G题解参与者 2已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@min44g1p
此快照首次捕获于
2025/12/01 20:15
3 个月前
此快照最后确认于
2025/12/01 20:15
3 个月前
查看原文

思路

dpu,0/1/2dp_{u,0/1/2} 分别代表以 uu 为根的子树中,选择的路径不经过 uu / 其中一个端点为 uu / uu 在这条路径上,但不为其端点可以得到的连通块的最大数量。
如果删掉的路径不包含 uu,直接分类讨论每一个儿子的情况即可:
dpu,0=maxv{dpv,0,dpv,1+1,dpv,2+1}dp_{u,0} = \max_v \{dp_{v,0}, dp_{v,1} + 1, dp_{v,2} + 1\}
如果删掉的路径中 uu 为端点,则除了儿子 vv 一起被删,其他的儿子会被分为不同的连通块。所以:
dpu,1=maxv{dpv,1+cnt1}dp_{u,1} = \max_v \{dp_{v,1} + cnt - 1\}
其中 cntcntuu 的儿子个数,1-1 是为了减少 vv 节点。
如果删掉的路径中 uu 在这条路径上,但不为其端点,则 uu22 个儿子也一定在这条路径上,那就可以理解为将一条以 uu 为端点的路径和一条以 uu 的一个儿子 vv 为端点的路径合并在一起,即:
dpu,2=maxv{dpu,1+dpv,11}dp_{u,2} = \max_v\{dp_{u,1} + dp_{v,1} - 1\}
因为需要用到 dpu,1dp_{u,1},所以在 dpu,1dp_{u,1} 更新前先更新 dpu,2dp_{u,2}。时间复杂度 O(n)\mathcal{O}(n)

代码

CPP
#include <bits/stdc++.h>
using namespace std;

const int N = 2e5 + 5;

int t, n;
int dp[N][3];
vector<int> tr[N];

void dfs(int u, int fa)
{
	int cnt = 0;
	for (int v : tr[u])
		if (v != fa) cnt++;
	dp[u][0] = 0, dp[u][1] = dp[u][2] = cnt;
	for (int v : tr[u])
	{
		if (v == fa) continue;
		dfs(v, u);
		dp[u][0] = max({dp[u][0], dp[v][0], max(dp[v][1], dp[v][2]) + 1});
		dp[u][2] = max(dp[u][2], dp[u][1] + dp[v][1] - 1);
		dp[u][1] = max(dp[u][1], dp[v][1] + cnt - 1);
	}
}

void solve()
{
	scanf("%d", &n);
	for (int i = 1, u, v; i < n; i++)
	{
		scanf("%d%d", &u, &v);
		tr[u].push_back(v);
		tr[v].push_back(u);
	}
	dfs(1, 0);
	printf("%d\n", max({dp[1][0], dp[1][1], dp[1][2]}));
	for (int i = 1; i <= n; i++)
		tr[i].clear();
}

int main()
{
	scanf("%d", &t);
	while (t--) solve();
	return 0;
}

评论

1 条评论,欢迎与作者交流。

正在加载评论...