ST表浅谈

ST表浅谈_第1张图片世界真的很大

说来惭愧,直到昨天才搞清楚这个st表,然后花时间整理了一下思路,终于是差不多了。其实本来不想写的,网上看来看去好像st表除了RMQ,LCA就没什么了,况且LCA我会树链剖分,RMQ能写线段树,除了代码量少的那么一点点优势,我学他干嘛?后来一想,这种倍增的思想其实可能有点用,有可能在许多dp方程之类的能用得到,况且整体思想还很简单,就直接简单说明一下了。
以RMQ为例吧,介绍一下ST表。(这里就只管区间最大值了)
首先来见识一下ST表的核心数组st[i][j],意思是,由数列i位置往后推2^j个单位长度的区间里的最大值,然后呢,stmax的更新也就是dp的思想,st[i][j]可以由st[i][j-1],st[i+(1<<(j-1))][j-1]得到,因为2^(j-1)肯定是2^j的一半,相当于就是把一个区间的前后两部分的最大值相比较,得出这个区间的最大值,这是一个递推的关系。代码:

for(int j=1;j<=log[n];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]);

查询的时候便更简单,有了这个st表几乎无所不能,没错,o(1)查询。
记录查询区间为l,r。如果(r-l+1)正好是2^j,那么就直接返回st[l][j]就行了。但不可能每次查询的时候正好区间长度就是2的整数次幂,所以我们直接取区间长度的log值,向下取整,有可能并不能完全覆盖区间长度,但也绝对比区间的一半要长,(理解一下log),那么我们就可以把区间分成两个部分,长度都是2^(log(n)),因为只是取最值,所以两段可以重合一部分,代码:

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

这里是提前预处理了log值,从1到n,向下取整,log函数的预处理其实可以和st表的预处理结合到一起,好好理解下:

for(int i=1;i<=n;i++)
    {
        log[i]=((i&(i-1))==0)?log[i-1]+1:log[i-1];
        st[i][0]=a[i];
    }

这个log就是重点了。
完整代码:

#include
#include
using namespace std;
int n=100,m,a[10010],st[10010][40],log[10010];
void init()
{
 log[0]=-1;
 for(int i=1;i<=n;i++)
 {
 log[i]=((i&(i-1))==0)?log[i-1]+1:log[i-1];
 st[i][0]=a[i];
 }
 for(int j=1;j<=log[n];j++)
 for(int i=1;i+(1<
 st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}

嗯,就是这样。。。

你可能感兴趣的:(ST表浅谈)