根号分治
概述
-
根号分治,是一种对数据进行分治的分治方式。
-
具体来说,如果所要求进行的过程满足满足大点、小点(一般以根号为分界,因为这样复杂度最平衡)可以使用不同的方式处理,则可以考虑使用根号分治。一般常见的有两种情况:
-
根号以下的数据的种类很少,可以全部维护之;根号以上的数据,直接暴力的复杂度可接受。典型代表是质因数分解,此时也许可以叫数论分治。
-
和上面刚好反过来。典型代表是对图按度数分治。当然事实上说两者一样也是对的,毕竟根号分治本质上就是把两种暴力拼到一起。
-
-
一定程度上,根号分治也是一种数据分治,只不过不是数据点分治罢了(笑)。
P3396 哈希冲突
-
题意:给定序列
,有 个操作,为单点修改或求 。 -
数据范围:
。 -
注意到传统方法,譬如线段树和分块,都不能很好地处理
的和,究其原因是 太多了,不同的 之间又互相难以复用。 -
但观察到对于大数即
的 ,直接暴力的复杂度是 。 -
于是考虑根号分治,小数只有
个,修改时直接暴力修改。 -
总复杂度
。
P3939 数颜色
-
题意略。大抵我就是数据结构学傻了吧...
-
考虑根号分治,小的用 set,大的用 ta(一开始还想着分块结果发现这里 ta 更优)。
。 -
发现小的部分复杂度很高,不太美妙。考虑换链表,去一个
,修改暴力修就可以。 。 -
注意到这是排列链表,不妨乱搞一下。维护出现位置行不行?好像可以,然后直接二分...那我要链表干啥?
。 -
主席树。看起来不卡空间。
。 -
差分,然后 cdq。
。 -
显然我选直接二分。。。
P1989 无向图三元环计数
-
题意略。这是非常经典的一道根号分治了...但我要先谈一个邪道做法。
-
bitset!暴力没有 bitset 怎么行!容易想到一个 bitset 维护连通性,然后枚举每条边把两个端点的出边与起来 count 一下的做法,
,然而发现空间复杂度为 ,开不下。 -
怎么办?暴力呗!根号分治,大度点开 bitset,小度点直接暴力枚举出边处理之,
。bitset 的常数比较小,所以是可以随便乱搞过去的。 -
当然啦,我们不提倡这个...毕竟三元环计数的正解非常妙,学一下。
-
核心思路:将环按照我们希望的方式定向。
-
注意到上面的做法中每个环会被统计三次,则如果我们能把环变成有向的(当然必须是等价变换),在这一过程中人为限制大度点的出度,则问题解决。
-
具体地,规定每条边由度小的点指向度大的点。若同度,则由编号小的点指向编号大的点。
-
发现这样的生成图一定是无环的,毕竟都严格全序了,原图上所有环现在都是一个角+一条边。考虑枚举角的第一个边
,然后对每个 检查是否有 。 -
检查通过预标记实现。这一做法的复杂度一定是正确的,因为其复杂度可以变换为
,而 ,证明如下: -
对于小度点,显然生成图上度不增。
-
对于大度点,度数不小于它的点只有
个。
-
-
综上,复杂度为
,比 bitset 更优且更优雅。
CF444D DZY Loves Strings
-
题意略。
-
乍一看没什么思路,不妨从暴力想起。一个显然的暴力就是枚举出现次数少的串的出现,在出现次数大的串的出现序列上二分来计算答案。
-
这一做法的问题主要有两个:第一,不知道出现;第二,会 T。
-
显然 KMP 这种
的求出现算法没机会,考虑 AC 自动机。我们知道 AC 自动机可以求每个模式串在文本串中的出现次数,但位置不太好办。考察其过程,发现本质上是 dfs 完之后做树形 DP,之所以位置不好办是因为要处理位置复杂度就变成了 ,其中 为 dfs 时经过的路径的可重集合,但这里 ,故可以直接做。 -
事实上并不需要这么麻烦。上面的
的实质不就是串长嘛,则直接枚举左端点 substr 创过去就可以了。 -
设法构造一下
(记 )的串最多有多少个吧,将 分为 块,让串在每块中都出现一次,则一块中至多有 个不同子串是输入串。性质不错,考虑根号分治。 -
对于出现次数
的串,暴力枚举其出现,对每个相关询问在对应串的出现上二分算答案,每个询问至多被处理 次,复杂度为 。 -
此时只剩下两个串出现次数都
的询问,考虑预处理,即关于第一个串在 上扫一遍,暴力维护包含 和第一个串在 左/右出现的子串的最小长度, 。 -
从而可以放弃上面的二分,把大部分事情交给预处理,对都是小次数串的直接双指针。
。
CF1039D You Are Given a Tree
-
题意略。差点被题解骗了以为可以整体二分...然而直接整的话是
的... -
本题其实比较数论分治。很容易注意到类似数论分块的性质,考虑对于固定的
怎么求解,发现其是一个赛道修建的退化版(不是边独立而是点独立),不用配对所以单轮 。 -
那么解很显然了,阈值以下的暴力求,阈值以上的二分答案检验可行的最大边数。显然对每个都二分是不可接受的,故可以考虑使用整体二分实现(只有
条不同的链,链长为 )但不优美,不妨利用单调性,首先对最小者计算答案,得到答案后二分边数一次决定下一个点在哪里,于是复杂度为 ,稍微平衡一下,得到 ,总复杂度为 。
P5901 [IOI2009] regions
-
题意略。审完之后就觉得是一个很麻烦的根号分治...
-
考虑在线线段树合并,求得
表示 的子树中颜色 的有多少种。这个 真的好烦啊...然而空间根本开不下...这部分复杂度 (直接认为颜色数和 同阶算了)。 -
将色分为小色和大色。对于小色,如果
是它,直接上去询问, ;对于大色,转而考虑反演,对每个点维护它的祖先中每个大色有多少个点,过程中对对应大色贡献答案, 。 -
显然这个
我们不喜欢, 倒是无所谓但是线合很麻烦啊,数据结构是脑子的平替,不能对标脑子。我们考虑将询问离线,把大色相关询问按上面那样处理,小色相关询问按 排序,对每个 跑一遍,直接整显然复杂度还是不对是 ,但我们可以转而考虑树剖,区间修改到根即可,复杂度为 ,至少比在线线合好不少。 -
平衡一下复杂度,得到
。行吧行吧~ -
p.s.实践表明大色部分不知道为什么跑得特别慢,这里平衡复杂度不如不平衡。奇怪...
CF103D Time to Raid Cowavans
-
题意略。不管怎么看都是很典的根号分治吧?
-
首先对于
,直接暴力之。对于 ,预处理即可,乍一看有 个 对还要枚举 不太对,然而实际上对每个 ,复杂度为 ,故复杂度为 。啊? 的 ?差分啊。 -
总复杂度为
,也没啥操作空间,直接 了事。 的空间是不可能被卡的。为什么 ?允许离线的啊。对每个小 单独做一遍不就好了。
P5309 [Ynoi2011] 初始化
-
题意略。
-
考虑直接模仿上一道题,根号分治,大的暴力,小的加到对应的剩余系上。注意到询问不太好搞。
-
暴力修的内容线段树维护一下就好了吧。也可以树状数组。考虑剩余系上的东西,枚举模数
,应该是把整个剩余系从 开始遍历了不知道多少遍然后剩一段,故我们可以对每个剩余系开一个 ta 来维护之。 -
故复杂度分别为
, 和 ,操作一下可以把 平衡进去。然而似乎还是可能会被卡... -
看了一眼题解,果然被卡了。考虑更高效的算法,把
去掉。众所周知整个 生态和 生态就不搭,把 ta 改成序列分块试试。 -
复杂度变成
, 和 。果然,这样好了不少,就是处理系的贡献时细节比较多。事实上我们可以放弃在系上开 ta,直接在系上维护前后缀和即可,复杂度不变,毕竟系的长度这么短。 -
p.s.因为出题人试图卡各种假做法,小系特别多。考虑调块长,毕竟我们的小系常数特别大,我取
过的。
P5355 [Ynoi2017] 由乃的玉米田
-
题意略。
-
前三种操作见莫队-莫队配合 bitset-小清新人渣的本愿。我们只谈第四种。
-
根号分治。对
的,暴力之,反正我们手里有每个数字是否出现的 bitset。 -
对
的,借用一下线段树求出现那边的手法,即对每个 ,维护一个 表示满足 或 的, 的最大 。显然这容易单次 做到。 -
乍一看好像得整个 ST 表,会带
...但事实上因为 ,我们可以强制 ,然后判一下 就好了。 。 -
注意有点卡空间,
个 int 有点开不下,还是把对阈值以下的询问离线下来挨个整吧。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!