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