专栏文章
CF2050G Tree Destruction 题解
CF2050G题解参与者 2已保存评论 1
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 1 条
- 当前快照
- 1 份
- 快照标识符
- @min44g1p
- 此快照首次捕获于
- 2025/12/01 20:15 3 个月前
- 此快照最后确认于
- 2025/12/01 20:15 3 个月前
思路
设 分别代表以 为根的子树中,选择的路径不经过 / 其中一个端点为 / 在这条路径上,但不为其端点可以得到的连通块的最大数量。
如果删掉的路径不包含 ,直接分类讨论每一个儿子的情况即可:
如果删掉的路径中 为端点,则除了儿子 一起被删,其他的儿子会被分为不同的连通块。所以:
其中 为 的儿子个数, 是为了减少 节点。
如果删掉的路径中 在这条路径上,但不为其端点,则 有 个儿子也一定在这条路径上,那就可以理解为将一条以 为端点的路径和一条以 的一个儿子 为端点的路径合并在一起,即:
因为需要用到 ,所以在 更新前先更新 。时间复杂度 。
代码
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 条评论,欢迎与作者交流。
正在加载评论...