重链剖分(维护树上信息)复习笔记
本文将介绍重链剖分算法。
问题的引入
看下面一道题:
有一棵根为 \(1\) 的树,点上有点权,进行如下操作:
- 将以 \(x\) 为根的子树内所有节点的点权增加 \(k\)。
- 求以 \(x\) 为根的子树内所有节点的点权之和。
节点数 \(1\le n\le 10^5\),询问数 \(1\le m\le 10^5\)。
显然,本题可以简单地使用 dfs 序线段树,将树上问题转化为数列上问题。
那么如果添加两个新的操作呢?
- 将 \(x\) 到 \(y\) 的简单路径上所有节点的点权增加 \(k\)。
- 求 \(x\) 到 \(y\) 的简单路径上所有节点的点权之和。
以上问题便是 洛谷 P3384 轻重链剖分。
此时 dfs 序线段树便无法解决了,需要引入一个新的算法,也就是重链剖分。
重链剖分
概念和定义
以下是重链剖分中的一些定义:
- 重儿子:对于一个非叶子节点,它的儿子中子树最大的那个节点称为它的重儿子。
- 轻儿子:对于一个非叶子节点,它的所有儿子中不是重儿子的都称为它的轻儿子。
- 重边:一个非叶子节点与它的重儿子相连的边称为重边。
- 重链:由一系列重边相连组成的链称为重链。
- 轻链:由一系列非重边相连组成的链称为轻链。
根据以上定义,显然有:
- 叶子节点没有重儿子或轻儿子(因为它没有儿子)。
- 每一条重链的起点是轻儿子。
- 所有重链互不相交,每个点只属于一条重链。
- 重链长度之和为 \(O(n)\)(因为每个点只属于一条重链)。
- 一个点到根节点经过的轻边条数最多为 \(O(\log n)\)。
我们定义的数组如下:
- \(dis_u\):\(u\) 的深度。
- \(fa_u\):\(u\) 的父亲。
- \(sz_u\):\(u\) 的子树大小。
- \(son_u\):\(u\) 的重儿子编号。
- \(top_u\):\(u\) 所在重链的顶端。
- \(dfn_u\):\(u\) 的 dfs 序(注意这里的 dfs 序与普通的不同,将在 dfs2 进行讲解。)
dfs1
在第一次 dfs 中,我们需要处理出每个节点的 \(dis,fa,sz,son\)。
伪代码:
\[\begin{array}{ll}
1 & \textbf{Method}\ \text{dfs1(u,f).}\\
2 & \textbf{let}\ dis_u\gets dis_f+1\\
3 & \textbf{let}\ fa_u\gets f\\
4 & \textbf{let}\ sz_u\gets 1\\
5 & \textbf{for}\ v\in\{\text{son of}\ u\}\\
6 & \qquad\text{dfs1(v,u)}\\
7 & \qquad\textbf{if}\ sz_v\gt sz_{son_u}\\
8 & \qquad\qquad\textbf{let}\ son_u\gets v
\end{array}
\]
dfs2
在第二次 dfs 中,我们需要处理出每个节点的 \(top,dfn\),要先 dfs2 处理重儿子再处理轻儿子。
伪代码:
\[\begin{array}{ll}
1 & \textbf{Method}\ \text{dfs2(u,tp).}\\
2 & \textbf{let}\ top_u\gets tp\\
3 & \textbf{let}\ tot\gets tot+1\\
4 & \textbf{let}\ dfn_u\gets tot\\
5 & \textbf{if}\ u\ \text{is leaf}\\
6 & \qquad\textbf{return}\\
7 & \text{dfs2(}son_u\text{,tp)}\\
8 & \textbf{for}\ v\in\{\text{son of}\ u\land v\ne son_u\}\\
9 & \qquad\text{dfs2(v,v)}
\end{array}
\]
数据处理
我们可以在 dfs2 中处理出在 dfn 意义下每个点的权值,然后使用线段树维护即可。
对于链上操作,我们每次找到深度较深的点,因为 dfs2 中先处理重链后处理轻链,所以重链的 dfn 是连续的,直接将这个点到重链顶端的区间进行操作,然后将这个点跳到重链顶端的父亲。
一直重复如上操作,直到两个点在同一条重链,此时两个点之间的 dfn 也是连续的,再进行一次区间操作即可。
伪代码:
\[\begin{array}{ll}
1 & \textbf{Method}\ \text{modify(u,v).}\\
2 & \textbf{while}\ top_u\ne top_v\\
3 & \qquad\textbf{if}\ dis_u\lt dis_v\\
4 & \qquad\qquad\textbf{swap}\ u,v\\
5 & \qquad\text{SegmentTreeModify(}[dfn_{top_u},dfn_u]\text{)}\\
6 & \qquad\textbf{let}\ u\gets fa_{top_u}\\
7 & \textbf{if}\ dis_u\lt dis_v\\
8 & \qquad\textbf{swap}\ u,v\\
9 & \text{SegmentTreeModify(}[dfn_v,dfn_u]\text{)}
\end{array}
\]
本题完结撒花!

浙公网安备 33010602011771号