前言
对于树的形态不改变但是需要对路径进行修改操作的,数量剖分就是一个很好的选择,也就是把树弄成链状的然后用数据结构去维护它。
哎哎哎,我突然发现树剖出来的也是DFS序,只是一种特殊的DFS序而已,因此可以维护子树啊!
原理
为了把树上的东西变成线性的,我们采取的办法就是把树弄成若干条链,并且放在一个序列中,这样就可以被一般的数据结构维护了,然后链一段一段的选取修改或者查询,这就是数量剖分的含义了。
为了得到比较好的时间复杂度,我们希望对于任何路径都可以表示成尽量少的链,这里说一个最常用的方法,就是所谓的“轻重链剖分”。
引入几个定义:
重儿子:如果j是i的子树中节点数量最多的,则称j就是i的重儿子。
轻儿子:除重儿子以外的其它子节点。
重边:点i与重儿子的连边。
轻边:点i与其轻儿子的连边。
重链:由重边连成的路径。(有时候单独的结点也算)。
轻链:轻边。
就根据这写定义拆就好了。
性质
性质1:如果(i,j)为轻边,则sz[j]*2 < sz[i];
性质2:从根到某一点j的路径上轻链、重链的个数都不大于log2n。
(根据所有走的都是轻边,然后重边子树必须倍增这一点来证明)
实现思路
首先我们要维护:子树大小、深度(为了之后的查询)、重儿子、父亲、树链的位置,重链的顶端结点。
我们进行两次DFS</