一种可以在线性时间复杂度维护子树中仅限深度有关的信息的算法,主要用于一些特殊的 $\text{dp}$
类似重链剖分,将儿子分为重儿子和轻儿子,重儿子组成的链构成长链
但不同的是重链剖分重儿子是子树结点最多的结点,长链剖分长儿子是子树深度最大的结点
长链剖分有两个重要性质
性质一:所有长链长度和为 $n$
显然所有点均属于且仅属于一条长链,所以性质一成立
性质二:长链剖分的一个重要性质是一个结点 $x$ 的 $k$ 级祖先所在的长链长度一定 $\ge k$
考虑结点 $x$ 和它的 $k$ 级祖先 $y$,如果 $x$ 和 $y$ 属于同一条长链,该情况下性质二成立
如果 $x$ 和 $y$ 不属于同一条长链,知 $y$ 的重儿子子树的深度一定大于 $x$ 的深度,该情况下性质二也成立
先一遍 dfs 处理出每个结点的深度、父结点、重儿子,同时用倍增法 $O\left(n\log n\right)$ 时间处理出每个结点的 $2^k$ 级祖先
第二遍 dfs 处理出每个结点所在长链的起点 $x$
对每个长链的起点 $x$ ,暴力处理出 $x$ 上下 $\text{len}(x)$ 个结点,其中 $\text{len}(x)$ 表示 $x$ 所在长链的长度
由于所有长链长度之和为 $n$ ,所以该暴力处理的时间复杂度为 $O\left(n\right)$
对每次查询结点 $x$ 的 $k$ 级祖先,记 $h_k=\lfloor \log_2 k\rfloor$,$tk=k-2^{h_k}$
先从 $x$ 向上跳 $2^{h_k}$ 级到 $y$ , 根据长链剖分性质,知 $y$ 所在长链长度必然 $\ge 2^{h_k}$
此时还需向上跳 $tk$ 级,$tk\lt 2^{h_k}$,所以 $x$ 的 $k$ 级祖先一定在 $y$ 所在长链起点的上下 $\text{len}(x)$ 级结点范围内
因此在从 $y$ 跳到 $y$ 所在长链起点,最后便可以 $O\left(1\right)$ 访问目标结点
时间复杂度 $O\left(n\log n\right)-O\left(1\right)$
给定一棵 $n$ 个结点的树,问有多少个无序点对 $(i,j,k)$ 满足 $i,j,k$ 两两间距离相等
树形$\text{dp}$,状态转移方程可以参考这份博客详情
利用指针位移使得父结点以 $O(1)$ 时间继承重儿子信息,暴力继承轻儿子信息
设当前结点为 $u$,$u$ 的儿子结点为 $x$,每次暴力继承时间复杂度为 $O\left(\text{len}\left(x\right)\right)$
总时间复杂度为 $\sum_u\left(\left(\sum_x \text{len}\left(x\right)\right)-\text{len}\left(u\right)+1\right)$
每个结点仅在 $\sum_u\left(\left(\sum_x \text{len}\left(x\right)\right)\right)$ 作为它的父结点的子结点出现一次
所以有 $\sum_u\left(\left(\sum_x \text{len}\left(x\right)\right)\right)=\sum_u \text{len}\left(u\right)-\text{len}(root)$
所以总时间复杂度为 $O\left(n\right)$