主要是因为两三个
log
\log
log的算法经常被分块秀死,
博主不得已学习这种刷RK榜神器。
下面用修改时间 O ( ) O() O()-查询时间 O ( ) O() O() -空间 O ( ) O() O() 来描述复杂度(对于分块,卡空间是很致命的)
1.分块维护块内信息,询问查每一个块和散点。
这种是最裸的也是最容易被搞出一个
log
\log
log算法的,没意思。
O
(
1
)
−
O
(
n
)
−
O
(
n
)
O(1) - O(\sqrt n) - O(n)
O(1)−O(n)−O(n)
2.分块维护第i块到第j块的总信息。
用于信息并不好O(1)整块查询,用空间换时间。
通常没有修改。
O
(
N
/
A
)
−
O
(
n
)
(
散
块
)
+
O
(
1
)
(
整
块
)
−
O
(
n
)
o
r
O
(
n
n
)
O(N/A) - O(\sqrt n)(散块)+O(1)(整块) - O(n) orO(n\sqrt n)
O(N/A)−O(n)(散块)+O(1)(整块)−O(n)orO(nn)
3.分块维护块前缀和信息。
每次修改把后面的块的前缀和取消,更新该块然后重新前缀和(可以直接加的话也可以直接加)。
O
(
n
)
−
O
(
n
)
(
散
块
)
+
O
(
1
)
(
整
块
)
−
O
(
n
)
o
r
O
(
n
n
)
O(\sqrt n) - O(\sqrt n)(散块)+O(1)(整块)- O(n)orO(n\sqrt n)
O(n)−O(n)(散块)+O(1)(整块)−O(n)orO(nn)
4.分块维护前缀和与块关系的信息。
更加适合处理散块和整块有关系的情形。
比如BZOJ 3744: Gty的妹子序列
一般无修改。
可以做到:
O
(
N
/
A
)
−
O
(
n
)
−
O
(
n
n
)
O(N/A) - O(\sqrt n) - O(n\sqrt n)
O(N/A)−O(n)−O(nn)
5.值域分块。
这个东西是拿来求比如一个区间内第K大的或是区间内小于X之类和数值大小有关的信息。
O
(
1
)
−
O
(
n
)
−
O
(
n
)
O(1) - O(\sqrt n) - O(n)
O(1)−O(n)−O(n)
与
O
(
n
)
−
O
(
1
)
O(\sqrt n) - O(1)
O(n)−O(1)的算法配套使用可以得到
O
(
n
)
O(\sqrt n)
O(n)的优秀复杂度(也是吊打两三个
log
\log
log算法的基础)
比如说:莫队
O
(
n
)
−
O
(
1
)
O(\sqrt n)-O(1)
O(n)−O(1)
维护块前缀和的分块
O
(
n
)
−
O
(
1
)
(
整
块
)
∗
O
(
n
)
(
值
域
分
块
)
+
O
(
n
)
(
散
块
)
O(\sqrt n)-O(1)(整块)*O(\sqrt n)(值域分块)+O(\sqrt n)(散块)
O(n)−O(1)(整块)∗O(n)(值域分块)+O(n)(散块)
6.莫队:
S
S
S为块大小。
O
(
q
S
+
n
∗
n
S
)
O(qS + n*\frac nS)
O(qS+n∗Sn)
S
=
n
q
S = \frac n{\sqrt q}
S=qn时最小。
为
O
(
n
q
)
O(n\sqrt q)
O(nq)(记住是谁开根,这意味着值域小询问多更可以用莫队。。。。。)
其中
O
(
q
)
O(q)
O(q)次询问,平均每次询问
O
(
n
q
)
O(\frac n{\sqrt q})
O(qn)次修改。
(可能)可以看作
O
(
n
)
−
O
(
1
)
O(\sqrt n) - O(1)
O(n)−O(1)
差不多就这样,分块重于实践,理论简单,实现实际上还是有难度的。
7.块状链表。
就是把每个块前后相连,支持插入,某一块过大之后可以分裂。
支持分块的所有操作,代码还比分块好写好调(个人观点)。
只是有点长。
可以套前缀块的值域分块以
O
(
n
n
)
O(n\sqrt n)
O(nn)的复杂度在带插入区间K小值踩爆
O
(
n
log
2
n
)
O(n\log^2 n)
O(nlog2n)的所谓替罪羊树套函数式线段树正解。
PS:在luogu只放块状链表过,vfk大佬立的flag。。。。。。