莫队

莫队

一种由莫涛提出的算法。

要求的是一个区间\((l,r)\)上的某个问题

如果一个函数\(f(l,r)\)可以轻易地转换为\(f(l+1,r)\),\(f(l-1,r)\),\(f(l,r+1)\),\(f(l,r-1)\),那我们就可以用类似于滑动窗口,双指针的东西维护每个值。然后移动左右区间来求出\(1\sim n\)范围内每个\(f(l,r)\)的值。

用代码形象地说

while(l>L)f(l,r)->f(l-1,r),l--;
while(r<R)f(l,r)->f(l,r+1),r++;
while(l<L)f(l,r)->f(l+1,r),l++;
while(r>R)f(l,r)->f(l,r-1),r--;
存答案

这里有个细节。要先扩大区间再缩小区间。这样可以保证区间没有变空的时候。

一般莫队步骤

  1. 寻找能不能轻易的将\(f(l,r)\)可以轻易地转换为\(f(l+1,r)\),\(f(l-1,r)\),\(f(l,r+1)\),\(f(l,r-1)\)
  2. 寻找合适的方法排序
  3. 求答案

这个排序就很重要。那我们按什么排序呢?这就要用到分块了。注意看,我们每次都要扩大缩小区间。如果一个数据要卡你,那就会这样出

\[(1,n)\rightarrow \left( \frac{n}{2},\frac{n}{2}+1 \right) \rightarrow(1,n)... \]

这样时间复杂度就变成了\(O(nq)\)(\(q\)代表查询次数)。那我们的复杂度又会激增。所以我们就想要一种方法让\(l,r\)变化最小。那这时分块就出马了。

我们可以分成\(\sqrt n\)块,按\(l\)所在的块为第一关键字,\(r\)为第二关键字排序。这样每次在块内移动最多移动\(\sqrt n\)次,跨块移动也只会移动\(2\sqrt n\)次。所以复杂度就被优化倒了\(O(q\sqrt n)\)

如果\(n,q\)同阶,那复杂度从\(O(n^2)\Rightarrow O(n\sqrt n)\)

posted @ 2025-12-22 20:26  NumLuck  阅读(7)  评论(0)    收藏  举报