st表
st表
ST 表是用于解决 可重复贡献问题 的数据结构
目前st表给我的感觉就是,我可以通过处理,实现O(1)的时间找任意静态区间的最小值,那么题目问到相关的问题的时候,我可以判断其是不是需要寻找静态区间的最值,从而决定是否使用st表来优化我的操作。
下面以区间最大值为例:
由于题目的特殊性,我们可以使用一个特殊的函数\(f[i][j]\),利用其来代表区间\([i,i+2^j-1]\)的最大值。之后我们可以得到,对于任意的i和j,总有\(f[i][j]=max(f[i][j-1],f[i+2^{j-1}][j-1]\),通过此方程,我们可以求得任意区间的最大值。
对于区间\([l,r]\)的查询操作,我们希望直接输出\(f[l][x],(l+2^x-1=r)\)
故\(x=log_2(r-l+1)\)
但是不是每个区间\([l,r]\)都能满足x为整数,而我们的f是整数划分的,所以基于此,我们可以取整x,并且重新划分区间\([l,r]\)为区间\([l,l+2^{[x]}-1]\)和区间\([r-2^x+1,r]\),为了消除取整之后的影响,则\(MAX[l,r]=max(f[l][x],f[r-2^x+1][x])\)
板子几步走:
首先输入数据
预处理logn函数
处理f函数
询问
例题
一维st表
-
静态区间最小值洛谷 P1816 忠诚
//>>>Qiansui
#include<map>
#include<set>
#include<list>
#include<stack>
#include<cmath>
#include<queue>
#include<deque>
#include<cstdio>
#include<string>
#include<vector>
#include<utility>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<functional>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x,y,sizeof(x))
#define debug(x) cout << #x << " = " << x << endl
#define debug2(x,y) cout << #x << " = " << x << " " << #y << " = "<< y << endl
//#define int long long
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-48;ch=getchar();}
return x*f;
}
using namespace std;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<ull,ull> pull;
typedef pair<double,double> pdd;
/*
st表
*/
const int maxm=2e6+5,maxn=1e5+5,inf=0x3f3f3f3f,mod=998244353;
int n,m,f[maxn][21],logn[maxn];
void pre(){//处理logn函数,便于计算$log(r-l+1)/log(2)$
logn[1]=0;
logn[2]=1;
for(int i=3;i<=n;++i){
logn[i]=logn[i/2]+1;
}
return ;
}
void solve(){
n=read();m=read();
for(int i=1;i<=n;++i){
f[i][0]=read();
}
pre();
for(int j=1;j<=21;++j){
for(int i=1;i+(1<<j)-1<=n;++i){
f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
}
int l,r;
while(m--){
l=read();r=read();
int lg=logn[r-l+1];
int ans=max(f[l][lg],f[r-(1<<lg)+1][lg]);
cout<<ans<<'\n';
}
return ;
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int _=1;
// cin>>_;
while(_--){
solve();
}
return 0;
}
二维st表
百炼OJ 2019 Cornfields
二维与一维类似,多一个维度而已
//>>>Qiansui
#include<map>
#include<set>
#include<list>
#include<stack>
#include<cmath>
#include<queue>
#include<deque>
#include<cstdio>
#include<string>
#include<vector>
#include<utility>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<functional>
#define ull unsigned long long
#define mem(x,y) memset(x,y,sizeof(x))
#define debug(x) cout << #x << " = " << x << endl
#define debug2(x,y) cout << #x << " = " << x << " " << #y << " = "<< y << endl
//#define int long long
using namespace std;
typedef pair<int,int> pii;
typedef pair<ull,ull> pull;
typedef pair<double,double> pdd;
/*
二维RMQ问题
*/
const int maxm=250+5,inf=0x3f3f3f3f,mod=998244353,Logn=11;
int n,b,k,dpmax[maxm][maxm][Logn][Logn],dpmin[maxm][maxm][Logn][Logn];
int logn[maxm];
void pre(){
logn[1]=0;logn[2]=1;
for(int i=3;i<=n;++i) logn[i]=logn[i/2]+1;
int x,y;
x=y=logn[n]+1;
for(int l=0;l<x;++l){
for(int r=0;r<y;++r){
if(l+r)
for(int i=1;i+(1<<l)-1<=n;++i){
for(int j=1;j+(1<<r)-1<=n;++j){
if(l){
dpmax[i][j][l][r]=max(dpmax[i][j][l-1][r],dpmax[i+(1<<(l-1))][j][l-1][r]);
dpmin[i][j][l][r]=min(dpmin[i][j][l-1][r],dpmin[i+(1<<(l-1))][j][l-1][r]);
}else{
dpmax[i][j][l][r]=max(dpmax[i][j][l][r-1],dpmax[i][j+(1<<(r-1))][l][r-1]);
dpmin[i][j][l][r]=min(dpmin[i][j][l][r-1],dpmin[i][j+(1<<(r-1))][l][r-1]);
}
}
}
}
}
return ;
}
int query(int l,int r){
int x,y,mm,nn,ll,rr;
x=y=logn[b];
ll=l+b-1-(1<<x)+1;
rr=r+b-1-(1<<y)+1;
mm=max(max(dpmax[l][r][x][y],dpmax[ll][r][x][y]),max(dpmax[l][rr][x][y],dpmax[ll][rr][x][y]));
nn=min(min(dpmin[l][r][x][y],dpmin[ll][r][x][y]),min(dpmin[l][rr][x][y],dpmin[ll][rr][x][y]));
return mm-nn;
}
void solve(){
cin>>n>>b>>k;
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
cin>>dpmax[i][j][0][0];
dpmin[i][j][0][0]=dpmax[i][j][0][0];
}
}
pre();
int l,r,ans;
for(int i=0;i<k;++i){
cin>>l>>r;
ans=query(l,r);
cout<<ans<<'\n';
}
return ;
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int _=1;
// cin>>_;
while(_--){
solve();
}
return 0;
}
2023ACM暑假训练day 7-RMQ问题
相关资料
一维板子
二维st表
本文来自博客园,作者:Qiansui,转载请注明原文链接:https://www.cnblogs.com/Qiansui/p/17521932.html