这名字···
这个算法是由之前的国家队队长莫涛巨神(Orz….%%% 64 )发明的,所以尊称莫队算法。
莫队算法
事实上,莫队算法这种东西,应该叫做——
一个优雅的暴力(引自Alan_Cty)
传说中能解决一切区间问题的算法
如果我们知道区间 [L,R] ,就能在O(1)求出 [L−1,R],[L+1,R],[L,R−1],[L,R+1] 的话,那就可以用莫队算法了。
有一种经典的问题:给你一些不带修改的区间询问,要求快速回答
显然,有一些我们可以通过线段树来完成,因为线段树是 O(NlogN) 的
但是,线段树有的东西是维护不了的。
看一个例子
给你一个数列,若干询问,要求回答区间内同种颜色大小。
线段树很难做,怎么办?
用莫队算法!
莫队算法的实质是通过将询问排序,每个询问均由前一个询问(排序后的)转移得来,通过一定的排序优化时间复杂度。往往可以有 O(NN‾‾√) 的效果
回到题目
显然对于两次询问
L,R
和
L′,R′
,知道了
L,R
的答案,就可以暴力计算
|L−L′|+|R−R′|
次得出
L′,R′
的答案。
|L−L′|+|R−R′| 。这个东西,数学上称之为曼哈顿距离
把每个询问看作是二维平面上的点,那么我们的最小总时间,就是这些点的最小曼哈顿距离生成树, 按照这个树的顺序做,复杂度变成了 O(NN‾‾√) (为什么?不好意思,我不会证),而且这个生成树连边也有特别的技巧,可以去看莫队在知乎上推荐的那篇。
然而这样有一点猥琐
有一个优美方便简洁好理解的替代品
分块大法好!
把整个序列分块,把 L 按照所在块的顺序为第一关键字,把 R ( R 本身!)为第二关键字排序。
为什么要分块不能直接排呢?
分块很好的减少了一种情况的影响。
L<L′<L″ ,并且距离很近,但是 R′<R<R″ ,并且 R′ 与另外两个离得很远。如果直接按 L 排序就会浪费非常多的时间。
由于每个块的大小是 N‾‾√
分块使得两个询问之间差异平均到了 L,R 上。
因此,理论复杂度大约是 O(NN‾‾√) ,实际上是 O( 玄学??跑的过就行 )
带上了修改,怎么办?
然后我们继续分块。
把二元组 L,R 变成三元组 L,R,x 。 x 是这次询问在修改第几次后。
然后把 R 所在块看作第二关键字, x 看作第三关键字排序即可。
转移时直接恢复(或删除)两次询问之间的修改。如果在区间内还要计算对答案的影响
然而修改的复杂度十分神奇,是 O(N53) ,且最优分块方式是每块 N23
复杂度的证明可以看看a_crazy_czy的博客
有一道板题
http://blog.csdn.net/hzj1054689699/article/details/51880644