树链剖分
本文最后更新于:2022年8月25日 下午
Intro
树链剖分有什么用呢?目前我唯一已知的用途是支持动态修改树以及求 LCA(常数还小点),还有将你的代码量加上 1 kib。
树链剖分将树分成若干链的形式,这样可以维护路径上的信息。也就是将一个树剖分成一堆序列。树链剖分分为重链剖分,长链剖分,实链剖分(用于 LCT 的剖分)。
大多数情况下,树链剖分一般指重链剖分。
重链剖分将树上任意一条路径划分成不超过 $\log(n)$ 条连续的链,都是自底向上的链,还能保证 DFS 序连续,这样可以用一些维护序列的东西来维护路径上的信息(such as 线段树)。
(线段树就不短了,再加一个树剖,我感觉不熟练的话就可以提前在聊天框里发 gg 了这样还能加 5 rp 值)。
不过写完后发现树剖也不是很长,主要长度感觉是线段树贡献的。
实现
给一些定义:
- 重子节点:表示其子节点中子树最大的节点,有多个的话取其一。
- 轻子节点:表示其子节点中除了重子节点以外的所有节点。
- 重边:从一个节点到重子节点的边为重边。
- 轻边:到轻子节点的边。
- 重链:若干条首尾衔接的重边构成的,落单的节点也当作重链。
树剖的实现分为两个 DFS 的过程,第一遍求出每个节点的父亲,节点的深度,节点子树的个数,重儿子,第二遍求出节点所在重链的顶部节点,DFS 序,和 DFS 序所对应的节点编号。
Code:
1 |
|
你会发现每次向下走一条轻边,所在子树大小就至少除以 2。
怎么用树剖求 LCA 呢?
不断向上跳重链,跳到同一条重链上时,深度较小的节点便是 LCA。
1 |
|
树链剖分
http://dxrprime.github.io/2022/08/25/树链剖分/