一棵树可以剖分成好多的链
鬼都知道ヾノ≧∀≦)o死开!
树链剖分的方法可以将树固定地分为几个链
生成树
跑两遍图
第一遍维护子节点最多的重(zhong)儿子
由重儿子们组成了重链
第二遍维护出重儿子优先的dfs
入栈序
这样这个入栈序就可以拆分成几个重链
如图
这棵树上边权为1的边为重链,除叶子节点外,每个节点必有重儿子
若存在多个儿子子节点和相等,则任取一个作为重儿子
该树的序为
1246 5 378 9
每个空格隔开的区间都是一条重链
于是一棵树就这么被剖开了
挺简单易懂是不是
为了更快速遍历这些链
我们维护一个top
数组
存储每个节点所在重链的深度最浅的点
在第二遍dfs
时,可以顺便维护出来
于是我们就可以用一些神奇的数据结构迅速地维护这棵树
树链剖分还可以求lca
非常快O(log n)
即可出答案
过程大概是
每次优先维护二者中深度更深的top
维护从top
到当前节点这个区间的值
直到二者top
相同
此时二者必在同一链上
最后维护二者之间的区间即可
实现:
int lca(int x,int y)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])//dep为深度
swap(x,y);//交换两个数
//此处可维护链,用一个映射存dfs序,如果需要再存一个反映射方便找回原数
x=fa[top[x]];
}
//此处也可维护链
retrun dep[x]<dep[y]?x:y;//返回深度较小的点
}