ST表

ST算法(Sparse Table):       

 它是一种动态规划的方法。以最小值为例。a为所寻找的数组,用一个二维数组
    f(i,j)记录区间[i,i+2^j-1]区间中的最小值。其中f[i,0] = a[i];所以,对于任意
 的一组(i,j),f(i,j) = min{f(i,j-1),f(i+2^(j-1),j-1)}来使用动态规划计算出来。
     这个算法的高明之处不是在于这个动态规划的建立,而是它的查询:它的查询效
 率是O(1)!如果不细想的话,怎么弄也是不会想到有O(1)的算法的。假设我们要求
 区间[m,n]中a的最小值,找到一个数k使得2^k<n-m+1,即k=[ln(b-a+1)/ln(2)] 这样,
 可以把这个区间分成两个部分:[m,m+2^k-1]和[n-2^k+1,n]!我们发现,这两个区间
 是已经初始化好的!前面的区间是f(m,k),后面的区间是f(n-2^k+1,k)!这样,只要
 看这两个区间的最小值,就可以知道整个区间的最小值!

小结:   

 稀疏表(SparseTable)算法是O(nlogn)-O(1)的,对于查询很多大的情况下比较好。    

 ST算法预处理:用dp[i,j]表示从i开始的,长度为2^j 的区间的RMQ,则有递推式dp[i,j]=min{dp[i,j-1],dp[i+2j-1,j-1]}即用两个相邻的长度为2j-1的块,更新长度为2j的块。因此,预处理时间复杂度为O(nlogn)。这个算法记录了所有长度形如2k的所有询问的结果。从这里可以看出,稀疏表算法的空间复杂度为 O(nlogn)。

代码:

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int n,a[1001],f[1001][20];
int rmq(int x,int y)
{
    int k=floor(log(double(y-x+1)/log(2.0)));
      return min(f[x][k],f[y-(1<<k)+1][k]);
}
int main()
{
    int i,j;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
      scanf("%d",&a[i]),f[i][0]=a[i];
    int k=floor(log(double(n)/log(2.0)));
    for(j=1;j<=k;j++)
      for(i=n;i>=1;i--)
        if(i+(1<<(j-1))<=n)
          f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
    int x,y;
    scanf("%d%d",&x,&y);
    printf("%d",rmq(x,y));
    return 0;
}

 

 

 

posted @ 2016-11-15 15:36  一叶落尽天下秋  阅读(163)  评论(0编辑  收藏  举报