数据结构 _ ST表 | RMQ 问题
基本概念
RMQ问题
RMQ英文是Range Maximum(Minimum) Query,
翻译就是区间求最值
的意思。
ST表(Sparse Table,稀疏表)
是一种简单的数据结构,基于 倍增 思想,主要用来解决RMQ问题。
不支持修改操作
实现
复杂度:
预处理:\(O(n \log n)\)
每次查询:\(O(1)\)
预处理
预处理复杂度: \(O(n \log n)\)
状态表示:
\(f[i][j]\)表示以 i 为左端点,长度为\(2^j\)的区间最大值.
状态转移 :
当j为0
此时区间长度为1,区间最值就是其本身对应的数组中的数。
代码就是:f[i][j]=a[i]
当j不为0
此时就将区间\([i,j]\)平均分成两部分:
- 左边:\([i,i+2^{j−1}−1]\)
- 右边:\([i+2^{j−1},j]\)
很明显\(f[i][j]\)就是两部分取最大值。
代码就是: f[i][j]=max(f[i][j-1],f[i+(1<<j-1)][j-1])
代码:
void get_st(){
for(int j=0;(1<<j)<=n;j++){
for(int i=1;i+(1<<j)-1<=n; i++){
if(j==0) f[i][j]=w[i];
else
f[i][j]=max(f[i][j-1],f[i+(1<<j-1)][j-1]);
}
}
}
查询
每次查询复杂度: \(O(1)\)
对于每个询问的[L,R]我们把它分成两部分,\(f [ l , l + 2 ^s − 1 ]\) 和 \(f [ r − 2^s + 1 , r ]\) 。其中\(s=log_2(r-l+1)\)。
取两个区间的最大值即可
如图
代码:
int query(int l,int r){
int len=r-l+1;
int k=log(len)/log(2);
return max(f[l][k],f[r-(1<<k)+1][k]);
}
模板代码
int f[N][20];
int n;
int w[N];
void get_st(){
for(int j=0;(1<<j)<=n;j++){
for(int i=1;i+(1<<j)-1<=n; i++){
if(j==0) f[i][j]=w[i];
else
f[i][j]=max(f[i][j-1],f[i+(1<<j-1)][j-1]);
}
}
}
int query(int l,int r){
int len=r-l+1;
int k=log(len)/log(2);
return max(f[l][k],f[r-(1<<k)+1][k]);
}
习题
1273. 天才的记忆
模板题
代码:
#include <iostream>
#include <cstring>
#include <vector>
#include <bits/stdc++.h>
#define endl '\n'
//#pragma GCC optimize(3)
#define int long long
#define pii pair<int, int>
using namespace std;
const int N = 2e5+10;
int min(int a, int b)
{
if (a > b)
return b;
else
return a;
}
int max(int a,int b){
if(a>b) return a;
else return b;
}
int f[N][20];
int n;
int w[N];
void get_st(){
for(int j=0;(1<<j)<=n;j++){
for(int i=1;i+(1<<j)-1<=n; i++){
if(j==0) f[i][j]=w[i];
else
f[i][j]=max(f[i][j-1],f[i+(1<<j-1)][j-1]);
}
}
}
int query(int l,int r){
int len=r-l+1;
int k=log(len)/log(2);
return max(f[l][k],f[r-(1<<k)+1][k]);
}
void solve(){
cin>>n;
for(int i=1;i<=n;i++) cin>>w[i];
get_st();
// for(int i=1;i<=n;i++)
// for(int j=0;j<=2;j++)
// cout<< f[i][0]<<" ";
// cout<<endl;
int m;cin>>m;
while(m--){
int l,r;cin>>l>>r;
cout<<query(l,r)<<endl;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
solve();
return 0;
}