莫队

普通莫队

莫队一般用于处理区间询问,且从当前区间 \([l,r]\) 移到相邻区间时间复杂度花费不大。考虑钦定一种顺序处理询问使得移动总次数尽可能小。

一种方法为分块,以 \(l\) 所在块编号为第一关键字,\(r\) 为第二关键字进行排序。设块长为 \(S\)。先考虑右端点移动次数,对于每一个块,其最坏移动 \(n\) 次,所以总移动次数为 \(\dfrac{n^2}{S}\);左端点在块内每一次移动至多为 \(S\) 次,总次数为 \(Sm\) 次,跨块移动为 \(S\) 次,会跨 \(\dfrac{n}{S}\) 次,总次数为 \(n\) 次,所以左端点移动次数为 \(Sm+n\) 次。

显然如果当 \(l\) 所在块编号为奇数 \(r\) 升序,为偶数 \(r\) 降序会快一点点。

块长为 \(\dfrac{n^2}{S}=Sm\),解得 \(S = \dfrac{n}{\sqrt{m}}\),据说开成 \(\dfrac{n}{\sqrt{\frac{2m}{3}}}\) 会快。

练习

考虑差分,将 \(g(l1,r1,x)\) 拆成 \(g(1,r1,x)-g(1,l1-1,x)\),重新定义 \(f(p,x)=g(1,p,x)\)。则原式为 \(\sum_{x=1}^{\infty}f(r1,x)f(r2,x)-f(l1-1,x)f(r2,x)-f(r1,x)f(l2-1,x)+f(l1-1,x)f(l2-1,x)\)

拆成四个形如 \(\sum_{x=0}^{\infty}f(l,x)f(r,x)\) 的询问后就可以莫队了。

带修莫队

由于带修,所以询问需要记录时间维度,这样才能保证移动相邻区间复杂度。

仿照普通莫队,将询问按照 \(l\) 所在块编号为第一关键字,\(r\) 所在块编号为第二关键字,\(t\) 为第三关键字。设块长为 \(S\)。先考虑 \(t\) 移动次数,对于每一对 \(l,r\) 所在块,其最多移动 \(m\) 次,总移动次数为 \(\dfrac{n^2}{S^2}m\) 次;考虑 \(r\) 移动次数,若不跨块,则每次询问其最多会在块内移动 \(S\) 次,总次数为 \(Sm\) 次,若跨块则会移动 \(S\) 次,一共会跨 \(\dfrac{n^2}{S^2}S=\dfrac{n^2}{S}\) 次,若 \(l\) 跨块则会移动 \(n\) 次,一共跨 \(\dfrac{n}{S}\) 次,次数为 \(\dfrac{n^2}{S}\) 次,所以总次数为 \(\dfrac{n^2}{S}+Sm\);考虑 \(l\) 移动次数,若不跨块,同右端点不跨块 \(Sm\) 次,若跨块会跨 \(\dfrac{n}{S}\) 次,总次数为 \(Sm+n\) 次。

则块长为 \(\dfrac{n^2m}{S^2} = Sm\),解得 \(S= \sqrt[3]{n^2}\)

回滚莫队

也称不删除莫队。

先介绍这道题的一种不使用回滚莫队的方法。先离散化,维护 \(n\) 个 deque,使用 \(set\) 维护每种数最大间隔,插入删除显然可以做到 \(O(\log n)\),查询为 \(O(1)\)。考虑平衡一下,使用值域分块可以做到 \(O(1)\) 插入删除,查询 \(O(\sqrt{n})\)。如果预处理每个颜色前驱后继就不需要维护 deque。

接下来为回滚莫队,由于该题插入简单删除困难,所以考虑尽量不删除。首先对于 \(L,R\) 在同一块内的询问,直接暴力计算。对于所有 \(L\) 在同一块内的询问,考虑维护双指针 \(l=r\),值均为块右端点。由于这些询问的 \(R\) 升序,所以就可以让 \(r\) 向后移动,每次找到一个询问的时候,就将 \(l\) 向左移动到询问的 \(L\) 位置,这部分使用临时数组计算,计算完答案后将 \(l\) 移回块右端点并撤销临时数组。处理完当前块后到下一个块的时候重置 \(l,r\) 指针即可。

image image image

类似这样。

模板1

发现也是插入简单删除困难,直接不删除莫队即可。

练习

显然有一个 \(O(n\sqrt{n\log n})\) 的做法,莫队加使用 set 维护前驱后继。

考虑优化掉 set 所带来的 \(\log\) 复杂度。发现链表可以做到 \(O(1)\) 删除,所以仿照不删除莫队,可以使用不插入的回滚莫队解决。

具体地,对于每一个块,将 \(l\) 初始化为块左端点,\(r\) 初始化为 \(n\),然后将 \(r\) 向左移,遇到询问的时候将 \(l\) 向右移即可。

posted @ 2026-07-16 13:15  ask_silently  阅读(5)  评论(0)    收藏  举报