学了这么久还不会 $ST$ 表,药丸
$ST$ 表是一种用来求解 $RMQ$ 问题的 $O(log \ n)$ 算法,相比于线段树求解 $RMQ$ 问题要更简洁,码量小,常数也更小,是一种基于倍增思想的算法。
我们定义数组 $f[i][j]$ 表示第 $i$ 个元素到 第 $i + 2^j$ 个元素区间范围内极值,那么可以根据倍增思想轻松写出转移方程。
$$f[i][j] = f[i][j-1] + f[i + (1 << (j-1)) + 1][j-1]$$
查询请求也非常简单,我们将区间 $[l, r]$ 拆为长度为 $log_2(r-l+1)$ 的两部分,最后合并答案即可。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int MAXN = 100000 + 10;
const int MAXK = 17 + 10;
int f[MAXN][MAXK];
int data[MAXN];
int n;
inline void ST_init(){
for(register int i=1; i<=n; i++)
f[i][0] = data[i];
int maxj = log(n) / log(2) + 1;
for(register int j=1; j<maxj; j++){
for(register int i=1; i<= n - (1 << j) + 1; i++)
f[i][j] = max(f[i][j-1], f[i+ (1 << (j - 1))][j-1]);
}
}
inline int query(int l, int r){
int j = log(r-l+1) / log(2);
return max(f[l][j], f[r - (1 << j) + 1][j]);
}