ABC401F Add One Edge 3 题解
ABC401F Add One Edge 3 题解
并不是很难的题,但赛时写的太麻烦了(4k,写了一个多小时),重新梳理一遍。
加上新的边 \((i, j)\) 之后,树的直径要么跨越 \((i, j)\),要么在原来的两棵树中。设 \(d_1\),\(d_2\) 分别表示两棵树的直径,\(f_1(u)\) 和 \(f_2(u)\) 分别表示两棵树中离 \(u\) 最远的点到 \(u\) 的距离,则加入新边后直径的长度为
求出直径和 \(f\) 数组后,考虑枚举第一棵树中的点 \(i\) 统计答案。把 \(f_2\) 排序,我们只需找到一个分界点 \(x\),当 \(j \ge x\) 时直径跨越两棵树,否则直径在原来的树中。二分以后求 \(f_2\) 的一段区间和,用前缀和优化。
现在来看看怎么求出 \(f\) 数组。我们有如下结论:在边权全为正的情况下,对树上的一点 \(u\),离它最远的点必然是直径的一端。这个结论在用 bfs/dfs 求直径时会用到,这里我们反着来使用它:求出直径的两端 \((s, t)\) 后,比较 \(\operatorname{dis}(s, u)\) 和 \(\operatorname{dis}(t, u)\),较大者即为 \(f(u)\)。按理说这是一个很基础的结论,求直径的时候也会用到,但赛时我鬼使神差地忘了,所以最好还是重新证一下:
设树的直径为 \((s, t)\)。离 \(u\) 最远的点为 \(v\),且 \(v\) 到 \(u\) 的距离严格大于 \(s\) 和 \(t\) 到 \(u\) 的距离。反证法,假设 \(v\) 不是直径的一端,分三种情况讨论:
-
\(u\) 在 \(s \rightsquigarrow t\) 上:
由于 \(\operatorname{dis}(u, v) > \operatorname{dis}(u, t)\),所以把 \(s \rightsquigarrow t\) 路径中的 \(u \rightsquigarrow t\) 替换成 \(u \rightsquigarrow v\),得到的 \(s \rightsquigarrow v\) 的距离比直径长,矛盾。
-
\(u\) 不在 \(s \rightsquigarrow t\) 上,且 \(s \rightsquigarrow t\) 与 \(u \rightsquigarrow v\) 有重合的点:
设 \(x\) 是两条路径上第一个重合的点。根据假设,有 \(\operatorname{dis}(x, v) > \operatorname{dis}(x, t)\),所以 \(\operatorname{dis}(s, v) > \operatorname{dis}(s, t)\),矛盾。
-
\(u\) 不在 \(s \rightsquigarrow t\) 上,且 \(s \rightsquigarrow t\) 与 \(u \rightsquigarrow v\) 没有重合的点:
考虑 \(u \rightsquigarrow t\) 这条路径,设这条路径与 \(u \rightsquigarrow v\) 最后一个重合的点为 \(x\),与 \(s \rightsquigarrow t\) 第一个重合的点为 \(y\)。那么 \(\operatorname{dis}(x, v) > \operatorname{dis}(x, t)\),因此 \(\operatorname{dis}(x, v) > \operatorname{dis}(y, t)\),进而 \(\operatorname{dis}(y, v) > \operatorname{dis}(y, t)\)(这都是建立在边权为正的基础上),最终可以推出 \(\operatorname{dis}(s, v) > \operatorname{dis}(s, t)\),矛盾。
(注:图中的一条边代表一条路径)
有了这个结论之后,就可以在求直径的时候同时求出 \(f\)。代码(参考了 jiangly 的写法)
但即使不知道这个结论,也可以求出 \(f\) 数组。这是我赛时的写法,比较难写,仅供参考:
换根 dp。设 \(g(u)\) 表示 \(u\) 子树的高度,dp 求出。设 \(r\) 为根节点,则 \(g(r) = f(r)\)。然后换根。由于转移方程涉及到 \(\max\),而 \(\max\) 不可逆,所以换根时不能简单地”减去“贡献,而枚举所有子节点重新求一遍,时间复杂度会退化成 \(O(n^2)\)。解决方法也很简单:预处理子节点高度的最大值、次大值和最大值数量,分类讨论删去的子节点是不是最大值即可。我的代码用了 multiset
,时间复杂度多了一个 \(\log\),但其实没有必要。代码