Loading

【笔记】莫队

来自\(\texttt{SharpnessV}\)省选复习计划中的莫队


莫队算法是对一类暴力的优化。

如果我们能够在 \(\rm O(1)\) 的时间内由 \([l,r]\) 的答案推出 \([l\pm1,r\pm 1]\) 的答案,就可以考虑使用莫队。

我们对询问排序,首先将序列分为\(\sqrt{N}\)块,左端点在不同块的按左端点大小排序,否则按右端点大小排序。

排序后,我们每次暴力移动左右指针,从上次询问答案推出当前答案。

复杂度分析:对于左端点在同一块的所有询问,每个询问左端点移动不超过 \(\sqrt{N}\),右端点有序,所以总移动不超过 \(N\),总的移动次数就是 \(\rm N\sqrt N\)。(假定序列长度和询问次数同级,下同)

由于一次移动是\(\rm O(1)\)的,所以时间复杂度为 \(\rm O(N\sqrt{N})\)

一个比较有用的常数优化就是奇偶块排序,左端点在第奇数块的询问右端点递增排序,否则右端点递减排序,这一般能优化一倍以上的常数。

如果莫队常数足够优秀的话,在没有特意构造数据的情况下甚至可以看成一个\(\log\)的。


例题1

模板题,开一个桶记录每个颜色出现了多少次。

代码

一下是本质相同的几道题。

例题2

例题3


例题4

莫队算法甚至可以支持修改。

一般莫队,都是维护两个维度表示区间左右端点,我们可以再加入第三个维度,表示当前询问之前有多少次修改。

然后我们将左右端点分块排序,先移动左右端点,再移动时间指针。

如果我们将块大小取到\(\sqrt[3]{NT}\)复杂度最优,其中\(T\)为修改次数,不难证明最劣时间复杂度为\(\rm O(N^{\frac{3}{5}})\)

代码

例题5

本质相同。


莫队甚至可以维护树上问题。

一般莫队,都是解决序列问题,我们可以试着将树上问题转换为序列问题。

如果是子树询问,我们可以通过 DFS序 转换为序列问题。

如果是路径询问,我们可以通过 欧拉序 转换为序列问题。

例题6

如果是序列上数颜色则是莫队模板,路径上数颜色我们通过欧拉序转换为序列问题再进行求解。

代码

我们还可以将树上莫队和带修莫队结合得到树上带修莫队,时间复杂度仍然是\(\rm O(N^{\frac{5}{3}})\)

例题7

糖果公园掉紫了,爷青结。


莫队甚至可以不用支持删除操作。

一般莫队,都需要支持\(\rm O(1)\)增/减操作,我们可以试着只用增操作完成。

对于左端点在同一块的询问,右指针单调递增。但是左指针会左右横跳。

可是左端点每次不会跳超过\(\sqrt{N}\),所以我们先将左指针固定到当前块的右端点,对于每个询问,暴力更新左指针。回答完询问后需要将左指针复原到当前块的右端点。

这样做时间复杂度仍然是\(\rm O(N\sqrt{N})\)

例题8

代码


莫队甚至可以和数据结构结合。

一般莫队,都需要支持\(\rm O(1)\)移动端点,而数据结构都是带\(\log\)的,我们可以试着使用一些特殊的数据结构。

例题9

我们需要支持单点,和查询区间和。目前最优的方式是树状数组做到\(\rm O(N\log N)\)

但是对于莫队来说,单点操作多达\(N\sqrt{N}\)次,而询问操作只有\(\rm O(N)\)次,所以我们可以使用值域分块完成,因为值域分块支持\(\rm O(1)\)修改\(\rm O(\sqrt{N})\)查询。

代码

例题10

我们还可以将莫队与bitset结合,因为bitset支持\(\rm O(1)\)修改,和\(\rm O(\dfrac{N}{64})\)查询,这样总的时间复杂度为\(\rm O(N\sqrt{N}+\dfrac{N^2}{64})\)

代码


莫队甚至可以解决序列以外的问题。

一般莫队,不论怎么变换都离不开区间查询的本质,但我们还可以灵活运用它。

例题11

我们可以通过容斥将问题转换为区间\([1,l]\)和区间\([1,r]\)中颜色相同的点对数。

这不再是我们所熟知的区间\([l,r]\),但是我们仍然把它看作广义区间,并开桶维护。时间复杂度\(\rm O(N\sqrt{N})\)

代码

posted @ 2021-12-16 22:36  7KByte  阅读(134)  评论(0编辑  收藏  举报