SDOI2013直径-题解

原题链接 Luogu

题面描述

给出一棵树,求有多少条边被所有直径同时覆盖。

解题思路

首先考虑求出一条直径的方法:Link

用两遍 DFS 至少能求出一条直径。怎么知道其中的哪些边被所有直径覆盖呢?

直径有一个性质:在边权为正时,所有直径的中点(可能正好在一个点上,也可能在一条边上)重合。

感性理解一下:如果有两条直径,首先他们应该相交,否则把它们连在一起一定更优;如果它们相交的地方并不是中点,比如这样:

那么把两端直径中较长的一段分别取出,就能拼出更长的直径(图中红 2 蓝 4)。

根据上面的性质,所有直径应该在中间重合,然后在两端分叉。我们只要找到离中点最近的两个分叉点,则分叉点之间的部分都是重合的。

所以我们要从中点出发,分别向两端枚举,如果发现分叉就结束。

那应该如何判断分叉呢?

由于直径的性质,我们可以知道,对于直径上一个不是分叉点的点,它不经过直径能到达的最远点应该比直径的端点更近(否则选取这个点就又是一条直径)。反过来,如果不经过直径能到达的最远点和直径的端点一样远,就说明那个“最远点”是另一条直径的端点,则当前点就是分叉点。

AC 代码