莫队

莫队是谁?


1. 普通莫队

用来解决区间询问的问题:如果已知 \([l,r]\) 的答案,可以快速求得 \([l-1,r],[l+1,r],[l,r-1],[l,r+1]\) 的答案,就可以用莫队处理

如这道例题

如果我们在线做,就会要 \(O(nm)\) 的时间

那我们考虑离线,将询问按 \(l\) 为第一关键字,\(r\) 为第二关键字排序

这在随机数据中可以跑得飞快,但对于一些构造数据就不行了,例如:\((1,1),(2,n),(3,2),(4,n)...\) 这样会将你卡回 \(O(n^2)\)

这时候有人就想到一个方法:利用分块来排序

我们按 \(l\) 将询问分为 \(sqrt(m)\) 组,按照组号为第一关键字,组内按 \(r\) 为第二关键字排序

这样我们保证复杂度是 \(O(n \sqrt{n})\)

其实还有一个卡常技巧:我们可以用奇偶块排序,即当组号为偶数时,组内按 \(r\) 从小到大排;为奇数时,按 \(r\) 从大到小排,这样在挪动指针时可以充分利用

代码

练习题:

P4462 [CQOI2018]异或序列

P5268 [SNOI2017]一个简单的询问

P4689 [Ynoi2016] 这是我自己的发明


2. 带修莫队

根据我们上面的分析,可以发现普通莫队是不支持修改的

但题目硬要修改怎么办

我们可以考虑将莫队的移动变成三维的:\((l,r,t)\)\([l,r]\) 与原来的意义一样(计算区间),\(t\) 表示执行了前 \(t\) 个修改

对于 \(t\) 的移动,我们可以分两类讨论:

  • 若修改位置 \(x\) 不在 \([l,r]\) 内,则操作忽略

  • 否则,相当于删除一个元素,再增加一个元素

我们再来研究该怎么排序(默认比较后是从小到大的):

  • 首先,如果左端点所在的块不相同,则比较左端点

  • 否则,再比较右端点所在的块:如果不相同,则比较右端点,反正最后比较 \(t\)

可以证明,当块的大小为 \(n/q^{\frac{1}{3}}\) 时是最优的(噢忘了提,普通莫队的最优的块的大小是 \(n/\sqrt{q}\),但由于 \(n,q\) 一般是同阶的,所以也会默认为 \(\sqrt{n}\)),此时复杂度为 \(O(nq^{\frac{2}{3}})\)

例题

代码

练习题:

CF940F Machine Learning


3. 回滚莫队

这是用来处理一类加入容易删除难的问题,即 \([l,r]\) 能快速转移到 \([l-1,r],[l,r+1]\),但 \([l+1,r],[l,r-1]\) 较难

这些问题通常是答案要求取最大值或最小值,如果要删除,就要记录一堆信息

既然删除难,那我们就别删除嘛

于是就有人想出了回滚这操作,他的实现是这样的:

  • 排序时,按照左端点所在的块为第一关键字从小到大排序,以右端点为第二关键字从小到大排序

  • 我们考虑每次处理一个块内的询问:莫队区间的左端点 \(nl\)\(R[T]+1\),右端点 \(nr\)\(R[T]\)(其中 \(T\) 表示块,\(R[T]\) 表示块的右边界)

  • 然后我们分类讨论:对于左右点在同一个块的询问,我们直接暴力求出答案,\(nr\) 不做移动

  • 对于左右点不在同一个块的询问,我们先移动 \(nr\) 到询问的右点,然后再将 \(nl\) 移到询问的左点,求出答案后,注意,我们要将 \(nl\) 滚回 \(R[T]+1\) 处,但 \(nr\) 不用撤回(因为块内的所以询问的右点是递增的,不会有删除的操作)

  • 回滚的时候将桶、临时答案都恢复 \(nl\) 移动前即可

可以证明,回滚莫队的时间复杂度依然是 \(O(n\sqrt{m})\) 的,但常数略大;注意每次处理完一个块后要将桶和临时答案都清空

回滚莫队也可以处理删除容易加入难的题目,只需要以下地方稍作改动:

  • 排序时,依旧按照左端点所在的块为第一关键字从小到大排序,但以右端点为第二关键字从大到小排序

  • 莫队区间初始化时,左端点 \(nl\)\(L[T]\) (块的左边界),右端点 \(nr\)\(n\)

  • 回滚时 \(nl\) 是滚回 \(L[T]\)

例题

代码

分组最好从 \(1\) 开始,能省去不少麻烦RE

练习题:

AT1219 歴史の研究


4. 树上莫队

例题

题意:求树链的颜色个数

由于莫队通常是处理区间问题,因此我们就要考虑将树拍成一个序列

我们考虑记录一个树的欧拉序,记 \(dfn[u]\) 为进入结点 \(u\) 时的序列位置, \(out[u]\) 为退出结点 \(u\) 时的序列位置

