线性RMQ——四毛子算法
$\text{RMQ}$
$\text{RMQ(Range Minimum/Maximum Query)}$,区间最值查询问题。
形式化来说,给出长为 $n$ 的数组以及 $m$ 组形如 $l,r$ 的询问,对于每组询问,需要回答区间 $[l,r]$ 里的最值。
有关四毛子算法
四毛子算法,一种分块的应用,也是一种能实现 $O(n)-O(1)$ 进行区间 $\text{RMQ}$ 的算法。
相比之下,它会比常见的其他算法时间要优,诸如什么 $O(n\log n)-O(1)$ 的 $\text{ST}$ 表,$O(n),O(\log n)$ 的线段树。但是常数相比 $\text{ST}$ 表会逊色一些。
做法
考虑设定阈值 $B=\log n$。把序列分成 $\frac{n}{B}$ 个块,每个块的长度为 $B$。
之后我们分两种区间考虑(询问的左右端点分别记为 $l,r$):
-
询问的左右端点不在同一个块中
整块:利用 $\text{RMQ}$ 预处理出第 $l\to r$ 个块的最小值,时间复杂度 $O(\frac{n}{B} \log n)$。
散块:维护块内前缀最小值与后缀最小值。
-
询问的左右端点在同一个块中
每个块中维护一个单调栈,遍历到一个点时记录当前单调栈中节点的集合(由于块长为 $\log n$,所以一个 $\text{int}$ 就能存下)。时间复杂度 $O(n)$。
查询对于 $r$ 的二进制集合状态,某位后面的第一个 $1$ 在哪一位即可(可以使用 `
__builtin_clz()`
)。