【模板】重链剖分(树链剖分)
我们知道对一列数进行区间或单点加减,乘除和区间求值等操作可以用线段树或树状数组 那么,如何对带权树上一条路径中的数进行这样的操作呢? 此时就用到了线段树的树上版——树链剖分 树链剖分的目的在于把树变成一条线段,以方便区间操作 显然,我们无法让每一条树上路径中所有数在这条线段中相邻,但又不能让它们太分散 于是,我们想寻找一个使区间操作均摊复杂度较小的树-线段映射方法 介绍概念: 重儿子:父亲节点的所有儿子中子树结点数目最多(size最大)的结点; 轻儿子:父亲节点中除了重儿子以外的儿子; 重边:父亲结点和重儿子连成的边; 轻边:父亲节点和轻儿子连成的边; 重链:由多条重边连接而成的路径; 轻链:由多条轻边连接而成的路径; 介绍数组: fa[i]:点i的父亲 top[i]:点i所在重链的顶点 si[i]:以点i为根的子树的节点数 son[i]:点i的重儿子 dfn[i]:点i的dfs序 dep[i]:点i的深度 比如上面这幅图中,用黑线连接的结点都是重结点,其余均是轻结点, 2-11就是重链,2-5就是轻链,用红点标记的就是该结点所在重链的起点,也就是下文提到的top结点, 还有每条边的值其实是进行dfs时的执行序号。 (图和说明来自 这位大佬的博客 ) 遍历时,我们使用先序遍历,并先遍历重儿子,再遍历轻儿子 于是,dfn重儿子=dfn父亲+1,即一条重链上从上到下dfn相邻且依次增大