莫队算法
普通莫队
形式:给定一个长度为 \(n\) 的序列,有 \(q\) 次询问,每次询问给出 \(l,r\),问区间 \([l,r]\) 的答案。
要求:询问必须离线,且从区间 \([l,r]\) 转移到区间 \([l+1,r],[l-1,r],[l,r+1],[l,r-1]\) 的时间复杂度是 \(O(1)\) 的。
做法:关于 \(l\) 对询问分块,块长为 \(T\),每个块内对 \(r\) 从小到大排序。按照一个个块的顺序处理询问,移动左右端点从一个询问转移到另一个询问,移动时维护区间答案。
时间复杂度:块内左端点每次跳 \(O(T)\),一共有 \(q\) 个左端点,一个块右端点会移动 \(O(n)\),一共有 \(\frac{n}{T}\) 个块,不同块间转移是 \(O(n)\) 的,一共有 \(\frac{n}{T}\) 个块。总时间复杂度是 \(O(\frac{n^2}{T}+qT)\),根据基本不等式,时间复杂度 \(\le \sqrt{n^2q}=n\sqrt{q}\),块长 \(T\) 取 \(\frac{n}{\sqrt{q}}\)。时间复杂度 \(O(n\sqrt{q})\)。
奇偶优化:奇数块 \(r\) 从小到大排序,偶数块 \(r\) 从大到小排序。
带修改莫队
问题:给定一个长度为 \(n\) 的序列,有 \(q\) 次询问,每次询问有两种:
- 给出 \(l,r\),问区间 \([l,r]\) 的答案。
- 把 \(a_i\) 改成 \(x\)。
用数据结构预处理序列上每个点每个时间是什么。显然用 mutiset 是好做的。
把每次询问答案看作三维数对 \((l,r,t)\)。离线做莫队。
对 \(l\) 分块,块长为 \(T\),每个块内对 \(r\) 分块,块长为 \(T\),按 \(T\) 从小到大排序。每个小块 \(t\) 最多移动 \(q\) 次,一共 \(\frac{n^2}{T^2}\) 个小块。每个小块内一次转移 \(l,r\) 最多移动 \(T\) 次,一共 \(q\) 次转移。不同小块间转移一次 \(r\) 移动 \(T\) 次,一共 \(\frac{n^2}{T^2}\) 个小块。不同大块间转移一次 \(l\) 移动 \(T\) 次,一共 \(\frac{n}{T}\) 个大块。总时间复杂度是 \(O(\frac{n^2q}{T^2}+qT+\frac{n^2}{T}+n)=O(\frac{n^2q}{T^2}+qT+n)\)。
一般来讲,\(T\) 取 \(n^{\frac{2}{3}}\) 时复杂度最优。总复杂度为 \(O(qn^{\frac{2}{3}})\)。
回滚莫队
问题:给定一个长度为 \(n\) 的序列,有 \(q\) 次询问,每次询问给出 \(l,r\),问区间 \([l,r]\) 的最大/最小/mex 值。
例如求区间 mex 值,我们发现区间减少一个数答案是好维护的,但是增加一个数答案不好维护。
于是还是按照 \(l\) 分块,块长为 \(T\),每块的询问左端点满足在区间 \([l_{min},l_{max}]\)。
我们在每个块中按 \(r\) 从大到小排序,预处理所有区间 \([l_{min},n]\) 的答案,对于每个询问,我们只需要从 \(n\) 开始不断向左移动右端点,移完存档一下目前的答案,然后向右移动左端点,求出询问的答案。之后回到存档,算下一个答案即可。
时间复杂度分析和普通莫队一样。
标签:frac,答案,询问,算法,端点,莫队,复杂度 From: https://www.cnblogs.com/liyixin0514/p/18406306