算法详解——st表

Posted ackers

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法详解——st表相关的知识,希望对你有一定的参考价值。

st表是解决区间RMQ(区间最值问题)的一类算法,时间复杂度为O(nlogn)的预处理和O(1)的查询,其主要运用了类似倍增的思想...

总体来说,st表的用处还是挺大的,代码也比较短,容易记...

 


 

st表

 

若现在给定一个长度为n的序列A,每次给定两个数l,r,求出A[l]~A[r]中的最大值...

那么我们考虑怎么做,首先是朴素做法,每次询问最大值时用for循环从l到r跑一遍,每次循环复杂度为O(r - l)

那有没有一种算法可以让我们以O(1)的复杂度就知道最大值呢?

这时我们引进st表算法...

 

具体做法:

我们定义一个二维数组st[i][j]表示区间[i,i+2^j-1]里的最大值,那么有st[i][0] = A[i],即A[i]是区间[i,i]的最大值,然后我们运用倍增的思想,每次维护区间最值就行了,预处理的代码如下:

inline void init()
{
    for(int i = 1;i <= n;i ++) st[i][0] = a[i]; 
    for(int j = 1;j <= 21;j ++)
        for(int i = 1;(i + (1<<j) - 1) <= n;i ++)
            st[i][j] = max(st[i][j - 1],st[i + 1<<(j - 1)][j - 1]);
}

 

关于查询,我们需要先对查询区间的长度取一个对数k,那么2^k一定大于等于区间长度的一半,接着我们从左右两个端点处向内取最大值(即使有重叠也没事),这样我们就O(1)的查询出了区间的最大值,代码如下:

inline int query(int l,int r)
{
    int k = log(r - l + 1);
    return max(st[l][k],st[r - (1<<k) + 1][k]);
} 

 

下面有一道板子题

洛谷P3865

代码如下:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>

const int maxn = 1e5 + 5;
int n,m;
int st[maxn][23];

inline int read()
{
  char ch = getchar();int x = 0,f = 1;
  while(ch<0||ch>9){if(ch == -) f = -1; ch = getchar();}
  while(ch>=0&&ch<=9){x = x*10 + ch -0; ch = getchar();}
  return x*f;
}

inline void init()
{
  for(int i = 1;i <= 21;i ++)
    for(int j = 1;j+(1<<i)-1 <= n;j ++)
      st[j][i] = std::max(st[j][i-1],st[j+(1<<(i-1))][i-1]);
}

inline int query(int l,int r)
{
  int k = log2(r-l+1);
  return std::max(st[l][k],st[r-(1<<len)+1][k]);
}

int main(int argc, char const *argv[]) 
{
  n = read();
  m = read();
  for(int i = 1;i <= n;i ++) st[i][0] = read();
  init();
  for(int i = 1;i <= m;i ++)
  {
    int l = read();
    int r = read();
    printf("%d
",query(l,r));
  }
  return 0;
}

 

以上是关于算法详解——st表的主要内容,如果未能解决你的问题,请参考以下文章

ST表超级详解

算法小讲堂之ST表算法详解

ST表算法详解

ST算法详解

LCA 算法ST表

ST表详解(稀疏表)