优雅的暴力 --- 分块
简介
关于什么是分块,顾名思义,就是将区间分成一块一块的,这就是分块,这是一种优雅的暴力。
我们可以将整个区间按照特定的性质分为 \(\sqrt n\) 个长度为 \(\sqrt n\) 的块,来代表整个区间。
我们将其称为一种数据结构,我感觉是因为它维护了一些东西。 它遵从一个思想: 小段朴素,大段维护
小段朴素,大段维护
怎么理解, 假设我们维护区间乘法,(很显然我们是可以用线段树 log 的求解) ,我们对于一个整块 \(ql , qr\) 我们打一个 \(lazy\) 标记,表示这个区间需要 \(\times k\) ,但是我们需要询问的时候 \(l ,r\) 这个区间,我们取最坏的情况,就是 \(l < ql ,\text{&} r > qr\) ,所以这个时候我们就直接把原数组进行暴力更改 。 这就是大段维护,小段朴素,朴素就是暴力。
数列分块 1 ~ 9
不一定非要按照分块写,有的题写着写着分块调不出来了,就选择用线段树解决或者选择其他 \(np\) 的东西 \(gank\) 掉了 。
代码链接就是直接点开题目的提交记录 , 查找提交者 : lucky_king , 即可。
数列分块1
【description】 :
涉及区间加法 , 单点查询。
【solution】
- \(1.\) 线段树暴力 $n\log n $ 求解,显然可过,这里直接是线段树的模板题,就不赘述了
- \(2.\) 分块做 。 其实是和线段树的思路差不太多的,线段树的逐渐 \(2 ^{k}\) 持续分块,并且块的关系关系成树形,但是这个分块则是单层的,直接一次性分成 \(\sqrt n\) 个块,并且块长为 \(\sqrt n\) ,这使得我们本来的复杂度会显著降低。就是本来的 \(n^2\) 的做法降成了 \(n\sqrt n\) 的做法,显然也是可过的。
具体分块怎么做 : 就是开一个 \(tag\) 来表示懒惰标记,本来我们朴素的算法是直接枚举需要的区间:\([l ,r]\) ,记一个 \(tag\) 则是对这个区间的整块不枚举加了,标记一下,等到询问的时候,看一下是否有 \(tag\) ,有的话就加上,就 \(OK\) 了。
数列分块2
【description】:
涉及区间加法,查询小于 \(x\) 的元素个数 。
【solution】 :
- 这道题显然分块是更有优势了。
- 区间加法不必赘述了,我们对块内进行排序,同时比较一下块内最大元素和需要查询的这个 \(x\) 是什么情况,如果 \(Max > x\) ,那么就在这个区间内,我们就直接找即可。如果 \(Max <= x\) ,那么直接加上这个块的长度。
数列分块3
【description】:
给出一个长为 \(n\) 的数列,以及 \(n\) 个操作,操作涉及区间加法,询问区间内小于某个值 \(x\) 的前驱(比其小的最大元素)
【solution】:
- 显然平衡树是一种很不错的方法
- 分块做法 : 接着第二题,我们可以在块内二分,找到最大的元素,求解。可以用 \(\text{lower_bound}\) ,不必自己再写一个二分函数
数列分块 4
【description】:
操作涉及区间加法,区间乘法 。
【solution】
- 显然的线段树,模板题。
- 我们是可以分别开两个标记 \(tag1 , tag2\) 分别表示加法的懒惰标记和乘法的懒惰标记。但是我们需要注意的是,我们在进行修改的时候,我们需要先把我们标记直接 \(pushdown\) 传下去。最后提醒一下: 先乘后加,数学基本 。
数列分块5
【description】 :
涉及区间求和和区间开方
【solution】 :
我们发现这个很棘手,因为区间开方和区间求和显然是无法打个标记就能行的。我们需要在区间求和的时候将该区间内的开方操作全部都开完。所以这个题,没有什么特别妙的解法,选择用分块来直接解决掉区间问题。
- 我们仍选择用 \(tag\) 来表示开方操作,根据数据范围我们发现,\(a_i\) 不断开方,最多开个位数次就可以开成 \(0| 1\) , 因为是向下取整的。 令 \(tag_p\) 表示 \(p\) 这个块开方的次数,如果这个 \(tag_p\) 超过 \(4\) 次话,那就必然是说明其已经全部为 \(0|1\) ,在搞的时候,直接跳过该区间。
数列分块6
【description】 :
涉及单点插入,单点修改。
【solution】:
- 这道题的先分块,然后在插入的时候我们比较一下需要插入的位置应该是在块 \(i\) 的左边还是右边还是就在这一个块内,插入的话,直接选择用 \(vector\) ,即可。 最后可能一直在某一个块内一直插入,从而导致这个块的块长巨长,那么我们也就可以自己设定一个块长,规定块长超过多少的时候,暴力重新构造块。
- 由于这道题我和 憨憨一样,我没有调出分块做法,所以就只有思路了,没有 \(A\) 掉的分块的代码。 我们其实发现这道题其实是可以用平衡树做的,同时,有一种神奇的 \(vector\) ,我们也是可以做的,还比较快。我用它 \(A\) 掉了,神奇。
没时间了,暂且咕了