分块相关杂谈
command_block · · 算法·理论
您将在此看到 OIer
分块的最低水平。
0. 分块概论
在数据结构问题中,我们需要维护一些离散的信息单位,单位的数目会影响处理的复杂度。
如果信息支持不受限制的合并与批量处理,那么就可以使用线段树等区间数据结构。
当然,有时并不存在高效的信息合并化简方式,而需要在“批量”和“零散”之间找到平衡点,这就是分块的核心思想。
这一类问题的性质更弱,所以问题形式变化多端,“整散”关系多种多样,具有传统数据结构难以比拟的灵活性。
1. 基础数列分块
在这一节中,我们将认识一些经典的数列分块问题,初步熟悉分块的形式和思想。
- 数列分块的形式
下面统一约定数列长度为
如图,在分块中有如下概念 :
-
末尾小块 : 因为整个数列划分不整而得到的一个较小的块,可能带来多余的细节。有时可以人为地增长数列将小块变成正常大小的块。
-
整块 : 被操作区间完整覆盖的块。总块数是
O(n/B) 的。 -
散块 : 被操作区间覆盖了一部分的块。散块包含的元素数目是
O(B) 的。
找出所有的 整块 和 散块内元素 是容易的。
-
**题意** : 区间加,区间求和。
在这个问题中,信息能够高效合并,这使得分块没有太大的优势。
但是,从这一类简单问题入门分块比较易于初学者理解。
-
区间查询 (一般先分析查询,搞清楚需要维护什么,再考虑如何维护)
注意到,每个元素对答案的贡献是独立的。我们可以对每个 块 / 散块 分别计算贡献。
(大多数分块都会满足这个性质,因为块间贡献一般很难考虑)
对每个整块记下总和,这样容易
O(1) 计算贡献。对于散块,暴力求和。 -
区间修改
对于散块,暴力加。
对于整块,记录加法标记。
这样,总和
= 块内元素总和+ 标记\times 块大小。当取单个元素时,要加上对应块的加法标记。
两者的复杂度均为
思考我们这样做的本质,不难发现,其实是将线段树这一 “二叉树” 改成了 “
上面的做法对应标记永久化,其实也可以将标记下推,即每次暴力清空两个散块的标记,复杂度不变。
评测记录 | 代码Link
-
**题意** : 区间加,查询区间大于等于 $k$ 的数的个数。 -
区间查询
这里贡献仍然独立。
考虑在每个块内维护有序序列,这样只需要一次二分即可计算块内贡献。
对于散块,暴力遍历即可。
若块大小为
B ,则复杂度为O((n/B)\log B+B) 。 -
区间加
对于整块,块内的相对顺序不变,只需记录加法标记。注意考虑加法标记对二分比较的影响。
对于散块,需要重构有序序列,若加完后暴力排序,复杂度是
O(B\log B) 。在旧的有序序列中提取加和未被加的两部分,各是有序序列,归并即可做到
O(B) 。复杂度
O((n/B)+B) 。
令
复杂度分析技巧 : 分块的主要思想是平衡,若复杂度由两部分组成,直接令两者相等,即可解得最优块大小。
(本题数据非常弱,错误做法可能可以通过)
-
**题意** : 区间加,查询区间前驱。
类似上一题,对每个块维护有序序列,查询时整块二分,散块暴力。
复杂度
评测记录
-
**题意** : 区间加,区间第 $k$ 大。
对每个块维护有序序列,查询时二分转化成 P2801
。复杂度为
仔细分析查询时的操作 : 整块二分,散块暴力。
根据信息论,整块二分难以优化。但对散块进行
可以事先将散块归并,这样对散块的查询无需暴力遍历,而可以一次二分搞定。
这样,单次询问的复杂度改进为
若将
注意,散块部分的常数较大,应适当调小块大小。
评测记录
附 : 觉得不过瘾可以做 P3380 【模板】二逼平衡树(树套树)
-
**题意** : 维护一个 $n$ 个点的有向图,每个点都有且仅有一条出边,且指向比自己编号大的点。 支持修改某个点的出边,查询从某个点出发几步会到达 $n$ 号点。
“行动步数”问题和经典的求算贡献问题有很大不同。
不难发现,若没有修改,容易
对于一个块,预处理其每个元素走出该块所需步数,以及到达的点。
这样,可以
在修改时,也只需
令
评测记录
-
**题意** : 给定两个长度为 $n$ 的数列 $A,B$ ,支持下列操作: - 将数列 $A$ 中区间 $[l,r]$ 内所有数加上 $w$ ; - 交换 $B_x$ 和 $B_y$ ; - 求 $\max\limits_{i\in[l,r]}\{A_i\times B_i\}$ .
操作二可以直接把涉及到的两个块重构。
区间加时,散块可以暴力重构,但是整块只能打标记。
每个位置的贡献可以看做关于标记的一次函数,于是维护凸壳即可。
散块重构时利用归并可以
查询时,由于标记只会递增,线性扫即可。
令
-
**题意** : 查询区间内出现偶数次的数(称为好数)的个数,强制在线。值域在 $O(n)$ 级别。
此时贡献是不独立的,对每个块分别考虑并不方便。
利用桶记录每个数的出现次数(奇偶性),即可增量维护好数的个数。
记
记
查询时,若
然后考虑散块的影响,仍然用增量法计算即可。
总复杂度为
若要节省空间,可以用 bitset
记录
可以发现,本题思想类似于回滚莫队。实际上,静态分块的功能是莫队的子集,所以强制在线时分块才有优越性。
-
**题意** : 区间众数,强制在线。
基本操作和上一题非常类似。
贡献不独立。
用桶记录每个数的出现次数(奇偶性),即可增量维护众数。
记
记
查询时,若
然后考虑散块的影响,仍然用增量法计算即可。(注意散块对出现次数也有贡献)
时空复杂度均为
-
**题意** : 区间众数,强制在线。要求空间 $O(n)$。
在上一题中,空间的瓶颈是
我们可以用 vector
记录下同类数的所有出现位置。
当判定散块中数
空间复杂度改进为
-
**题意** : 区间逆序对,强制在线。
在逆序对问题中,每一对数都有贡献,贡献模式是二维的。
询问时,答案的贡献成分如下图 :
绿色是整块内部的贡献,橙色是散块内部的贡献,红色是整块和散块之间的贡献,蓝色是散块之间的贡献。
考虑对每个块内前后缀都预处理内部逆序对数,容易使用树状数组做到
考虑归并排序的过程,不难两个区间之间的逆序对可以将这两个区间归并计算。
于是,预处理块内有序序列,蓝色部分就可以(先取出有序散块)归并计算。
然后预处理
考虑差分,有
两块间贡献仍然可以
接下来预处理
复杂度为
还有另一个常数较小的做法,预处理
这样,计算两块之间的贡献时,直接差分即可(不需要常数巨大的归并)。
计算红色部分时,可以转而枚举整块,然后差分。
蓝色部分依然需要归并计算。
2. 经典分块技巧
一些 基于分块的技巧 和 分块需要的技巧。
某些分块可以视作三层的
块状数组查询和修改的复杂度一优一劣,用于查询和修改数目不同的问题,以平衡复杂度。
-
维护块和,修改时只需修改对应元素以及块和,查询时和数列分快相同。  -
维护块内前缀和,块和的前缀和。查询时整块正缀和加上块内前缀和。 修改时暴力 $O(\sqrt{n})$ 分别重新计算块内前缀和和块和的前缀和。 
当值域大小为
-
维护块和。查询时先逐块确定,然后进入块内逐个确定。 -
首先求出答案在那个值域块内,再求答案。 对每个 $k$ 维护第 $k$ 大值在哪个值域块中,会形成 $O(\sqrt{n})$ 个段。 一次修改后,每个段的端点会移动,总复杂度是 $O(\sqrt{n})$ 的。 对于每个值域块维护一个有序序列,利用插入排序可以做到 $O(\sqrt{n})$。 再维护每个块前面的数的数目,将 $k$ 减去之后直接取对应下标即可。 -
例题 : CC Chef and Churu
题意 : 给定一个长度为
n 的序列和m 个区间。有两种操作:
- 把序列中的第
x 个数改为y - 求第
x 个区间到第y 个区间的和 (的和)
- 把序列中的第
将区间分块。维护
这样,在单点修改之后,能
查询时,对于散块暴力
-
配合莫队使用 : 莫队小记
-
可持久化块状数组
将上述三层
例题 : P5574 [CmdOI2019]任务分配问题 (
解决一系列带插入的序列问题。(在带插入的序列上维护分块)
将某个元素插入某个块时,将该块重构。若某个块的大小超过
这样,分裂次数是
代码实现细节较多,具体见例题。
- 例题 : P4278 带插入区间K小值
在远古时期这题的时限是
先考虑带单点修改区间K小值,若沿袭 P5356
的做法,复杂度为
注意到本题的特殊性 : 值域较小(认为与
维护序列块的前缀权值块状数组,差分能得到任意一端块的权值块状数组。再将散块
在线性组合后的权值块状数组上,模仿主席树二分来爬,复杂度是
在单点修改时,只会有
取
接下来考虑插入,只需多考虑分裂操作。
评测记录 | 代码Link
题意 : 维护一个序列,支持(在指定元素后面)插入元素,询问两个元素的先后顺序。
显然可以使用平衡树维护,回答询问时,求出两者的排名并比较。这样能做到
考虑给每个元素一个标号,是的先后顺序和标号的大小顺序相对应。
给根一个值域区间,如
显然,这样得到的权值也满足左小右大的性质。若平衡树的最大高度为
使用重量平衡树(如替罪羊树)来维护这个序列,这样能够保证我们每次操作更新(并重新标记权值)的子树大小是
而且,替罪羊树的树高严格 double
或 long long
即可满足。
比较先后顺序时,只需比较标号即可,这样即可做到(均摊)
- 均摊
O(1)
将序列分成块状链表的形式,每一块的大小在
块外用替罪羊树维护。共产生
比较时,先比较所在块的先后顺序,再比较块内的先后顺序。
块内使用链表维护,插入的元素的权值设置为前驱和后继权值的平均数,这样所需的值域也并不大。
-
严格
O(1) : 先咕咕。 -
**题意** : 静态序列,查询区间 $\min$。
该问题的一个经典做法是
考虑将原序列分为
这样,若查询的区间端点异块,则使用散块前/后缀
上面的复杂度是
若区间端点同块,只能暴力,但是题目中一般不会出现这种情况。这样,我们就得到了一个简易的
递归套用本算法可以得到
3. 根号分治 & 自然根号
有时,根号复杂度会产生于一些非常自然的问题中。
例 : 有若干数和为
若对于某个数可以
-
例题① : 「Be Surrounded」
题意 : 维护一个
n 个点m 条边的无向图,支持下列两种操作 :- 将点
u 的权值+y - 查询与
u 相连的点的权值和
- 将点
点度数总和是
对于度数
在查询小点时暴力。修改时主动给周围的大点贡献,由于大点数目是
总复杂度
-
例题② : P3396 哈希冲突
题意 : 维护一个长为
n 的序列A ,支持下列操作 :- 单点修改
- 查询
\sum\limits_{i=1}^n[i\bmod x=y] A_i
考虑
对于剩下每个询问
-
练习题
-
[DS记录]P5309 [Ynoi2011]初始化
-
[DS记录]P5528 [Ynoi2012]WC,THUWC,CTSC与APIO2017
-
[DS记录]P5397 [Ynoi2018]天降之物
-
[??记录]CF1039D You Are Given a Tree
-
题解 CF1039E 【Summer Oenothera Exhibition】
-
-
有若干数和为 $n$ ,则最多有 $O(\sqrt{n})$ 个不同的数。
显然,最差情况是
-
有 $m$ 个集合,大小分别为 $S_1,S_2...S_m$。设 $n=\sum_{i=1}^mS_i$。 有 $q$ 次对子询问,处理询问 $(x,y)$ 的复杂度为 $O\big(\min(S_x,S_y)\big)$。 若将询问记忆化,则总复杂度为 $O(n\sqrt{q})$。
证明 : 我们选出复杂度最大的
记
最差情况是
例题 : P5576 [CmdOI2019]口头禅
-
对于(多串建立的)广义 SAM ,定义节点 $u$ 的 $siz_u$ 为 $parent$ 树子树内串的种类数。 (即将输入中第 $i$ 个串的所有终止节点加上标记 $i$ ,问子树内不同标记个数) 设 $n=\sum_i|S_i|$ ,则 $\sum_u siz_u$ 是 $O(n\sqrt{n})$ 级别的。
证明 : 对于某个
当
当
也存在达到此上界的构造,可见 Itst : 广义 SAM 上每个模板串包含的节点数量和的上界以及构造
例题 : [Str记录]CF204E Little Elephant and Strings
-
将 $\rm SAM$ 上每个节点的 $\rm endpos$ 集合划分为若干等差序列。等差序列的总个数为 $O(n\sqrt{n})$。
证明 :
-
-
由此,只有 $>len/2$ 的空位才能隔断某个等差数列,故每个点的等差数列个数至多是 $O(n/len)\leq O(\sqrt{n})$ 的。
也存在达到此上界的构造,限于篇幅故不展示。
找出这些等差序列的方法暂不介绍,有题目之后再说。
-
一个串的 $\rm Border$ 可以被划分为若干等差序列,其中公差 $>B$ 的等差序列总大小 $\leq O(n/B)$。