莫队学习笔记

莫队,一个很好玩的算法,基础莫队可以以 \(O(m\sqrt{n})\) 轻松处理 RMQ 一类的问题。狠狠恶心一下不爱开大数据的出题人

文章内普遍认为 \(n,m\) 同阶。

文章中的“一个块中的询问”指所有询问中 \(l\) 位于这个块的询问。

从基础开始。

普通莫队

对于 RMQ 问题,我们一般采取 ST 表、线段树等 log 级别的数据结构维护,但有些题目很难用这些数据结构维护,此时可以尝试莫队。

介绍

首先,莫队的底层逻辑是由 \([l,r]\) 区间的答案来更新 \([l-1,r]\)\([l+1,r]\)\([l,r-1]\)\([l,r+1]\) 的答案。大多数情况下,这个转移是 \(O(1)\) 的,不过有的题也会改。

莫队就是让一对 \([l,r]\) 不断的在 \([1,n]\) 上移动,以此记录每个查询的结果。

如果我们在线实现这一操作,容易发现可能被卡到 \(O(nm)\) 的复杂度,莫队就是要让查询离线,找一个顺序让区间移动的次数尽量少,做到 \(O(m \sqrt{n})\) 复杂度。

优化方法

容易发现,可以尽量让 \(l\) 不动,让 \(r\) 不断在区间上移动查询。于是我们就可以对查询以 \(l\) 为第一关键字排序,以 \(r\) 为第二关键字排序。

但是随便模拟一下就会发现这玩意也太好卡了吧,我只需要让每个 \(l\) 都不同,然后让 \(r\) 的差距特别大不就行了?

于是,就涉及到另一个毒瘤数据结构了————分块,没学过的朋友们可以去稍微看一下,基础不难。

对于这 \([1,n]\) 的序列,将它分成 \(\sqrt{n}\) 个块,所以每个块的长度也是 \(\sqrt{n}\) 级别的。

然后,我们 \(l\) 所在的块为第一关键字,以 \(r\) 为第二关键字排序,容易发现,一个块中的所有查询,\(l\) 移动的量级为 \(\sqrt{n}\)\(r\) 最多移动 \(n\) 次。

实现
bool cmp(node x,node y){
    if(pos[x.l]==pos[y.l]){
        return x.r<y.r;
    }
    return x.l<y.l;
}

奇偶性优化

对于每个块,如果它的编号为奇数,那么让其中的查询以 \(r\) 升序排序,为偶数则以 \(r\) 降序排序。它可以让查询的 \(l\) 在不同块时,\(r\) 移动的长度尽量小。在查询比较密集时优化效果比较明显。

实现
bool cmp(node x,node y){
    if(pos[x.l]==pos[y.l]){
        if(pos[x.l]&1) return x.r<y.r;
        return x.r>y.r;
    }
    return x.l<y.l;
}

带修莫队

普通莫队能干的事还是太少了,如果在查询里插点修改就完全不能用了。

所以,我们需要一个能修改的莫队。

时间戳

我不知道应不应该叫这个名字,但是你只要知道这玩意就是用来记录这是第几次出现的就行了。

很容易发现在处理当前区间查询时,将所有在这个查询前的修改改了就行,所以可以把查询和修改分开,拿一个指针记录修改改到哪了然后继续改。

实现
while(last<q[i].t){
    last++;
    if(t[last].p>=l && t[last].p<=r){
        add(t[last].x);
        del(a[t[last].p]);
    }
    swap(a[t[last].p],t[last].x);
}
while(last>q[i].t){
    if(t[last].p>=l && t[last].p<=r){
        add(t[last].x);
        del(a[t[last].p]);
    }
    swap(a[t[last].p],t[last].x);
    last--;
}

块长优化

明显地,因为多加了一个修改,如果还沿用原来的 \(\sqrt{n}\) 的块长,很容易被卡成 \(O(n^2)\)

然后呢,怎么优化?我不会证明,有兴趣的自己搜一下。

对于结论来说,取 \(n^{\frac{2}{3}}\) 的长度为块长复杂度就能达到 \(O(n^{\frac{5}{3}})\) 的结果,已经是很优秀的复杂度了。

那你又说我怎么算出 \(n^{\frac{2}{3}}\) 啊,我又不会换底公式什么的。

那你就用 pow 呗,不会有人不知道这个函数能处理小数乘方吧。

回滚莫队

上强度的来了。

虽然但是带修莫队能做的题目还是太公式了,我们需要更加强力的算法!

于是,有人开始考虑解决这样的问题:如果莫队时增加和删除这两种操作只有一种比较好处理,我们怎么解决?

然后回滚莫队就诞生了,也被称为 不删除/不增加 莫队。

原理

容易得到回滚莫队不能使用奇偶性优化,因为奇偶性优化会使 \(r\) 必须增加和减少,也就必须要保证可以实现增加和删除两种操作。

对于每一个块内的询问,

posted @ 2025-10-18 11:10  幻琳  阅读(16)  评论(0)    收藏  举报