RMQ问题ST表
稀疏表(Sparse Table表)
解决静态RMQ,区间最值查询问题的数据结构,树状数组(BIT)解决动态前缀和问题的数据结构;
例:https://www.luogu.org/problemnew/show/P3865
原理:把给定区间分成长度是2的幂次的小区间。先预处理出它们中的最小值是多少,然后用一种类似二分的思想由小区间到大区间比较两个区间的最小值。
ST算法,设f[i][j]f[i][j]表示从序列的第ii个位置开始ajaj个数的最大值,我们可以得到公式f[i][j]=max(f[i][j−1],f[i+2j−1][j−1])f[i][j]=max(f[i][j−1],f[i+2j−1][j−1]),相当于把一个从ii到2j2j的区间分成了两个长度为2j−12j−1的区间。当我们查询最大值的时候,我们可以算出一个kk,就是让2k<2k<这个区间长度时,kk的最大值,那么我们查询的区间(l,r)(l,r)的答案就为max(f[l][k],f[r−2k+1][k])max(f[l][k],f[r−2k+1][k]),这两段刚好覆盖了这个区间,所以答案是准确的。
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; const int maxn=1e5+10; //区间最值的ST表做法; int n,m,x,y,f[maxn][22]; //一维是端点,二维是长度(二的幂次级别); int main() { scanf("%d%d",&n,&m); //n个元素,m个询问 for(int i=1;i<=n;i++)scanf("%d",&f[i][0]); for(int j=1;j<=20;j++) { for(int i=1;i+(1<<j)-1<=n;i++) { f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);//每个区间的更新一分为二 } } while(m--){ //ST表的查询; scanf("%d%d",&x,&y); int k=log2(y-x+1); //区间长度可达的最大的幂次级; printf("%d\n",max(f[x][k],f[y-(1<<k)+1][k])); //从左端点查询长度为查询的区间的最大2次幂可达值,在从右端点查询,这两个区间一定会有重合,并完全覆盖查询区间. } return 0; }