重链剖分(维护树上信息)复习笔记

本文将介绍重链剖分算法。

问题的引入

看下面一道题:

有一棵根为 \(1\) 的树,点上有点权,进行如下操作:

  1. 将以 \(x\) 为根的子树内所有节点的点权增加 \(k\)
  2. 求以 \(x\) 为根的子树内所有节点的点权之和。

节点数 \(1\le n\le 10^5\),询问数 \(1\le m\le 10^5\)

显然,本题可以简单地使用 dfs 序线段树,将树上问题转化为数列上问题。

那么如果添加两个新的操作呢?

  1. \(x\)\(y\) 的简单路径上所有节点的点权增加 \(k\)
  2. \(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} \]

本题完结撒花!

一些习题

posted @ 2021-06-10 13:24  rui_er  阅读(85)  评论(0)    收藏  举报