一些依靠遍历序维护树上信息的方法

本文较为基础,可以看作博主复习所用

主要依据维护区域的形态进行分类。

直接表示成常数段区间

通过合适的选择遍历序,我们常常能将树上的范围转化成序列上的一段区间。

子树、子树补

最常见的。利用dfs序即可。

去掉某个点的子树以及其到根路径的范围

不知道怎么命名的区域……
利用后序遍历和反后序遍历(即在遍历儿子时使用相反的优先级),我们可以用第一个序的一个前缀+第二个序的一个前缀表示出一个点的上述范围。

一个点的邻域

这里的邻域就是指和该点直接相邻的点。
我们把它们分成儿子和父亲两类。父亲只有一个,是好处理的。利用bfs序,可以将儿子表示成一段区间。
进一步的,“某个点的子树内到它的距离恰好为x的点”也可以用bfs序表示。

同时维护子树和邻域

使用bdfs序:用dfs遍历到一个点时,将它的所有儿子加入序列。这种序列具有以下特点:

  1. 一个点的所有儿子构成连续的一段区间。
  2. 一个点的子树除去这个点自身之外,构成连续的一段区间。

配合树链剖分

下面我们默认使用重链剖分。
接下来可以看到,通过对节点的分类,我们能有效的处理很多较为基本的问题,这其实也是树剖的基本思想。

链上操作

我们自然需要使用dfs序来保证一条重链上的点是一段区间。
但其实,我们并不完全一定需要保证这一点。考虑bdfs序,按照先dfs重儿子的顺序做,那么显然重链上的点并非一段区间;但是确实存在一个区间,使得内部的重儿子点全都是这条链上的点。于是如果在线段树上将重儿子点和轻儿子点的信息分开维护,我们一样可以维护链上操作。
使用bdfs序+树剖,通过对节点的分类(重儿子/轻儿子,也就是链顶/非链顶),我们能实现链上、邻域上的操作(比如加法&求和)。

维护儿子/子树信息

类似ddp的维护方法。


一些小技巧

转化贡献

往往应用在操作(修改/查询)之一是单点的情况。
比如说链加、单点求值,自然可以树剖+线段树,但是若是转化贡献,可以变成单点加、子树求和,就是一个BIT可以解决的了。
这样不仅能让代码简单不少,还常常能降低复杂度。

链加、子树和

这个单独提出来的原因是,修改和查询看起来都不是单点,但这个问题确实能单log。
我们同时使用dfs序的先序遍历和后序遍历两个序,不难发现一个点在两个序中对应的前缀的差,恰好就是它到根的链。
于是如果只要做单点查询,我们只需实现前缀加,单点求值。子树查询改为区间求和即可。、
这应该是本文所示技巧中一个较不广为人知但是巧妙的应用。

posted @ 2022-04-14 17:39  秋叶冬雪  阅读(224)  评论(2编辑  收藏  举报