ST表实现RMQ
什么是RMQ?
RMQ 是英文 Range Maximum/Minimum Query 的缩写,表示区间最大(最小)值。
什么是ST表?
ST 表是用于解决 可重复贡献问题 的数据结构。
除 RMQ 以外,还有其它的“可重复贡献问题”。例如“区间按位和”、“区间按位或”、“区间 GCD”,ST 表都能高效地解决
(都是可以重复贡献问题)
对于更好的解释:OI-wiki_ST表
用ST表实现RMQ问题?
时间复杂度:(O(nlog n)-O(1)),
空间复杂度:(O(nlog n))
『题目传送门』:洛谷P3865 ST表
题目大意:给定 (n) 个数,有 (m) 个询问,对于每个询问,你需要回答区间 ([l,r]) 中的最大值。
关键思想:
令一个数组(f(i,j))表示区间([i,i+2^{j}-1])的最大值,那么显然就有(f(i,0) = a_i)。
预处理数组关键递推式:
(f(i,j) =max( f(i,j-1),f(i+2^{j-1},j-1)))
查询操作:
查询:对于每个询问 ([l,r]) ,把它分成两部分: (f[l,l+2^s-1]) 与 (f[r-2^s+1,r]) 。其中 (s=leftlfloorlog_2(r-l+1)
ight
floor) 。
代码实现
//#define judge
// Author: oceanlvr
#include <bits/stdc++.h>
using namespace std;
static int faster_iostream = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(NULL);
return 0;
}();
const int logn = 21;
const int maxn = 1e6 + 10;
//令go(i,j)表示区间[i,i+2^j-1]的最大值。
int go[maxn][logn], Logn[maxn];
void pre() {
Logn[1] = 0;
Logn[2] = 1;
for (int i = 3; i < maxn; i++) Logn[i] = Logn[i / 2] + 1;
}
int n, m;
int l, r;
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> go[i][0];
pre(); //预处理Log
for (int j = 1; j <= logn; j++) {
for (int i = 1; i + (1 << j) - 1 <= n; i++) {
/*
预处理区间
把区间分为[i,j]分为[i,i+2^{j-1}-1] [i+2^{j-1},i+2^{j}-1]
1.即从i开始,向后跳2^{j-1}个点,右区间到i+2^{j-1}-1
2.即从i+2^{j-1}开始,向后跳2^{j-1}个点,右区间到i+2^{j}-1
*/
go[i][j] = max(go[i][j - 1], go[i + (1 << (j - 1))][j - 1]);
}
}
for (int i = 1; i <= m; i++) {
int x, y;
cin >> x >> y;
int s = Logn[y - x + 1];
/*
go(i,j)表示区间[i,i+2^j-1]的最大值。
那么对于一对查询x,y,求[x,y]区间内的最大值
对于区间长度(y - x + 1):
有 [log(y - x + 1)]_{floor} = s
[x][s]和[y - (1 << s) + 1][s]
*/
cout << max(go[x][s], go[y - (1 << s) + 1][s]) << endl;
}
return 0;
}