$RMQ$又叫$st$表,本质上是一种倍增动态规划,用来求解区间最大值。
通过预处理,快速查询区间最大值。
定义$f[i][j]$表示从$i$开始,区间长度是$2^j$的区间中的最大值是多少。
和$tarjan$的想法一样,以区间的中间点为分界点,可以容易得到递推式$f[i][j] = max(f[i][j - 1] + f[i + 2^{j-1}][j - 1])$。
状态数量第一维是$n$,第二维是$logn$,所以该算法的时间复杂度是$O(nlogn)$的。
acwing 1273.天才的记忆
https://www.acwing.com/problem/content/description/1275/
1 #include <iostream> 2 #include <algorithm> 3 #include <cstring> 4 #include <cmath> 5 6 using namespace std; 7 8 const int N = 2e5+10, M = 18; 9 10 int a[N]; 11 int f[N][M]; 12 int n, m; 13 14 void init() 15 { 16 for(int j = 0 ; j < M ; j ++) 17 for(int i = 1 ; i + (1 << j) - 1 <= n ; i ++) 18 if(!j)f[i][j] = a[i]; 19 else f[i][j] = max(f[i][j - 1], f[i + (1 << j - 1)][j - 1]); 20 } 21 22 int query(int l, int r) 23 { 24 int len = r - l + 1; 25 int k = log(len) / log(2); 26 27 return max(f[l][k], f[r - (1 << k) + 1][k]); 28 } 29 30 int main(){ 31 cin >> n; 32 for(int i = 1 ; i <= n ; i ++)cin >> a[i]; 33 cin >> m; 34 init(); 35 36 while(m --) 37 { 38 int l, r; 39 cin >> l >> r; 40 cout << query(l, r) << endl; 41 } 42 return 0; 43 }