ST表学习笔记
0.关于ST表
ST表时间复杂度极小,不过是静态,支持RMQ,区间GCD等问题。
1.ST表入门
ST表基于倍增思想,以区间最小值为例,设\(st_{i,k}\)为从\(i\)开始往后\(2^k\)个的最小值。
显然,\(st_{i,0}=a_i\)(其中\(a\)为序列)
而\(st_{i,k}=\min(st_{i,k-1},st_{i+2^{k-1},k-1})\)(将前一半与后一半合并)
接下来是区间查询。先上代码
int query(int l,int r){
int k=lg[r-l+1];//lg为预处理的log2
return min(st[l][k],st[r-(1<<k)+1][k]);
}
可以证明,这样是不会超出\([l,r]\)的范围的,也不会出现漏算的情况。
里面会有一些重复,这就是ST表只支持RMQ等问题的原因。
RMQ重复算是不会对答案产生影响的,而RSQ等会产生影响。
P3865AC代码:
#include<bits/stdc++.h>
using namespace std;
int ans[100001][21],n,m,lg[100001];
int st(int x,int y){
int k=lg[y-x+1];
return max(ans[x][k],ans[y-(1<<k)+1][k]);
}
int main(){
scanf("%d%d",&n,&m);lg[0]=-1;
for(int i=1;i<=n;i++){
lg[i]=lg[i>>1]+1;
scanf("%d",&ans[i][0]);
}
for(int i=1;i<=20;i++){
for(int j=1;j+(1<<i)-1<=n;j++){
ans[j][i]=max(ans[j][i-1],ans[j+(1<<(i-1))][i-1]);
}
}
while(m--){
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",st(x,y));
}
return 0;
}
时空复杂度证明:
预处理部分,一维为\(\log n\)级别,一维为\(n\)级别,总共为\(O(n\log n)\)
询问部分:显然\(O(1)\)