题目:给定n个数,q个询问,每个询问包含l和r(l和 r代表区间),求区间[l,r]内的最大值。
RMQ问题:RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于一个长度N的数组,在多次询问中,每次都以O(1)的时间得到区间[a, b]
的最大值或最小值。
ST ( Sparse Table ) 算法:ST(Sparse Table)算法是一个非常有名的在线处理RMQ问题的算法,它可以在O(nlogn)时间内进行预处理,然后在O(1)时间内回答每个查询。其思想就是保存以i为起点的某段数据的最小值。
在线算法:在线算法有个预处理过程,预处理数据之后,能够更快速的处理每次请求的结果,但是会有一个相对长一点的预处理过程。
离线算法:所谓离线算法只是在来了非常多的请求之后,一次性处理多个请求,能够不依赖于预处理数据,却能一次完成多个请求的结果。
解题思路:DP思想,首先要记录每步的状态。
最初始状态:F[0, 0] = A[0]; F[1,0] = A[1]; F[2,0] = A[2]; 意思是说每单个元素的最大值都是自己(因为只有一个元素)
之后:F[i, j] = max(F[i, j-1], F[i+2^(j-1)][j-1]);
假如查询的区间是奇数个,头尾分开。
首先明确区间的长度为j - i + 1
可以取k=log2( j - i + 1)
//要能够两个F加在一起能够覆盖整个区间
RMQ(A, i, j)=max{F[i , k], F[ j - 2 ^ k + 1, k]}
代码实现:
1 #include<iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include<algorithm> 5 using namespace std; 6 #define MAXARR 1005 7 int T, n, q; 8 int l, r; 9 int maxNum[MAXARR][32]; 10 //int minNum[MAXARR][32]; 11 void RMQ(int n) { 12 for (int j = 1; j < 31; j++) { 13 for (int i = 0; i < n; i++) { 14 if (i + (1 << j) - 1 < n) { 15 maxNum[i][j] = max(maxNum[i][j - 1], maxNum[i + (1 << (j - 1))][j - 1]); 16 // minNum[i][j] = min(minNum[i][j - 1], minNum[i + (1 << (j - 1))][j - 1]); 17 } 18 } 19 } 20 } 21 int main() { 22 cin >> T; 23 while (T--) { 24 memset(maxNum, 0, sizeof(maxNum)); 25 // memset(minNum, 0, sizeof(minNum)); 26 cin >> n; 27 //初始化第一列 28 for (int i = 0; i < n; i++) { 29 cin >> maxNum[i][0]; 30 // minNum[i][0] = maxNum[i][0]; 31 } 32 RMQ(n); 33 cin >> q; 34 for (int i = 0; i < q; i++) { 35 cin >> l >> r; 36 int k = log2(r - l + 1); 37 cout << max(maxNum[l - 1][k], maxNum[r - 1 - (int)(1 << k) + 1][k]) << endl; //区间根据下标要减1 38 // cout << min(minNum[l - 1][k], minNum[r - 1 - (int)(1 << k) + 1][k]) << endl; 39 } 40 } 41 return 0; 42 }