莫队算法分那么几类:
- 普通序列
- 带修改
- 树上
- 回滚
- 支持在线
其实上述的类型还可以组合起来(非常的毒瘤)。
个人理解莫队算法的精髓在于如何利用暴力将答案再合理的时间和空间内跑出来。说白了:
\[莫队算法=一种很牛逼的自定义排序+分块处理+暴力 \]
首先要理解自定义排序,这个排序之后整个序列可以最快地处理所有的询问(这里暂时不谈第五类问题(支持在线),这里认为莫队是只能离线处理问题的,必须先把所有的问题都离线下来)。怎么为之快,快要看左端点移动的总距离+右端点移动的总距离最小。那么一般用块的奇偶性来排序就够快了。如下:
bool cmp(const node &a,const node &b)
{
return (p[a.l]^p[b.l])?(p[a.l]<p[b.l]):((p[a.l]&1)?(a.r<b.r):(a.r>b.r));
}
排完序后大致移动的次数就在可控的范围内了。
其次是分块,因为一般这种序列题的复杂度是\(O(\frac{n^2}{S}+mS)\) (\(n\)是序列长度,\(m\)是询问次数,\(S\)是块大小)。
那么用均值不等式去分析这个复杂度就好了。一般\(n\),\(m\)同阶的时候取\(\sqrt n\)最优,但是假如\(n\)和\(m\)有别的情况的话具体分析,有时候还要决定用时间换空间来保证空间也过得去。
之后就是暴力,想办法怎么通过指针的移动(进入和离开所求区间\([ql,qr]\))的时候统计答案。
这个要看基本功了(很多时候就是数学功底)。
一般这个复杂度要尽量的低,最好是\(O(1)\),否则会影响整体的复杂度。
下面我们具体情况具体分析一下:
普通序列莫队
没什么好说的,直接套板子,有时候维护不了了就想想变化量是什么,其实只用知道变化量是什么其实都不太难了。
带修改序列莫队
好像只用在原有的基础上加上一维表示时间即可。但是块大小应该不能是\(n^{0.5}\)了,这样会将整体复杂度退化成\(O(n^2)\)。块大小可以取\(n^{\frac{2}{3}}\)或者是\(n^{\frac{3}{4}}\)。