写这篇博文呢,主要还是为了准备信息队员交流,毕竟分块是我最喜欢的数据结构,所以我就试着写了一篇博文。
基本介绍:
分块是维护较为复杂的信息的,尤其是不满足区间可加性可减性的信息的重要工具。如果运用树状数组或线段树,代码也非常的麻烦和不直观,Debug 可以 Debug 一天。而分块是以一种 “暴力” 的思想来维护信息的,所以非常直观和好理解。其基本思想就是通过把序列划分为多个小块(块长一般为 √n)并预处理出一部分信息保存下来,从而达到维护信息的一种数据结构。分块直观,通用,容易理解和实现。接下来我将以几道例题来谈谈分块。
[Example 1] A Simple Problem with Integers
给定长度为 N(N≤105) 的数列 A , 然后输入 Q(Q≤105) 行指令。
第一类指令形如 C l r d
,表示把数列中第 l∼r 个数都加 d.
第二类指令形如 Q l r
,表示询问数列中第 l∼r 个数的和.
固然,这道题可以使用树状数组或线段树在 O((n+m)logn) 的时间复杂度内解决此问题,但是我们现在使用分块来求解。
我们考虑把数列 A 分解成 N 个长度为 ⌊√N⌋ 的段,其中第 i 段左端点为 (i−1)⌊√N⌋+1 ,右端点为 min(i⌊√N⌋,N) ,如图所示(大约很丑)。
像这样,我们把一个数列分成了 √n 段。
我们可以预处理出每段的数字之和,存在数组 sum 里面,其中 sumi 便是第 i 段的区间和,最后另外开一个 add 数组,然后设 addi 为这个块上还要加的数,起初 addi=0 。
我们分别进行处理:
- 区间加指令。
- 如果 l 和 r 在同一块 i 里面,暴力修改,把 Al,Al+1···Ar 都加 d 的同时 sumi+=d(r−l+1) 。
-
要不然就让 l 在第 lb(Left Block)段,让 r 在第 rb(Right Block)段。首先对于 i∈[lb+1,rb−1] ,使 addi+=d 。然后两端朴素更新。
- 区间查询指令。
-
如果 l 和 r 在同一块 i 里面,暴力查询,答案是 r∑i=lai+addi(r−l+1) 。
-
要不然就让 l 在第 lb(Left Block)段,让 r 在第 rb(Right Block)段。首先对于 i∈[lb+1,rb−1] ,使 ans+=sumi+addi×leni(leni 表示第 i 块的块长)。然后两端朴素查询。
这就是分块算法的基础——对 add 数组的使用。以后可能会用更多的数组来维护一个分块,我们统称其为 “大分块”。不过目前的阶段没有必要碰这个毒瘤的玩意。
因为段数和块长都是 √n ,所以整个算法的时间复杂度为 O((n+m)√n) 。
呃,这个,大家都知道我是 log 分块邪教的 (/ω\) 这样的块长是 log(n)×5 最坏时间复杂度是 O((n+m)nlogn×5) ,在 Q 多的数据下效率非常不错(DarkBZOJ Top1), 但是对于 n 多的数据就会非常坑爹。
请完成例题的代码实现:
请独立思考完成以下习题:
[Example 2] 教主的魔法
给定长度为 N(N≤106) 的数列 A , 然后输入 Q(Q≤3×103) 行指令。
第一类指令形如 M l r d
,表示把数列中第 l∼r 个数都加 d.
第二类指令形如 A l r k
,表示在区间 l∼r 求大于等于 k 的数的个数.
修改操作在前面已经说过了,大区间打标记,小边角暴力改,最后区间要查询的就是 k−addi,修改时直接排序。
我们再来考虑询问操作,直接把查询的块排好序,然后二分查找 k 的值,最后边角料直接暴力检查是不是大于等于 k 。
然后就可以过了。注意单块查询的时候考虑 add 数组的值。
复杂度大约是 O(nlogn+m√nlogn)。
其实代码实现还是挺简单的。
好吧其实要注意的地方还挺多的… 当时是调了一个晚上差不多。
请完成例题的代码实现:
请独立思考完成以下习题:
[Example 3] 蒲公英
给你一个长度为 n 的数列 a ,有 m 次询问,每次询问一个区间 l∼r ,求该区间的区间众数。如果众数有多个,则输出最小的那一个。注意,你的算法必须是在线的。
考虑 O(n√nlogn) 做法:预处理所有以段边界为端点的区间 [l,r] 的众数,再对每个数字建一个 vector 桶,按顺序保存该数值在序列 a 中每次出现的位置。
对于每个询问,扫描 [l,L) ,(R,r] 中每个数 x ,在对应的 vector 里二分查找即可得到答案。
感谢 Bovine__Kebi 提供的 O(n√nlogn) 代码。
请完成例题的代码实现:
请独立思考完成以下习题:
我们现在分块的学习可以入门了。(也许我可以搞个进阶教程)我们掌握了分块的思想和基本操作,那么非常感谢您能阅读到这里!!!谢谢 qwq
如有谬误,敬请指正 qwq
8 条评论
lhd2006 · 2020年7月19日 6:53 下午
删我账号干嘛
Inversentropir_36 · 2020年7月19日 6:55 下午
发布不友善言论
Inversentropir_36 · 2020年7月19日 6:55 下午
而且为什么在我博客上发
boshi · 2020年7月19日 8:14 上午
推荐 Yuno loves sqrt technology I 和 Yuno loves sqrt technology III
Inversentropir_36 · 2020年7月19日 9:32 上午
稍安勿躁~《再谈数列分块问题》里有的~
boshi · 2020年7月20日 1:55 下午
赞诶
Qiuly · 2020年7月18日 4:12 下午
感谢发文 /qq
Inversentropir_36 · 2020年7月18日 6:14 下午
/qq Qiuly