题解:CF622E Ants in Leaves

题意简述

link: 题面

有一棵树,\(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 否则会超时。

posted @ 2025-02-10 11:02  hsy8116  阅读(14)  评论(0)    收藏  举报