树链剖分
树链剖分
一、树链剖分的概念和写法
1.1概念
定义:树链剖分用于将树分割成若干条链的形式,以维护树上路径的信息。具体来说,将整棵树剖分为若干条链,使它组合成线性结构,然后用其他的数据结构维护信息。
树链剖分(树剖/链剖)有多种形式,如 重链剖分,长链剖分 和用于 Link/cut Tree 的剖分(有时被称作「实链剖分」),大多数情况下(没有特别说明时),「树链剖分」都指「重链剖分」。
树链剖分一般可以做:路径修改\查询,子树修改\查询
一些定义:
定义 重儿子节点 表示其子节点中子树最大的子结点。如果有多个子树最大的子结点,取其一。如果没有子节点,就无重子节点。
定义 轻儿子节点 表示剩余的所有子结点。
从这个结点到重子节点的边为 重边。
到其他轻子节点的边为 轻边。
若干条首尾衔接的重边构成 重链。
把落单的结点也当作重链,那么整棵树就被剖分成若干条重链。
我们观察图中,重链是以轻儿子或整棵树的根为起点,依次向下连接所有重儿子组成的链。而轻链是以重链为主干链,其分支的链为轻链的,且向外扩展长度为1。
轻链的本质就是一些长度为1的边,将他们作为桥梁连接下一个重链。同时还可以看出,轻儿子(除去叶子结点)都是下一条重链的起始结点。
两遍dfs就是树链剖分的主要处理,通过dfs我们已经保证一条重链上各个节点dfs序连续,那么可以想到,我们可以通过数据结构(以线段树为例)来维护一条重链的信息
第一遍
第二遍
❗关于第二遍
首先根据
为什么要记录链头元素?(该部分引用自 )
我们得到了一系列的重链,如何对它们快速操作?那么就是记录链头元素。这样我们就可以直接跳到链头元素。但是我们遇到了一个问题:在同一条重链上可以直接跳到头部,如果不是在同一条链上呢?方法是:从这条重链的头部再往上跳,到他的父亲结点,必定在另外一条重链上,然后根据需求继续跳。如图所示,b结点跳跃的过程:
b在{6 b}这条重链,跳至6号结点,从6号再跳到{1 2 4 5 a}这条重链,再跳就是1根节点。到这里,再想想什么是轻链,理解会更深刻“将他们作为“桥梁”连接下一个重链”。
1.2 (重要)性质
经过轻边,子树大小翻倍。一个点往上走,最多走
1.3基本实现
1 |
|
1.4 简单应用:树链剖分求
预处理时间复杂度
以上图为例,求
首先思考两个问题:
谁先跳?
深度大的先跳。这时候你会想,那
的深度一样呀。不是的,不是直接比较 的深度,而是比较 向上跳一个链的深度。 结点所在的重链往上跳一个链就是到 号结点,而 所在重链,往上跳也就是到 了。我们需要比较的是 号和 号结点的深度,显然 号深度更大,那么 先跳。 什么时候能判断出
?
如果两个点在同一重链上,那么深度较小的,为,否则还是要不断的跳。 结点,当 结点跳到 结点时, 和 在同一重链中,即 ,所以 为 最终的 。
例题:树上LCA2
1 |
|
二、树链剖分的路径查询
根据上面第一点中所说的,在第二遍
此时我们考虑对整个
考虑一个点

例题:SDOI2011, 染色
题意:
给定一棵
- 将节点
到节点 的路径上的所有点(包括 和 )都染成颜色 。 - 询问节点
到节点 的路径上的颜色段数量。
颜色段的定义是极长的连续相同颜色被认为是一段。例如 112221
由三段组成:11
、222
、1
。
思路:考虑从
注意点如下图:

注意拼接顺序❗
1 |
|
三、树链剖分的子树查询
例题:NOI2015, 软件包管理器
题意:要下载某一个软件,就要把该软件到根路径上的所有没下载的软件都下载了。问每次操作完,有多少个软件包状态发生改变(从安装到没安装,或者从没安装到安装)。
1 |
|
四、总结
树链剖分把路径问题转为为
- Title: 树链剖分
- Author: Nannan
- Created at : 2023-11-25 16:47:00
- Updated at : 2024-09-30 19:49:28
- Link: https://redefine.ohevan.com/2023/11/25/八、树链剖分/
- License: This work is licensed under CC BY-NC-SA 4.0.