介绍和认识:
分块算法实质上是一种是通过分成多块后在每块上打标记以实现快速区间修改,区间查询的一种算法。其均摊时间复杂度为
。
分块算法相较于各种高级数据结构,具有简便易写,方便调试等多种优点。在同等数据规模下,如
,其时间效率并不会低太多,在很多时反而是一种更好的选择。
分块算法;
为了使得其有着最稳定的时间复杂度,我们经常将一个长度为 的序列分为 个大小为 的块,如果 不是完全平方数,则序列最右端会多出一个角块。
比如给定序列:
1 2 3 4 5 6 7 8 9 10
那么分块为:
因为
的值向上取整为
,所以分为
块,前
块大小为
,最后一个是角块大小为
。
而我们要有一个记录值,记录每一个序号属于哪一块。
根据上图,
属于第一块,
属于第二块,
属于第三块,
属于第四块。
获取每一个序号的所在块:
int n;//总个数
int block=sqrt(n);//每一块大小
for(int i=1; i<=n; i++) {
belong[i]=(i-1)/block+1;//每一个数所在块
}
namo,如何用分块来维护区间最值?
维护区间最值
比如这题:给定一个长的为n数列,求出任意区间[l,r]的最大值
学此之前,我想到的解法有:线段树,树状数组,滑动窗口。
但是现在可以拿分块做!
拿上面这张图,我们现在给每个点上加了一个权值,每个块维护一下块内最大值,这样当我们查询任意一个区间
)时:
- 如果 所在的块与 在的块相同,如 ,则直接暴力查询即可,时间复杂度 。
- 若其不在一个块但是块是相邻的,一样是暴力查询,时间复杂度 。
- 若其块不相邻,如 ,我们先处理两边的边块角块,先暴力查询 和 所在的块内最大值,最后直接查询中间块内最大值即可,时间复杂度 。
所以总时间复杂度是
。
接下来是区间修改:
区间修改
- 对于整块修改,我们打个加法标记,即当前块增加了多少,最大值相应的就增加了多少。
- 多于边块角块,暴力修改,特判最大值即可。
所以总时间复杂度也是 。
当然分块还可以解决很多区间问题,可以参考:oi-wiki
比如这题:给出一个长为
的数列,以及
个操作,操作涉及区间加法,询问区间内小于某个值
的前驱(比其小的最大元素)。
ac代码:https://blog.csdn.net/nuoyanli/article/details/103985041
分块的实质
转自:https://zhuanlan.zhihu.com/p/42089861
分块其实是一种思想,其本质是一种树形结构,它是一种只有三层的树,形态如下:
分块算法的延申
莫队(待补…)