[Резюме] 基础数列分块
Preface
分块可以 \(O(n\sqrt{n})\) 解决不能用线段树解决的问题,即不能快速合并区间信息的问题,是很多高级算法与数据结构的基础。
本篇只是作者基础入门的一些感受,例题为 \(\text{LOJ} [6277,6285]\);下一步计划学习莫队算法,这里有学习总结。
Content
0
如何分块?考虑将标准块大小 \(len\) 定为 \(\lfloor \sqrt n \rfloor\) 或 \(\lfloor \sqrt N \rfloor\),记录编号或指定计算方式以判断两点是否在同一块中。个人通常记录 \(p_i=\lfloor\dfrac{(i-1)}{len}\rfloor\);维护块信息,建立块标记方便修改,建立块值方便查询。修改碎块时更新所在块的值,查询时要与块标记合并。
这是基础数列分块的模型。
1
区间加值,单点查询。
是 \(4\) 的退化版,所以请看 \(4\)。
时间复杂度 \(O(n\sqrt n)\).
适时码风过于迥异,暂时不放代码。
2
区间加值,查询指定数区间排名。
观察到整块加值不会影响块内元素相对大小,所以初始出块内有序表,加值时整块仅更新块标记。碎块更新则考虑暴力重构:加值,然后所在块重排序。查询时整块二分,碎块里逐个统计即可。
时间复杂度 \(O(n\sqrt n\log n)\).
3
区间加值,查询指定数区间前驱。
和 \(2\) 本质相同,仍然维护有序表,只不过二分和统计的对象不同。
4
区间加值,区间查询。
建立单点值为元素值,块标记为加值,块值为元素之和,记录块长的分块模型。整块加值加在块标记上,碎块加值时所在块值也更新。查询时整块值为块长乘标记加块值,碎块值为元素值加所在块标记值。
时间复杂度 \(O(n\sqrt n)\).
5
定义 \(f(x)=\lfloor\sqrt x\rfloor\),仿照多重对数 \(\log*\) 定义 $ f* $,可发现 \(f*(V) \le 6\),\(V\) 为值域,即 \(f*(V)\in O(1)\)。
建立单点值为元素值,块标记为修改次数,块值为元素之和,记录块长的分块模型。整块修改时,若块标记大于 \(6\) 则不用更新,否则暴力更新每一项,统计块值;碎块则直接计算并更新所在块块值。查询时,整块就加块值,碎块逐个累加即可。
时间复杂度 \(O(n\sqrt n)\).
6
区间插值,区间查询,数据随机生成。
首先对初始数组分块,统计出每块的元素表和块长。对于每一个插入操作,从头累加块长,当累加和大于等于给定位置时,将该块内原来大于等于给定位置的元素整体后移,然后放入给定元素。
平均时间复杂度 \(\Theta(n\sqrt n)\).
一些口嗨:
可以树状数组维护块长前缀和二分优化常数?
平均时间复杂度 \(\Theta(n\sqrt n\log^2 n)\).
7
区间乘,区间加,单点查询。
建立单点值为元素值,块值为元素之和,记录块长的分块模型。;类似线段树,建立两个标记系统,加和乘。考虑合并式为 \(\text{tag}_\times\cdot\text{val}+\text{tag}_+\);修改整块时,若为加,则仅更新 \(\text{tag}_+\),若为乘,则将 \(\text{tag}_\times\) 和 \(\text{tag}_\times\) 乘上给定值(乘法分配律)。修改碎块时标记下放,恢复 \(\text{tag}_+=0,\text{tag}_\times=1\),再分别修改。查询整块直接将值与标记合并后统计,碎块下方后分别统计。
时间复杂度 \(O(n\sqrt n)\).
8
区间修改,区间查给定数个数。
维护块内有序表和块长。
处理修改:整块打替换标记,碎块下放标记,分别修改后暴力重构有序表。
处理查询:令 \(c\) 为给定数,\(\text{len}\) 为块长。整块无标记时,二分边界计算个数,即:
cnt_c=upper_bound(rangeL,rangeR+1,c)-lower_bound(rangeL,rangeR,c)
有标记直接对比标记,贡献为 \([\text{tag}=c]\times \text{len}\)。
碎块无标记,就分别统计碎块,否则对比 \(\text{tag}\).
9
区间最小众数。
先离散化,然后预处理两个数组:
\(s[i][j]:\) 前 \(i\) 块中 \(j\) 出现的次数。直接扫描,时间复杂度 \(O(n)\),空间复杂度 \(O(n\sqrt{n})\).
\(p[i][j]:\) 块 \(i\) 到块 \(j\) 的最小众数。每次确定块 \(i\) 作为起点,维护一个计数数组和当前众数,顺次枚举元素,当枚举到块 \(j\) 终点时,更新 \(p[i][j]\),时间复杂度 \(O(n\sqrt n)\),空间复杂度 \(O(n)\).
查询:容易发现区间最小众数是整块部分的最小众数或碎块部分的最小众数。容易证明结论:两区间的共同众数一定是两区间的众数之一(咕咕咕)。则统计整块部分的众数的总出现次数和碎块部分众数的总出现次数,其时间复杂度只有枚举碎块部分的 \(O(\sqrt n)\).
Ending
Thanks for reading!
\(\text{QED}\).
Please enjoy Rachmaninov prelude No.5:

        分块可以 $O(n\sqrt{n})$ 解决不能用线段树解决的问题,即不能快速合并区间信息的问题,是很多高级算法与数据结构的基础。本篇只是作者基础入门的一些感受,例题为 $\text{LOJ} [6277,6285]$
    
                
            
        
浙公网安备 33010602011771号