ST表学习笔记
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=1;j<=20;j++) //注意要把j放外层,这样可以确保此时f[i+(1<<(j-1))][j-1]已经被赋值了 for(int i=1;i<=n;i++)//枚举区间左端点 if(i+(1<<j)-1<=n) f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]); }
好啦建立好了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.完整代码
1 #include<bits/stdc++.h> 2 #define go(i,a,b) for(register int i=a;i<=b;i++) 3 using namespace std; 4 const int MAXN=1e6+5; 5 int a[MAXN],f[MAXN][20]; 6 void ST(int n){ 7 go(j,1,20) 8 go(i,1,n) 9 if(i+(1<<j)-1<=n) 10 f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]); 11 return; 12 } 13 int main(){ 14 int n,m; 15 scanf("%d%d",&n,&m); 16 go(i,1,n) scanf("%d",&a[i]),f[i][0]=a[i]; 17 ST(n); 18 while(m--){ 19 int i,j; 20 scanf("%d%d",&i,&j); 21 int k=(int)(log(j-i+1)/log(2.0)); 22 printf("%d\n",max(f[i][k],f[j-(1<<k)+1][k]));//O(1)直接查询 23 } 24 return 0; 25 }
Update!
加一道例题——