题意:
https://uoj.ac/problem/794
思路:
可以发现这是一个类网格图最短路的问题,因此可以考虑 旅行者 中的技巧:每次找到一个点集 \(s\),计算过点集 \(s\) 的所有路径贡献,然后删除点集 \(s\),对剩余的每个连通块递归执行这个过程。
显然比较好的点集 \(s\) 需要满足以下性质:
- 点集 \(s\) 要比较小,这是为了保证计算过 \(s\) 路径的贡献的复杂度。
- 删去点集 \(s\) 后图要裂成至少两个连通块,且每个连通块的大小较为均匀。
那么现在的目标就是每次在图中寻找一个比较优的 \(s\)。
首先这个图是不可能比网格图更优的,所以我们考虑寻找 \(\Theta(\sqrt{n})\) 大小的 \(s\)。
还是考虑类似的根号分治,我们先考虑树高不超过 \(\sqrt{n}\) 的情况,此时可以考虑竖向划分。
此时我们可以直接找到 \(dfn\) 序最中间的点 \(p\),选择其到跟链,这样划分非常均匀,但是左右两个部分并没有完全断开,它们还可以从下方绕过去。
因此如果 \(p\) 不是叶子,我们可以将其 \(dfn\) 序最小的儿子加入;如果 \(p\) 是叶子,注意此时如果 \(p\) 不在最后一层,那么左右两边还是可以通过下面的点连通,不过我们选择 \(s\) 并没有一定要选链的要求,所以可以选择下一层中 \(dfn\) 比 \(p\) 大的第一个点加入 \(s\),重复这个过程。
可以发现这样就得到了一个符合要求的 \(s\) 了,可以发现左右两边是不可能绕过 \(s\) 连通的。
对于树高超过 \(\sqrt{n}\) 的情况可以考虑横向划分,因为一定存在一行大小不超过 \(\sqrt{n}\)。
可以找到最中间的一行 \(l_1\),满足上面和下面的大小都不超过 \(\frac{n}{2}\)。
但是这一行的大小可能超过 \(\sqrt{n}\),不能直接划开这一行。
但是在 \(l_1\) 上 \(\sqrt{n}\) 行内一定会存在一行 \(l_0\) 大小不超过 \(\sqrt{n}\)(可能为 \(0\),即连通块在这里结束了),同理 \(l_1\) 下方 \(\sqrt{n}\) 行内一定会存在一行 \(l_2\) 大小不超过 \(\sqrt{n}\)。
我们可以把 \(l_0\) 和 \(l_2\) 割开,这样 \(l_0\) 上方和 \(l_2\) 下方两个连通块大小就都不超过 \(\frac{n}{2}\),满足条件。不过 \(l_0\) 和 \(l_2\) 中间的部分仍可以很大,不过这个部分的树高一定不超过 \(\sqrt{n}\),我们再使用竖向划分的方法即可。
这样复杂度是 \(T(n)=2T(\frac{n}{2})+n^{1.5}=n^{1.5}\)。