前言#
因为觉得这个思想很有意思,最近也见到了许多使用根号分治的题目,自己也出了一些用根号分治的题目,所以想总结一下。
(下文各种根号分治的名字是我掰出来的,应该有别的称呼)
对文章的细节有疑问或是发现错误的欢迎提出。
介绍#
根号分治是一种在对数据规模分类讨论的基础上利用不同算法平衡复杂度的思想。
根号分治的思想非常朴素,举个例子:
对于一个
从上例可以看出,根号分治的重点在于分治,而不是根号,根号只是在部分情况下复杂度的形式。
根号分治的本质是平衡复杂度,这里的复杂度包括时间复杂度和空间复杂度,根号分治可以实现时间和空间之间的转化。
根号分治有一个重要特点:和一定。这里的和的类型多种多样,比如字符串的长度和,点的度数和,点对的距离和等等。
因为和的类型多种多样,因此根号分治的应用场景十分广阔。(为什么什么东西都能根分)
接下来你将会见到一些不同类型根号分治的基础应用和扩展应用。
应用#
度数根号分治
给出一张个点, 条边的无向图,每个点有点权,进行 次操作,操作分两种:
- 将点
的点权增加 。 - 查询与点
直接相连的点的点权和。
。
这道题可以说是根号分治最经典的题目之一了,我们按照根号分治的过程分析。
首先,我们需要找到一个东西,满足它的和一定,在这道题中,我们发现给出的是一个一般无向图,没有什么好的性质……吗?
因为边数为
那么我们考虑根据点的度数进行根号分治,按照套路,设定一个阈值
因为点的度数和为
我们对于每个重点都维护与其直接相连的点的点权和,记做
- 操作
:
直接将点
- 重点操作
:
直接输出
- 轻点操作
:
暴力扫一遍所有与
分析一下复杂度,单次第
我们说了这么久的根号终于出现了!
时空平衡根号分治
有个集合,集合中元素个数和为 ,进行 次询问,每次询问两个集合交集的元素个数。
。
我们都知道有一个东西叫做 bitset
,我们直接开 bitset
,对于一个集合,若一个数存在,那么对应位就是
在询问时,我们直接将这两个询问的集合的 bitset
与一下,再数一下
让我们看看复杂度,时间复杂度是
我们发现 bitset
中的
套路的,设定阈值为 bitset
,那么 bitset
的个数不会超过
询问时,我们将元素个数小于 bitset
中,再与另一个集合的 bitset
与。
那么这样操作下来,时间复杂度变成了
从这个例子中,我们看出了根号分治平衡时空复杂度的强大能力。
分类根号分治
统计中满足以下条件的数的个数:
- 数位中含有
个连续的数字 。 - 可以被
整除。 多测,
。
(所谓分类根号分治,就是 暴力 + 暴力 = 正解)
就跟我们在文章开头举的例子一样,我们设定一个阈值
当
当
设计函数 dfs(pos, limit, have, rem, cnt)
表示当前考虑到第
具体的说,考虑记忆化数组
其中,
时间复杂度为
那么我们的总复杂度就是
空间复杂度为
事实上,分类根号分治是最常用的根号分治方法之一,平衡两种暴力的复杂度的思想是非常重要的。
本质上,分类根号分治利用的是数据范围的和一定的性质。(这也算性质)
余数根号分治
维护一个长为序列 ,进行 次操作,操作分以下两种:
- 将
增加 。 - 查询所有下标模
的余数为 的所有数的和。
。
(事实上,这个类别应该归入分类根号分治中,但因为比较常见就单独拎出来了)
因为这也是分类根号分治的一种,因此我们考虑两种暴力:
-
直接修改,查询时从
开始枚举,每次 ,求和。 -
设
表示下标模 的余数为 的所有数的和,修改时 更新 数组,查询时直接查表输出。
我们发现,这两种暴力分别对应了两种极端:一种是
那么我们还是按照老套路,将这两种暴力合并。
设定阈值为
同时,我们依旧开一个表,但我们只开
修改时,因为我们只开了
算下来,总时间复杂度为
模根号分治常见于数据结构题中,跟下文的步长根号分治有一定的相似性。
颜色根号分治
给定一个的网格,每个点有一个颜色 ,统计有多少条路径满足以下条件:
- 起点和终点的颜色相同。
- 只能向下或向右走。
。
首先,我们需要找到和一定的东西,在颜色根号分治中,和一定的是点的数量(这不是废话吗),或者换句话说,是所有颜色的点的数量和。
先别管那么多,我们设定阈值为
对于这道题,我们对每种颜色独立考虑,对当前考虑的颜色是轻还是重分类讨论。
-
如果当前是轻颜色,那么我们直接双重枚举该颜色的所有点,对于一对点
,其能产生的路径数量显然是 。 -
如果当前是重颜色,我们发现还有一种 DP 做法可以统计路径数量。
设
分析一下复杂度,重颜色的数量不会超过
轻颜色的数量是
那么总复杂度是
颜色根号分治也是常见的根号分治,经常会结合一些奇怪的东西一起考察。
步长根号分治
给定一颗个点的带边权树,边权为 或 ,多次询问,问在从点 出发到点 ,一次可以走 的距离的情况下最少要走几步。
。
步长根号分治利用的是两点之间距离一定的性质。
设定阈值为 万能的套路),那么我们发现当
当
这个东西可以之间倍增处理,也就是
那么单次询问时我们从
步长根号分治可以看作余数根号分治的扩展。不过做法的细节还是比较多的。
总结#
除了上述几大类根号分治之外,还有一些比较特别的根号分治,比如质因子根号分治,斜率优化根号分治等等,但因为泛用性不广,故不一一列出。
总的来说,根号分治是一种常见的思想,在 OI 中占有一席之地,在遇到可以找出某个东西和一定的题目时可以想想根号分治。
涉及到平衡复杂度的算法并不多,主要就是一众根号算法(根分,分块,莫队),当复杂度不平衡时可以往这边想一想。
更多题目#
(包括了上面的一部分题目,还有一些其他题目,都是洛谷链接,有些题是 OJ 的内部题放不上来)
步长根号分治:ODW。
颜色根号分治:Regions,Frequency Problem,Yet Another Path Counting。
余数根号分治:Remainder Problem。
分类根号分治:Two Arithmetic Progressions,9,Train Maintenance,You Are Given a Tree,Array Queries。
度数根号分治:交友问题。