分块算法总结

来源:互联网 发布:java写入文本文件 编辑:程序博客网 时间:2024/06/02 21:31

分块算法总结

前言

第一次接触分块是写 luogu 线段树和树状数组模板 的时候,看了一篇题解,后来发现分块其实是一种很实用的暴力算法。
如果本blog有错误,请务必通知作者进行修改!

线性分块(序列分块)

(时间复杂度O(n),证明推荐 关于分块时间复杂度的证明)

简单介绍

如果你已经知道线性分块是什么了,可以直接跳转到“具体实现”,因为这一节基本都是废话

先贴一个 dalao【orz】的blog。(好吧我承认这篇blog用了dalao用过的的名字orz)
远航之曲-分块算法总结

下面进入正题。(终于到正题了)

如上文言,分块是一种很暴力的算法。嗯,用ZHW的话就是一种优化过的暴力。
具体来说,分块算法就是将一段很长很长的序列分成若干截较短的序列,分别进行操作。
当然,作为一种暴力算法,一般来说,它其实没有线段树、树状数组它们优……(但是也是能看的)
为什么是“一般来说”呢,因为……
暴力出奇迹嘛。

具体实现

引用 yhzq dalao 的话(懒得写)。

0.初始化
我们首先把求出块的大小
block=n
然后求出一共有多少个块
num=n÷block
再求出每一个块的左右端点
l[i]=(i1)×block+1
r[i]=i×block
最后求一下每个节点属于哪个块
belong[i]=(i1)÷block+1
然后就初始化完了(有可能还要维护一下别的值)
这个步骤一般所有分块都有。

其实就是把 N 分成N 块,分别查询和修改。

这里就不写例题和题解了,可以参照 yhzq 和 黄学长 的blog。

树分块

如果你已经了解并掌握了线性分块,那么我们可以学习一种新的暴力算法……树分块。
如果没有,建议先写几道题(例如文首提到的 线段树和树状数组模板)。

如何分

和线性分块相似,树分块就是把树分成一些比较小的连通块。然而树比较复杂,怎么分是个问题。

方法一 作死不对法

要注意 它并不是可行的。
首先我们设置一个值block(可以认为是N)。
然后对树进行DFS遍历,每遍历到一个节点把它压入栈中。
当栈中节点数超过block时,弹栈,弹出的元素即为一块。
但是:
这样做有许多七零八落的节点,可能树块内部并不是联通的。

方法二 官方正确法

那么正确的做法是什么呢?

对于每一个节点x:    以初次访问它时栈的栈顶作为相对栈底,    每遍历完 x 的子节点所在的子树,    判断此时 栈顶-相对栈底 得到的元素个数 是否 >=block.        若成立,弹栈至 相对栈底。    访问完所有子节点:        回溯到x的父节点时,把x压入栈。

具体实现

(干笑)还没写过,以后再补充。


未完待续


参考 & 博文推荐
远航之曲
hzwer
漠空

关于分块时间复杂度的证明
《浅谈分块思想在一类数据处理问题中的应用》 罗剑桥
《浅谈分块在一类在线问题中的应用》 邹逍遥
《非常规大小分块算法初探》 徐明宽

原创粉丝点击