分块学习笔记

分块学习笔记

分块是基于区间修改和查询的工具。

用一道题来引入:

给出一个长为n的数列,以及n个操作,操作涉及区间加法,单点查值。

#6277. 数列分块入门 1

这道题如果用暴力来求解的话,需要 \(O(n^2)\) 的时间复杂度,这样我们是不满意的,那怎么办呢?我们想到,如果 \(l=1,r=n\) 时,我们是否可以直接记一个变量进行记录现在已经加了多少值了,所以思路就出来了。

但是,\(l=1,r=n\) 的情况太少了,那能不能分为几组进行加值呢?

当然是可以的,我们直接分为 \(k\) 组 (当然,\(k\)组的长度尽量是一样的)。

在区间加时,在最左边的组和最右边的组之间用 \(O(k)\) 的时间复杂度进行遍历,依次加上对应的值,中间我们直接在一个这个组的 add 数组里加一个值即可,\(O(n/k)\)的时间复杂度。

那区间查询怎么做呢,那还不简单,直接原来的值加上这个组的值即可,\(O(1)\)的时间复杂度。

总时间复杂度 \(O(n* \max(n/k,n))\)

这里要使时间复杂度尽量的小,使 \(n/k=n\) 即可,所以 \(k=\sqrt n\) 是最佳情况,总时间复杂度 \(O(n \sqrt n)\)

所以,分块的核心思想就是\(l=1,r=n\)的解决方案加上 \(l=r\)的解决方案。

再来一道题:

#6279. 数列分块入门 3

沿用我们上面的思想,如果 \(l=r\),那我们就直接判断即可,如果 \(l=1,r=n\),我们是不是排序之后二分查找即可,那查询就不难了。

那修改呢?这也不难,直接按照上面那一题的方法即可,在查询的时候之间查询 \(x-add\) 即可。

再来看一道较难的题目:

#6281. 数列分块入门 5

区间开方?这个有点难办呀,但是我们想到,这个区间开方能开很多次吗?是不是每一个块至多开方六次就会全都变为零,这样开方的均摊时间复杂度就是 \(O(6n)\) 了,其他的都和上面的一样。

看一道不太一样的题目:

#6282. 数列分块入门 6

好,这里的单点插入我们好像没有见过,思考一下要用什么实现单点查询。

数组的插入是 \(O(n)\) 的,而链表的查询是 \(O(n)\),这里使用 vector 是最佳的,因为 vector 自带 insert 函数,更简单吧。

当你需要查询的时候直接遍历过来,而插入的时候也是遍历过来,操作的时间复杂度是 \(O( \sqrt n )\)

这样的时间复杂度就是 \(O(n \sqrt n)\) 的。

但是这样如果他一直把数放在一个块里呢?

那我们可以定期重构一下 vector 就可以了。

练习:

loj数列分块入门 1-9

P4145 上帝造题的七分钟 2 / 花神游历各国

posted @ 2025-02-10 14:27  hnczy  阅读(16)  评论(0)    收藏  举报