ST 表,也称稀疏表,是用于解决可重复贡献问题的数据结构。可重复贡献问题,可理解为重叠并不改变结果。与区间和不同,如果两个区间有重叠,元素就会被重复使用,从而使答案错误。
区间最大/最小值,区间按位与/或/异或,区间 GCD 等都是可重复贡献问题,可以用 ST 表解决。
特别地,我们称区间最大/最小值的问题为 RMQ (Range Maximum/Minimum Query) 问题。
ST 表主要基于**倍增(Binary Lifting)**的思想,可以做到 $\Theta(n\log n)$ 预处理,$\Theta(1)$ 回答每个询问,但是不支持修改。
设 $f(i,j)$ 表示 $[i,i+2^j-1]$ 上的最大值,有 $f(i,0)=a_i$(只有一个数)
由于区间大小正好是 $2^j$,则正好可以将区间切为大小为 $2^{j-1}$ 的左右两半,表达式分别为 $f(i,j-1)$ 和 $f(i+2^{j-1},j-1)$,只要对这两个子区间取最大值,原区间最大值也就得到了。

据此,利用递推求出 $f(i,j)$,列出转移方程:
$$ f(i,j)=\max(f(i,j-1),f(i+2^{j-1},j-1)) $$
const int N = 1e5;
int Log2[N];
void init() {
for (int i = 0; i <= n; i++) f[i][0] = a[i];
for (int j = 1; (1 << j) <= n; j++) { // 保证区间长度 2^j 小于 n
for (int i = 1; i + (1 << j) - 1 <= n; i++) { // 区间末尾是 i+2^j-1,保证不越界
f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
// 注意 j 要在外面,i 在里面
}
}
// 对可能的 log_2(x) 值的预处理,之后用到
Log2[1] = 0, Log2[2] = 1;
for (int i = 3; i <= n; i++) {
Log2[i] = Log2[i >> 1] + 1;
}
}