本文思路参考自何开大佬
引子
相信各位大佬一定会线段树这种非常实用的数据结构
那么如果我们要维护一棵树上的链的权值的时候怎么办
就比如说BZOJ1036树的统计这道题目
可能诸位草率地想想线段树是可以口头AC的,But 这是在一棵树上,线段树支持的连续的区间操作
在这棵树上,如果链的编号断断续续,那么我们的线段树就和暴力没有什么区别有一点点区别了
概念
所以这里就需要用到树链剖分,这种可以支持树上链操作的数据结构
树链剖分有很多高大上的名词需要我们去记
我们先定义一些概念东东
size[u]表示以u为根的树的大小
dep[u]表示u的深度(根的深度定为1)
fa[u]表示u的爸爸(???)
有了这些东东,我们开始定义真正的概念
重儿子:u的所有儿子v中,size[v]最大的v称为u的重儿子
轻儿子:u的所有儿子v中,不是重儿子的都被叫做轻儿子
重边:u 连向它的重儿子的边称为重边
沁轻边:u连向它的轻儿子的边称为轻边
重链:组成这条链的所有的边都是重边
沁轻链:组成这条连的所有边都是轻边
一些小性质
性质1:V为u的轻儿子,则必有size[V] <= size[u] / 2
这个性质证明可以用到反证法
如果存在V为轻儿子并且size[V] > size[u] / 2
我们会发现如果一个节点成为重儿子的条件就是size[V] >= size[u] / (SonNumber[u]) //SonNumber[u]表示u的儿子的数目
因为size[u] / 2 > size[u] / 3 > size[u] / 4 ………………………………
而且size[V] 是不可能大于size[u]的
所以,V为这时候只能为重儿子
与假设不符
证毕~~~~
性质2:从根到某一节点的路径上,轻边的数量不超过O(log N),重链的数目不超过O(log N)
这个我们也是可以证明的
因为我们可以从性质1直接推得轻边的数量不超过O(log N)
后来我们发现
没存在一条轻边,就会出现两条重链
所以重链的数量不超过O(log N)
证毕~~~~
操作
核心操作其实有两个
其中一个是找出所有的重儿子,因为重儿子找出来以后,重边也就找出来了
第二个操作就是找出所有的重链
那么来考虑修改和查询操作
如果是修改的话,我们线段树凉拌加个蛋
如果是查询的话,我们改一点点点点还是凉拌加个蛋
我们如果可以将两个节点移到同一个重链上
然后再进行线段树上的操作就行了
对于在将一个节点移到同一个重链时,代码非常的好理解
但是代码中有一个地方打错了