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表

//>>>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问题

相关资料

一维板子

  1. https://oi-wiki.org/ds/sparse-table/
  2. https://zhuanlan.zhihu.com/p/123360481

二维st表

https://blog.csdn.net/VictoryCzt/article/details/83684082

posted on 2023-07-03 09:28  Qiansui  阅读(18)  评论(0编辑  收藏  举报