第一眼感觉动态加点维护答案是困难的,所以先来考虑一下静态问题。
一个较为简单的做法是枚举根在哪里,然后树的深度就是距离根最远点的距离。
而且还要满足可以构成二叉树,即需要满足如下两个性质:
- 根节点的 deg≤2。
- 其余节点的 deg≤3。(deg 表示节点度数)
然后我们再试图优化一下枚举根的过程,发掘一下性质,会发现:距离 u 最远的点距离相当于 u 先到达树的中心 c 的距离再加上直径的一半。
证明如下:
显然最远点一定是直径端点之一。
那么相当于 u 先从某个点 v 进入直径,然后再走到更远的端点。
可以想到把从 v 到中心 c 点的路径合并进 u 到 v 的路径里,就变成了 u 到中心 c 再加上直径一半。
对于静态问题,直径的一半是常数,那么我们只要求出距离中心最近的 deg≤2 的点即可,这一问题可以直接 dfs 用 O(n) 的时间复杂度求解。
考虑如何解决动态问题。首先要解决动态求中心的问题,即动态维护直径。
容易发现加入一个节点 u 的时候,只需要把它到直径两端点的距离分别的当前直径长度比较即可。中心可以倍增跳,不过有较为简单的维护方法。
观察到每次加入点,中心移动距离不会超过 0.5,即它要么在点上要么在一条树边的中心。
所以我们只要动态维护当前的树中心,维护方法是记录一个二元组 (u,v),如果 u=v 表示中心在点 u 上,否则表示在 (u,v) 边的中点上。
接下来就不能直接用 dfs 求最近点了,怎么办呢?
好像直接把树拍扁成 dfs 序然后线段树维护就好了呢。