题解:CF622E Ants in Leaves
题意简述
有一棵树,\(1\) 号点是根,每个叶子有一只蚂蚁,每次可以往上爬一个点,除根外的点每次只能容纳一只蚂蚁,问所有蚂蚁爬到根结点的最小时间。
解题思路
首先考虑根结点可以容纳多只蚂蚁而其他点不能,所以根结点的子结点可以同时往根上跑蚂蚁,所以蚂蚁爬完的最终时间是根结点的子结点中最慢爬完蚂蚁的时间。
考虑根的一棵子树,\(x\) 为子树根。\(x\) 子树中会存在多个叶子结点(有蚂蚁的结点),这些叶子跑到整个树的根 \(1\) 号点会有一个距离,这个距离和深度 dep 一致(\(1\) 号点深度为 \(0\)),所以将叶子的 dep 值放入 dis,组成叶子跑到整个树的根 \(1\) 号点的距离数组。在 dis 数组中,如果有两个值相等,那么在 \(x\) 子树中一定有两只蚂蚁会在这个子树中的某个点撞上,所以需要让一个值增加 \(1\),进行等待。
在具体实现上,考虑对每个 \(x\) 子树的 dis 排序,从小到大遍历,若有相邻的两个值相等,对靠后的值加 \(1\) 以避免冲突。
\(Code\)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
const int NR = 5e5 + 10;
struct edge
{
int nxt, to;
}e[NR * 2];
int head[NR], cnt;
void add(int x, int y)
{
e[++cnt].nxt = head[x];
e[cnt].to = y;
head[x] = cnt;
}
int dep[NR];
int dis[NR], sz;
void dfs(int x, int fa)
{
dep[x] = dep[fa] + 1;
bool isLeaf = true;
for (int i = head[x]; i; i = e[i].nxt)
{
int y = e[i].to;
if (y == fa) continue;
isLeaf = false;
dfs(y, x);
}
if (isLeaf) dis[++sz] = dep[x];
}
int main()
{
int n;
scanf("%d", &n);
for (int i = 1; i < n; i ++)
{
int x, y;
scanf("%d%d", &x, &y);
add(x, y);
add(y, x);
}
int ans = 0;
for (int i = head[1]; i; i = e[i].nxt)
{
int x = e[i].to;
sz = 0;
dep[1] = 0;
dfs(x, 1);
sort(dis + 1, dis + sz + 1);
for (int j = 2; j <= sz; j ++)
{
dis[j] = max(dis[j], dis[j - 1] + 1);
}
ans = max(ans, dis[sz]);
}
printf("%d\n", ans);
return 0;
}
整体复杂度为 \(O(n\log{n})\),注意对每个子树 \(x\) 不要做 memset 否则会超时。

浙公网安备 33010602011771号