类似于轻重链剖分,也有一种树链剖分方式叫做长链剖分,每次我们选子树深度最大的节点当做重儿子,注意这里子树深度是指一棵子树中所有结点的深度最大值。

有以下性质:

  • 一个节点的 $k$ 级祖先所在链的长度一定大于等于 $k$。

比较显然。因为如果小于 $k$ 的话就会选从那个祖先到这个节点的路径当做重链。

  • 所有链的总长是 $O(n)$

比较显然。因为重链不交,可以近似看做是对整个树的划分。

  • 任意一个点向上跳跃重链的次数不会超过 $\sqrt n$ 次。

我们一直向上跳,每次跳到的一个点所在重链长度最小是上个点的重链长度加 $1$,所以我们一直经过的重链长度最多是 $1,2,…\sqrt n$,由此可知性质得证。

求 $k$ 级祖先

求 $k$ 级祖先,长链剖分可以做到 $O(n\log n)$ 预处理,$O(1)$ 查询。

具体做法如下:我们倍增处理所有结点的祖先,然后对于每个链,设链长为 $len$,处理出该链链顶向上,向下(顺着链向下)长度为 $len$ 的每一个点。这是预处理。

对一个查询,设为 $x,k$,表示我们要查询 $x$ 的 $k$ 级祖先,我们考虑设 $r$ 为 $k$ 的最高二进制位表示的那个二进制数,我们考虑寻找 $x$ 的 $2^r$ 祖先,由性质 $1$,我们可以得到这条重链的长度一定是大于等于 $2^r$ 的,这样我们就可以保证,我们要查询的点,一定是被我们预处理过了。所以我们可以通过判断被查询点和该链顶点的深度来进行 $O(1)$ 的查询。

长链剖分优化 dp

具体方法是,我们在合并信息的时候,直接把重儿子的承接过来,其余儿子的信息暴力统计,这样做的话时间复杂度是 $O(n)$ 的。

考虑证明。当一个儿子的信息被暴力统计时,这个儿子一定是其所在重链的链顶,那么合并这个儿子的信息的时间复杂度可以看做其所在重链的长度。

由此可以看出,总的暴力合并的复杂度不会超过链的总长,由此可以得到时间复杂度为 $O(n)$。

当然,大多是当这个 DP 与深度有关时才这么做,这样暴力合并的复杂度才不会超过链的总长。