分块学习笔记

分块学习笔记

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

用一道题来引入:

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

#6277. 数列分块入门 1

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

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

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

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

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

总时间复杂度 O(nmax(n/k,n))

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

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

再来一道题:

#6279. 数列分块入门 3

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

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

再来看一道较难的题目:

#6281. 数列分块入门 5

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

看一道不太一样的题目:

#6282. 数列分块入门 6

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

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

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

这样的时间复杂度就是 O(nn) 的。

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

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

练习:

loj数列分块入门 1-9

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

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