ST表

ST算法(Sparse Table,又称稀疏表、ST表)是用来解决RMQ问题的一种算法。

RMQ(Range Minimum/Maximum Query)问题是询问区间最值的一种问题。

ST表的实质是利用倍增思想的动态规划。相较于朴素的暴力(O(n))做法,ST表可以做到(O(nlog n))时间的预处理,(O(1))时间的查询,是解决这类问题最快的算法,但不支持在线修改。
ST表利用一个二维数组记录答案(典型的以空间换时间),在这个数组中(st[i][j])表示从第(i)个数开始连续(2^j)个数中的最值(包括第(i)个数),因此查询的区间范围为([i,i+2^j-1]),并且初始条件为(st[i][0]=)(i)个数。在构造的过程中,我们有如下转移方程(以最大值为例)

[st[i][j]=max(st[i][j-1],st[i+2^{j-1}][j-1]) ]

需特别注意构造时的细节。第一,第(i+2^j-1)个数(右边界)不能出界(即不超过最后一个数的序号);第二,两层循环的外层应是(j),这可以感性地理解一下,因为每次构造ST表时都是先让区间长度固定将序列全部遍历完后再修改区间长度,而这里的区间长度就对应循环里的(j)
构造说完后,再说查询。设读入区间范围为([l,r]),那么它的长度为(r-l+1),由于有可能区间的长度不能严格等于(2)的幂次,所以我们会把它分成两段分别查询然后求最值,这并不影响结果。具体做法是,先求出(k=leftlfloor {{{log }_2}(r - l + 1)} ight floor) ,然后将它分成([l,l+2^k-1])([r-2^k+1,r])两段,即在查询时分别查询(st[l][k])(st[r-2^k+1][k]),注意到这两段有重合的地方,且长度均为(2^k-1)。至于为什么这么分是正确的,是基于一个公式

[2^{lfloor{log_2 N} floor}>frac{N}{2} ]

因此我们取对数总能保证两段将整个区间完全覆盖。
最后,还有一点小插曲值得一提,在我看到的求对数的写法中,基本上都是int k = (int)(log((double)(r-l+1))/log(2.0)),由于数学库中没有提供以任意底求对数的函数,于是就用了换底公式进行了转换(让我对换底公式有了深刻的记忆2333),换底公式为

[log_aN=frac{log_bN}{log_ba} ]

但由于这里要求(2)为底的对数,所以不用这么麻烦,直接用库里提供的log2()就好啦!


说完了这些,刚好附一道裸的模板题的代码,就当板子用啦qwq
(题目:[P2880]Balanced Lineup)

#include <iostream>
#include <cmath>
#define MAX(a,b) a>b?a:b
#define MIN(a,b) a<b?a:b
using namespace std;
int n,q,STmin[50005][20],STmax[50005][20];
void RMQbyST()
{
    int k=log2(n);
    for(int j=1;j<=k;j++)
        for(int i=1;i+(1<<j)-1<=n;i++)	//构造时需特别注意
                STmax[i][j]=MAX(STmax[i][j-1],STmax[i+(1<<(j-1))][j-1]),
                STmin[i][j]=MIN(STmin[i][j-1],STmin[i+(1<<(j-1))][j-1]);
}
int main()
{
    ios::sync_with_stdio(false);
    cin >> n >> q;
    for(int i=1;i<=n;i++)
    {
        cin >> STmin[i][0];
        STmax[i][0]=STmin[i][0];	//初始条件不能忘!
    }
    RMQbyST();
    while(q--)
    {
        int l,r;
        cin >> l >> r;
        int k=log2(r-l+1);
        int Max=MAX(STmax[l][k],STmax[r-(1<<k)+1][k]),
            Min=MIN(STmin[l][k],STmin[r-(1<<k)+1][k]);
        cout << Max-Min << endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/wzzyr24/p/11423512.html