ST表

P3865 【模板】ST 表

ST表是什么?

ST表是基于倍增的思想,可以实现&O(1)&的查询,但是不支持修改,ST表是解决区间最大值和最小值的问题的,解决这类为题的还可以用很多方法,例如线段树,单调队列,但是时间复杂度都不如ST表更优,所以说这篇博客我讲讲怎么利用ST表来解决这类问题

在这里说一下我对ST表的理解吧:

存储:

	ST表其实就是类似于区间dp的一个查询的工具
f[i][j] 表示的是从地i个开始往后的2^i-1的最大值(min/max) 
就是记录的从这个点之后的最大值,dp式子就是这个含义
就比如说 f[1][3] 就是表示的从1开始的往后2^(3-1)的位置的最大值 
存储的时候还用到了倍增的原理,就是说从小往大跳 

查询:

	 ST表的查询也就是和存储差不多吧,就是说算出
[l,r]之间最大能跳跃的长度,然后利用ST表从当前这个点往后找最大值的
特性来求出两个期间的最大值,[l,r]这个区间 的最大值max(f[l][k] , f[r-(1<<k)+1][k]);	
就是说从l开始往后找k个看看最大值( 因为k是log2(r-l+1) ),所以说不用担心越界的问题
然后就开始找r端点之前的(2^k) 为止,+1是因为没有取到右端点,要取到才行 
然后就是找到最大值然后输出就行了

记录:

	输入的时候可以直接从f[i][0]开始输入,因为ST表的地0个也就是(2^0)就是只
包含他自己的一个数,然后存储的时候也要注意是存储的 max(f[i][j-1] , f[i+(1<<(j-1))][j-1] );
这个范围,也就是说从l开始到( 2^(j-1) )这个位置,,就拿第一个赋值开讲吧,因为f[i][0]已经被赋值过了,现在要赋值的
是f[i][1],而现在的i是1,所以要保证后面的是f[2][1],所以说 (2^(j-1) )只能是1,那就只能j是i-1了 (j从1开始的情况) 

code

#include<cstdio>
#include<cmath>
#include<iostream>
const int N = 2e5+5;
const int M = 5500;
const int INF = 0x3f3f3f3f;
using namespace std;

int n,m,Ans,k,l,r;
int f[N][21];

inline int read()
{
	int 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*10+ch-48;ch=getchar();}
	return x*f;
}

inline int max(int x,int y) {return x>y?x:y;}

inline int Max(int l,int r)
{
	k = log2(r-l+1);
	return max(f[l][k] , f[r-(1<<k)+1][k]);	
}
/*
		在这里说一下我对ST表的理解吧: 
	存储:
		ST表其实就是类似于区间dp的一个查询的工具
	f[i][j] 表示的是从地i个开始往后的2^i-1的最大值(min/max) 
	就是记录的从这个点之后的最大值,dp式子就是这个含义
	就比如说 f[1][3] 就是表示的从1开始的往后2^(3-1)的位置的最大值 
	存储的时候还用到了倍增的原理,就是说从小往大跳 
	查询:
		 ST表的查询也就是和存储差不多吧,就是说算出
	[l,r]之间最大能跳跃的长度,然后利用ST表从当前这个点往后找最大值的
	特性来求出两个期间的最大值,[l,r]这个区间 的最大值max(f[l][k] , f[r-(1<<k)+1][k]);	
	就是说从l开始往后找k个看看最大值( 因为k是log2(r-l+1) ),所以说不用担心越界的问题
	然后就开始找r端点之前的(2^k) 为止,+1是因为没有取到右端点,要取到才行 
	然后就是找到最大值然后输出就行了
	记录:
		输入的时候可以直接从f[i][0]开始输入,因为ST表的地0个也就是(2^0)就是只
	包含他自己的一个数,然后存储的时候也要注意是存储的 max(f[i][j-1] , f[i+(1<<(j-1))][j-1] );
	这个范围,也就是说从l开始到( 2^(j-1) )这个位置,,就拿第一个赋值开讲吧,因为f[i][0]已经被赋值过了,现在要赋值的
	是f[i][1],而现在的i是1,所以要保证后面的是f[2][1],所以说 (2^(j-1) )只能是1,那就只能j是i-1了 (j从1开始的情况) 
*/
signed main()
{
	
	n=read() ; m=read();
	for(int i=1;i<=n;i++)
		f[i][0] = read();
	
	k = log2(n);
	
	for(int j=1;j<=k;j++)
		for(int i=1;i<=n;i++)
			f[i][j] = max(f[i][j-1] , f[i+(1<<(j-1))][j-1] );
	
	for(int i=1;i<=m;i++)
	{
		l = read() ; r = read();
		printf("%d\n",Max(l,r));
	}
		
	return 0;
}

如果有错误的地方,欢迎dalao指出

posted @ 2022-09-28 20:34  Low_key_smile  阅读(63)  评论(0编辑  收藏  举报
//music