把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

ST表学习笔记

算法简介:\(RMQ\)是一个经典的动态规划问题,是可以\(O(1)\)时间求静态区间最大值的东西,
不过需要\(O(nlog^2n)\)的预处理
算法实现:我们定义\(f_{i,j}\)表示以\(i\)为起点,向后\(2^j\)个数中最大值。两重循环,一重枚举\(i\),一重枚举\(j\)那么可以得到状态转移方程:\(f_{i,j}=max(f_{i,j-1},f_{i+2^{j-1},j-1})\)其中初始值为\(f_{i,0}=a_i\)。接下来开始查询,如果我们要查询的区间为\(x\)\(y\),那么先求出\(log^2(x-y+1)=k\),再在\(f_{x,k}\)\(f_{y-2^k+1,k}\)之间取最大值,因为两端区间会重合,但这个重合没有关系。
查询\(1-12\)的最大值,那么求出\(log^2(x-y+1)=3\),那么在\(f_{1,3}\)\(f_{5,3}\)之间去最大值,虽然有重合,但没有关系,因为最大值不会被算两次。
个人理解:作为一个\(dp\)产生的数据结构,这个思想无疑是极优的。尤其是重合不会影响答案的思想,更为巧妙,但这也局限了他的用途,毕竟不是每个问题都重合不会影响答案。
代码实现:

#include<cstdio>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
int n,a[50039],stin[50039][39],x,y,z,m,stax[50039][39],maxn,minn;
inline void read(register int &x){
	x=0;register char s=getchar();
	while(s<'0'||s>'9') s=getchar();
	while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+(s^48),s=getchar();
}
inline void print(register int x) {
	if(x>9) print(x/10);
	putchar(x%10+'0');
}
int main(){
	register int i,j,k;
	read(n);read(m);
	for(i=1;i<=n;i++)read(a[i]),stin[i][0]=a[i],stax[i][0]=a[i];
	for(i=n-1;i>=1;i--){
		for(j=1;i+(1<<j)-1<=n;j++){
			stax[i][j]=max(stax[i][j-1],stax[i+(1<<j-1)][j-1]);
			stin[i][j]=min(stin[i][j-1],stin[i+(1<<j-1)][j-1]);
		}
	}
	for(i=1;i<=m;i++){
		read(x);read(y);
		k=0;
		while(x+(1<<k+1)-1<=y) k++;
		maxn=max(stax[x][k],stax[y-(1<<k)+1][k]);
		minn=min(stin[x][k],stin[y-(1<<k)+1][k]);
		print(maxn);
		putchar('\n');
		print(minn);
		putchar('\n');
	}
	return 0;
}
posted @ 2020-03-14 21:16  275307894a  阅读(55)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end