$ST$ 表 $Sparse\ Table$
$RMQ$ ($Range\ Minimum\ /\ Maximum\ Query$) 问题:
$O(1)$ 查询区间最大 / 最小值
基本思想
基于倍增的基本思想, 定义 $f_{i, j}$ 表示从 $i$ 开始,长度为 $2^j$ 的区间中最大 / 小值
考虑状态转移,将一个区间分为两部分,维护两部分的 $max$ 或 $min$ 即可。则有:
$$ f_{i, j} = max(f_{i, j - 1},\ f_{i + 2^{j - 1}, j - 1}) $$
在具体使用时,询问 $[l, r]$ 区间,len = r - l + 1
,只需找到最大的 $k$ 使得 $2^k \geqslant len$。
$$ \Kappa = \lfloor \frac {log(len)} {log(2)} \rfloor $$
(c++ 标准库中 $log$ 函数默认以 $e$ 为底)
时间复杂度分析
$f_{i, j}$ 第一维 $n$ 个,第二维 $log_2n$ 个。
因此 $ST$ 表可以做到先以 $O(n \cdot log_2n)$ 的时间复杂度预处理,之后对于每次查询时间复杂度为 $O(1)$
例题
离线查询区间最大值 - 天才的记忆
1 | int f[N][J]; // 下标从 i 开始,长度为 2^j 的区间最大值 |
进阶应用 - 超级钢琴
注意 $ST$ 中存储值最大的下标。
1 | int n, k, l, r; |