当询问一条树链 \((u,v)\) 时(假设 \(dfn[u]<dfn[v]\)),对应到序列上就是:区间 \([out[u],dfn[v]]\)只出现一次的点,加上 \(LCA(u,v)\)

真的是太妙了

而我们在做莫队的时候,我们就当第二次加入是删除第二次删除是加入即可

代码

练习题:

P4074 [WC2013] 糖果公园(树上带修莫队)

(如果出现 \(LCA(x,y)=x\) 的情况,询问的区间会出现 \(l>r\) 的情况,这其实并不影响答案的正确性;但如果实在要统一为 \(l\le r\),那么我们可以询问 \([dfn[x], dfn[y]]\),然后答案不要再计入 \(LCA\)


5. 二次离线莫队

当加入或删除中有一方较困难实现时,我们可以利用回滚莫队做到
\(O(n\sqrt n)\);但某些毒瘤的出题人 (比如lxl) 将每次修
改操作的复杂度升到 \(O(\log n)\) 甚至以上时,莫队似乎就不太
可行了

但道高一尺魔高一丈,于是就有人发明了一种新的科技:二次离线
莫队。它可以将原本 \(O(n\sqrt n\ k)\) 的时间降为 \(O(n\sqrt n+nk)\)\(k\) 为一次修改的复杂度)

我们先假设 \(x\) 对区间 \([l,r]\) 的贡献为 \(f(x,l,r)\)

二次离线莫队需要一个比较重要的条件:即 \(f(x,l,r)=f(x,1,r)- f(x,1,l-1)\),即可差分性

显然,每次左指针移动时会产生的修改
\(f(nl,nl+1,nr)=f(nl,1,nr)-f(nl,1,nl)\),每次右指针移动时会
产生的修改\(f(nr,nl,nr-1)=f(nr,1,nr-1)-f(nr,1,nl-1)\)

显然\(f(x,1,x), f(x,1,x-1)\)我们可以用 \(O(n)\) 的时间预处理
出来,而且通常情况下自己对自己不会有贡献,因此有
\(f(x,1,x)=f(x,1,x-1)\)

现在考虑 \(f(nl,1,nr), f(nr,1,nl-1)\) 该如何求出

我们已经将问题转化为 \([1,pos]\) 这样的区间问题,那么我们就考虑用扫描线的方法

考虑将莫队的每次移动都记录下来,如 \(x,1,y\),我们就将 \(x\) 记录到 \(y\) 的桶中,当扫描线扫到 \(y\) 时,用 \(O(1)\) 的时间得出答案

但如果要记录 \(n\sqrt n\) 个询问的话空间复杂度有些吃不消,而我们观察到对于每个询问,由于它的移动是连续的,而且一个指针移动时,另一个指针是不动的(也就是存入的桶相同),那我们就可以存入指针移动的左右端点

而这里也有个卡常小技巧,就是预处理 \(f(x,1,x)\) 时我们可以表示成前缀和的形式,在计入答案时就直接算 \(pre[R]-pre[L-1]\)\([L,R]\) 就是指针移动的区间)

最后答案需要继承排序后的上一个询问的答案,因为我们每次记录的是莫队指针移动后贡献发生的变化

例题

对于本题,我们先预处理出二进制有 \(k\)\(1\) 的所有数,利用 \(a\oplus b=c \Leftrightarrow a\oplus c=b\),处理出答案

这里注意一个点:莫队的指针要及时更新,否则会影响另一个指针存放的桶的位置! (我不会告诉你我因为这里调试了一个下午的)

代码

练习题:

P5047 [Ynoi2019 模拟赛] Yuno loves sqrt technology II

P5501 [LnOI2019]来者不拒,去者不追

(配合值域分块 \(O(\sqrt n)\) 插入,\(O(1)\) 查询)


6. bitset 优化莫队

这是一个经典的套路,难以概括,选择一道例题进行介绍

答案显然为 \((r_1-l_1+1)+(r_2-l_2+1)+(r_3-l_3+1)-3\times len\),其中 \(len\) 为三个区间的公共颜色数

如果用 bitset 记录颜色,我们只能求出三个区间公共颜色的种数

实际上,我们可以将序列离散化,使一个数的新值为:比它小的数的个数+1

这样,在莫队加入一个数 \(a\) 时,我们就将 bitset\(id[a]+cnt[a]-1\) 的位置标记为 \(1\)\(id\) 就是离散化后的值, \(cnt\) 是指数值出现的次数

这样,我们在取三个区间的交集时,我们就可以直接通过数出 bitset\(1\) 的个数,求得公共颜色的个数

注意到这道题:开一个大小为 \(10^5\times 10^5\)bitset 显然还是比较吃力的,我们就考虑将询问分成三个部分,分开进行莫队

代码

练习题:

P3674 小清新人渣的本愿

P5355 [Ynoi2017] 由乃的玉米田

P5313 [Ynoi2011] WBLT


精通了莫队,你就学会了卡常和水分

posted @ 2022-04-13 20:55  zuytong  阅读(94)  评论(0编辑  收藏  举报