树分治学习笔记

前言

既然序列可以分治,那么树也可以分治。树上的分治可以分为点分治与边分治。

点分治

边分治主要用于处理树上路径问题。

考虑一个分治的过程:选中一棵树的根,计算经过根的路径的贡献,然后以其子结点为根对子树递归地计算贡献。容易发现,在构造数据下这种算法的复杂度是可以达到 \(O(n^2)\) 的,原因在于递归的层数可能太深了。如果不使用子结点,而是使用子树的重心,那么每一次子树的大小都会减半,递归层数降到了 \(O(\log n)\) 级别。而每一层的点数是 \(O(n)\) 的,所以总时间复杂度变成了 \(O(nk\log n)\),其中 \(k\) 是统计贡献的复杂度。

然而从理论到实现还是需要一定距离的,因为点分治需要很多细节。

拓展:点分序列

我们可以将每次计算贡献函数里的点都加进一个序列,那么我们就得到了有 \(O(n\log n)\) 个数,称为点分序列。我们不妨在上面维护一些信息,比如说这个点到它当时的根的路径产生的贡献。这样你就通过 \(O(n\log n)\) 个区间来表示整棵树的路径信息了。可以用来做超级钢琴类似的东西。

点分树

有了点分治的基础,我们就可以方便定义点分树了。点分树的构造方式就是每一个重心向下一层递归中心连有向边,形成一棵有根树。它有两个重要的性质:

  • 它的深度是 \(O(\log n)\) 级别的。

  • 对于 \(u\)\(v\),它们在点分树上的 \(\text{lca}\) 在原树 \(u\)\(v\) 的路径上。

由第二个性质我们可以得到 \(\text{dist}(u,\text{lca})+\text{dist}(v,\text{lca})=\text{dist}(u,v)\)。其中 \(\text{dist}\) 是原树上距离,而 \(\text{lca}\) 是点分树上 \(\text{lca}\)

有了这个重要的性质,就可以直接暴力跳祖先维护了。

posted @ 2023-05-02 20:25  TulipeNoire  阅读(65)  评论(0)    收藏  举报