莫队

  • upd on 10.13:修改了假完的复杂度分析。

考虑一个这样的问题:

给定一个长度为 \(n\) 的序列 \(a\)\(q\) 次静态询问。每次给定一个区间 \(l, r\),求解这个区间的某种属性。允许离线。

一般来说暴力做复杂度是 \(\mathcal O(nq)\) 甚至更高的。比如说如果要求解区间颜色数(即有多少种不同的数),那么需要维护一个桶统计每种数字的出现次数。然后维护一个指针,从 \(l\)\(r\) 扫描,每扫到一个数就更新桶,并尝试更新答案。

int cnt[N], res;

for (int i = l; i <= r; ++ i ) {
    if (!cnt[a[i]]) res ++ ;
    cnt[a[i]] ++ ;
}

这个“扫描”的过程可以这样理解:如果我们已经解决了 \([l, r]\) 的询问,维护好了统计每个数字的出现次数的桶,那么我们可以用 \(\mathcal O(1)\) 的时间复杂度更新表示 \([l, r+1]\) 的桶,以及求解 \([l, r+1]\) 的答案。

同理,如果已经处理好了 \([l, r]\) 的询问,那么 \([l, r\pm 1],[l \pm 1, r]\) 也可以 \(\mathcal O(1)\) 的更新桶、求答案。

那么如果上一次询问的区间是 \([l, r]\),下一次询问的区间是 \([l',r']\),那么我们可以用上面的方法,每次让一个端点加减 \(1\),就可以在 \(|l-l'|+|r-r'|\) 步内得到新的答案。

事实上,如果我们把一次 \([l, r]\) 的询问看作是平面上 \((l, r)\) 这个点,那么从上一次询问 \([l, r]\) 拓展到下一次询问 \([l', r']\) 的复杂度,就等于平面上 \((l, r)\)\((l', r')\) 的曼哈顿距离。

显然截至目前我们并没有将复杂度从暴力的 \(\mathcal O(nq)\) 优化下来,因为任意两个点的曼哈顿距离都是 \(\mathcal O(n)\) 级别的。但是注意到询问允许离线,也就是我们可以任意调换处理询问的顺序。那么是否存在一种处理询问的顺序使得可以证明它的复杂度小于 \(\mathcal O(nq)\) 呢?

现在的问题是:

平面上有 \(q\) 个点,每个点横纵坐标都在 \([1, n]\) 内。现在要求从某个点开始游走,要求遍历到每个点,且走的总距离(也就是每相邻两个点的曼哈顿距离)最小。

第一个想法是,如果所有点的纵坐标都随横坐标的增大而增大,那么我们只需要从横纵坐标最小的那个点出发,一直向右或向上走。这样总共向上走 \(\mathcal O(n)\) 次,向右走 \(\mathcal O(n)\) 次,总复杂度就是 \(\mathcal O(n)\) 的。事实上这就是双指针的思想。

显然题目并没有保证这个优美的性质。于是我们考虑将点分成若干组,每组内尽量满足这个性质。

分组的方法是这样的:我们将横坐标(对应回区间就是左端点)接近的点分成一组。具体的,我们设置一个阈值 \(B\),将横坐标在 \([1,B]\) 内的点分在同一组,在 \([B+1,2B]\) 内的点分在同一组,在 \([2B+1,3B]\) 内的点分在同一组,以此类推。显然所有点被分成了 \(\mathcal O\left(\dfrac nB\right)\) 个组。

然后我们将组内的点按照纵坐标(对应回区间就是右端点)从小到大排序,即按照纵坐标从小到大遍历每个点,也即每个组内只往上走不往下走。

图来自 Gu_Pigeon

这样虽然也没法在组内实现「所有点的纵坐标都随横坐标的增大而增大」,但是每当下一个点的横坐标出现问题(即这个点的横坐标比上一个点的横坐标大)时,我们也只需要用 \(\mathcal O(B)\) 步就能解决。感觉上复杂度是很优秀的。

具体地我们分析这个做法也就是莫队算法的复杂度。分为几部分:

  • 某块内:
    • 向上移动:因为一块内的点纵坐标递增,所以一组内总共向上移动 \(\mathcal O(n)\) 次。总共 \(\mathcal O\left(\dfrac nB n\right)\)
    • 左右移动:从一个点到下一个点,不可能移动超过 \(B\) 次否则就超出这个块了。总共 \(\mathcal O(qB)\)
  • 两块之间:
    • 上下移动:总共 \(\mathcal O\left(\dfrac nB n\right)\)
    • 左右移动:一次最多移动 \(2B\) 次。总共 \(\mathcal O\left(\dfrac nB B\right)\)

综上总复杂度为 \(\mathcal O\left(\dfrac{n^2}B + qB\right)\)。当 \(B=\dfrac n{\sqrt q}\) 时达到最优 \(\mathcal O(n \sqrt q)\)

posted @ 2025-08-06 22:43  2huk  阅读(45)  评论(0)    收藏  举报
2048 Game
Score
0
Best
0