ST表学习笔记

时间:2023-11-25 15:07:02

ST表是一种利用DP思想求解最值的倍增算法

ST表常用于解决RMQ问题,即求解区间最值问题

接下来以求最大值为例分步讲解一下ST表的建立过程:

1.定义

f[i][j]表示[i,i+2j-1]这个长度为2j的区间中的最大值

2.预处理

f[i][0]=a[i],即区间[i,i]的最大值就是a[i]

3.状态转移

将[i,i+2j-1]平均分成两份,分别为[i,i+2j-1-1]和[i+2j-1,i+2j-1],两段的长度均为2j

[i,i+2j-1]的最大值为这两段的最大值中的较大值,即f[i][j]=max(f[i][j-1],f[i+2j-1][j-1])

4.核心代码

void ST(int n){
for(int j=;j<=;j++)
//注意要把j放外层,这样可以确保此时f[i+(1<<(j-1))][j-1]已经被赋值了
for(int i=;i<=n;i++)//枚举区间左端点
if(i+(<<j)-<=n)
f[i][j]=max(f[i][j-],f[i+(<<(j-))][j-]);
}

好啦建立好了ST表,接下来我们就可以直接O(1)地查询啦!QWQ

讲一讲查询的步骤:

1.查询过程

若需要查询的区间为[i,j],那么我们需要找到两个覆盖这个闭区间的最小幂区间,这两个区间可以重叠,因为这对区间最大值并没有什么影响。

这个区间的长度为j-i+1,所以我们要记录一个值k=log2(j-i+1)

于是就可以得到答案MAX(i,j)=max(f[i][k],f[j-(1<<k)+1][k])

2.完整代码

 #include<bits/stdc++.h>
#define go(i,a,b) for(register int i=a;i<=b;i++)
using namespace std;
const int MAXN=1e6+;
int a[MAXN],f[MAXN][];
void ST(int n){
go(j,,)
go(i,,n)
if(i+(<<j)-<=n)
f[i][j]=max(f[i][j-],f[i+(<<(j-))][j-]);
return;
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
go(i,,n) scanf("%d",&a[i]),f[i][]=a[i];
ST(n);
while(m--){
int i,j;
scanf("%d%d",&i,&j);
int k=(int)(log(j-i+)/log(2.0));
printf("%d\n",max(f[i][k],f[j-(<<k)+][k]));//O(1)直接查询
}
return ;
}

Update!

加一道例题——

邻值查找