[算法模板]ST表

[算法模板]ST表

ST表和线段树一样,都能解决RMQ问题(范围最值查询-Range Minimum Query)。

我们开一个数组数组(f[maxn][maxnlog_2])来储存数据。

定义(f[i][j])代表从(i)开始的(2^{j})位这个区间的最大值。

初始化

因为(f[i][0]=a[i]),所以有:

[f[i][j]=max(f[i][j-1],f[i+2^{j-1}][j-1]) ]

通过这个转移方程即可构造出(f)

查询

查询区间([l,r])的最大值。

(k=log _2(l-r+1)),那么很容易想明白:

[ans=max(f[l][k],f[r-2^k+1][2^k]) ]

注意定义(f)的时候,(i)是包含在(2^k)里面的,所以可能会+1/-1。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define maxn (int)(1e5+1000)
int a[maxn],f[maxn][21],n,m;
void init(){
	for(int i=1;i<=n;i++)f[i][0]=a[i];
	for(int j=1;j<=20;j++){
		for(int i=1;i-1+(1<<(j-1))<=n;i++){
			f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
		}
	}
	return;
}
int query(int l,int r){
	int k=log2(r-l+1);
	return max(f[l][k],f[r-(1<<(k))+1][k]);
}
int main(){
	//freopen("in","r",stdin);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	init();
	for(int i=1;i<=m;i++){
		int l,r;scanf("%d%d",&l,&r);
		printf("%d
",query(l,r));
	}
	return 0;
}
原文地址:https://www.cnblogs.com/GavinZheng/p/10831563.html