RMQ 和 ST 表
简介
RMQ,英文名 Range Min/Max Query,即区间最大值/最小值查询。
算法介绍
以区间最大值为例:
给定长度为
1. 暴力
这种方法不必赘述,单次查询时间复杂度为
2. 分块
可以把
这样总复杂度为
3. ST 表
ST 表,英文名 Sparse Table,也称稀疏表。它是一种简单的数据结构,主要用于求解 RMQ 问题。它应用倍增的思想,可以
使用一个二维数组
预处理:
-
- 对于
j\ge 1 的情况,按照区间长度2^j 从小到大的顺序进行枚举,有f(i,j)=\max\{f(i,j-1),f(i+2^{j-1},j-1)\} ,为了让f(i,j) 有意义,需要保证i+2^j-1\le n 。
预处理时间复杂度为
对于每一次查询
令
总时间复杂度为
4. 一些提示
- C++ 中的
2^x 表示为1 << x,注意不是2 << x、2 ^ x! - 左移运算符的优先级比加减运算符低,有些时候需要加上括号,比如预处理过程中
f(i,j)=\max\{f(i,j-1),f(i+2^{j-1},j-1)\} ,应写为f[i][j] = max(f[i][j - 1], f[i + (1 << j - 1)][j - 1])。 <cmath>中提供的log2函数较慢,可以用__lg代替,或者干脆预处理:lg(i)=\begin{cases}0& i=1\\ lg\left(\left\lfloor\frac{i}{2}\right\rfloor\right)+1& i>1\end{cases}
5. 代码实现
以下是 ST 表求解 RMQ 问题的代码。
const int N = 1e5 + 5;
int n, m;
int lg[N], p[N][20];
int main() {
read(n), read(m);
for (int i = 1; i <= n; i++)
read(p[i][0]);
for (int i = 2; i <= n; i++)
lg[i] = lg[i >> 1] + 1;
for (int j = 1; (1 << j) <= n; j++)
for (int i = 1; i + (1 << j) - 1 <= n; i++)
p[i][j] = max(p[i][j - 1], p[i + (1 << j - 1)][j - 1]);
for (int i = 1; i <= m; i++) {
int l, r;
read(l), read(r);
int tmp = lg[r - l + 1];
write(max(p[l][tmp], p[r - (1 << tmp) + 1][tmp]));
putchar('\n');
}
return 0;
}
题目练习
- P3865 【模板】ST 表
- P1198 最大数
- P1714 切蛋糕
- P1816 忠诚
- P2048 超级钢琴
- P2216 理想的正方形
- P2251 质量检测
- P2471 降雨量
- P2880 Balanced Lineup
- P8818 策略游戏