岛屿
岛屿
给定若干棵基环树森林,求解每棵基环树的直径之和。
首先如果最长的两个点在环上某个点的子树中,可以直接求解树的直径。
若最长的两个点穿越了环,则一定是环上两点子树内最深的两个点。
对于每个基环上的点,可以求出其子树内最深的深度,设基环树上两点最长的距离为 \(S(i,j)\),然后就变成了选取两个点使得 \(S(i,j)+d(i)+d(j)\)。
可以破环为链,对 \(S\) 做前缀和,然后对于 \(j<i\),距离为 \(S_i-S_j\),那就是对于每个 \(i\),求解 \(\max(S_i+d(i)+d(j)-S_j)\),发现对于 \(i\) 来说与 \(i\) 相关的项是固定的,就是求解后面的关于 \(j\) 的式子的最大值。发现满足要求的 \(j\) 需要与 \(i\) 的距离 \(<环长\),这就是一个滑动窗口求解最值的问题,可以用单调队列。
注意寻找基环树上的环需要 dfs
中记录来的边,而不是来的点,因为这会导致两个点的环(即有重边)情况出现差错。
前缀和是指从任意一个点开始往一个方向走的前缀和,注意对 \(S\) 做前缀和时,若下标 \(\ge 环长\),则需要为 \(S_{环长-1}+S_{下标-环长}\),因为这样才能保证作差时可以恰好消去,变为真实距离。