模板 ST表

ST表,适用于解决RMQ(区间最值问题),相似于线段树和树状数组这两个算法node

ST表相比于线段树,预处理的复杂度与线段树同样,而查询的复杂度则大大快于线段树ios

  预处理 查询
ST表  O(nlogn) O(1)
线段树 O(nlogn) O(logn)

 

洛谷 P3865 【模板】ST表git

ST表算法

 

线段树(不开O2):数组

 

线段树(开O2优化): ide

 

 

经比较,咱们能够垂手可得的看出,当咱们解决RMQ问题时,ST表的速度明显优于线段树函数

 

ST表的主体是一个二维数组:st[i][j]。表示查询的数组的下标ii+2^j-1优化

如何进行预处理呢??ui

首先,咱们把从0~n-1的2^0的部分进行覆盖spa

而后向下处理

Q:处理??怎么处理??

A:不明白??那咱们来举一个例子

咱们以一个长度为5的数组

2^0部分覆盖过去就是 a[1],a[2],a[3],a[4],a[5]

2^1部分的长度为4,也就是下标从1到4,

st[0][1]是下标为0~1的区间的最值

也就是st[0][0]和st[0][1]的最值

以此往下类推

 

结论:st[i][j] = min ( st[i][j-1] , st[i + 2^(j-1) ][j-1] );

 

预处理函数(求最大值):

inline void init(int n)
{
    for(int i=1;i<=n;i++)
    {
        st[i][0]=a[i];
    }
    for(int j=1;(1<<j)<=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]);
        }    
    }
}
预处理函数

 

 

查询函数,这个地方就很难理解了

 

首先,初始化,初始化的时候,每个状态对应的区间都是2^j

因为查询时的长度不知道

因此咱们要用到一个定理:2^log(a)>a/2

 

由于log(a)函数表示是小于等于2的最大次方

也就是说,a>=2^(max_j)

其中2^max_j表示的是不大于a的2的最大次方

Q:不明白。。

A:不要紧,那咱们来看几个例子就知道了

log(4)=2; log(5~7)=2; log(8)=3; log(9~15)=3; log(16)=4; log(17~31)=4;....

Q:可窝仍是不明白。

A:不要紧,咱们再以log(4)=2,log(5~7)=2为例

这些数的log都是2

再仔细琢磨一下log()里面的数

4,5,6,7。floor(sqre(4)),floor(sqre(5)),floor(sqre(6)),floor(sqre(7))它们的值都等于2。

也就是2^max<=a。

 

那么咱们要查询x到y的最大值

咱们设len=(y-x+1),data=log(len)=log(y-x+1)

根据上面的定理,咱们能够知道,2^data>len/2

从下标(位置)上来看,x+2^data>(x+y)/2;

也就是越过了区间[x,y]的中间

由于位置超过了一半

因此x到y的最大值就能够表示为max(从x日后的2^t的最大值,从y往前2^t的最大值);

前面的状态咱们能够表示为 st[data][x]

设后面的初始位置为k,也就是说,从y往前2^t的最大值的初始位置是k

那么k+2^data-1=y;

因此k=y-2^data+1;

因此后面的状态就是st[data][y-2^data+1]

因此说,区间[x,y]的最大值就能够表示为max(st[data][x],st[data][y-2^t+1])

因此查询的时间复杂度是O(1)

 

查询函数:

inline int search(int l,int r)
{
    int k=(int)(log((double)(r-l+1))/log(2.0));
    return max(st[l][k],st[r-(1<<k)+1][k]);
}
查询函数

 

 一道ST表模板题,(上文也有提到)

能够垂手可得的看出ST表和线段树在处理RMQ问题上的速度差别

如下是AC代码(ST表和线段树都有 线段树的并不是AC代码)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctype.h>

using namespace std;

int a[100001];
int st[100100][21];

inline int read()
{
    int s=1, w=0; char ch=getchar();
    for(; !isdigit(ch);ch=getchar()) if(ch=='-') s =-1;
    for(; isdigit(ch);ch=getchar()) w = w*10+ch-'0';
    return s*w;
}

inline void init(int n)
{
    for(int i=1;i<=n;i++)
    {
        st[i][0]=a[i];
    }
    for(int j=1;(1<<j)<=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]);
        }    
    }
}

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

int main()
{
    int n,m;
    n=read();
    m=read();
    for(int i=1;i<=n;i++)
    {
        a[i]=read();
    }
    init(n);
    for(int i=1;i<=m;i++)
    {
        int l,r;
        l=read();
        r=read();
        printf("%d\n",search(l,r));
    }
    return 0;
}

//
//#include<iostream>
//#include<cstdio>
//#include<cstring>
//#include<cmath>
//#include<ctype.h>
//#define int long long int 
//
//using namespace std;
//
//struct node
//{
//    int l;
//    int r;
//    int w;
//    int lazy;
//    int mxx;
//}tree[5000010];
//
//int n,m;
//int ans;
//int x,y;
//
//inline int read()
//{
//    int s=1, w=0; char ch=getchar();
//    for(; !isdigit(ch);ch=getchar()) if(ch=='-') s =-1;
//    for(; isdigit(ch);ch=getchar()) w = w*10+ch-'0';
//    return s*w;
//}
//
//void build(int l,int r,int k)
//{
//    tree[k].l=l;
//    tree[k].r=r;
//    if(tree[k].l==tree[k].r)
//    {
//        tree[k].w=read();
//        tree[k].mxx=tree[k].w;
//        return;
//    }
//    int m=(tree[k].l+tree[k].r)/2;
//    build(l,m,k*2);
//    build(m+1,r,k*2+1);
//    tree[k].w=tree[k*2].w+tree[k*2+1].w;
//    tree[k].mxx=max(tree[k*2].mxx,tree[k*2+1].mxx);
//}
//
//inline void down(int k)
//{
//    tree[k*2].lazy+=tree[k].lazy;
//    tree[k*2+1].lazy+=tree[k].lazy;
//    tree[k*2].w+=tree[k].lazy*(tree[k*2].r-tree[k*2].l+1);
//    tree[k*2+1].w+=tree[k].lazy*(tree[k*2+1].r-tree[k*2+1].l+1);
//    tree[k].lazy=0;
//}
//
//inline void ask_max_query(int k)
//{
//    if(tree[k].l>=x&tree[k].r<=y)
//    {
//        ans=max(ans,tree[k].mxx);
//        return;
//    }
//    if(tree[k].lazy)
//    {
//        down(k);
//    }
//    int m=(tree[k].l+tree[k].r)/2;
//    if(x<=m)
//    {
//        ask_max_query(k*2);
//    }
//    if(y>m)
//    {
//        ask_max_query(k*2+1);
//    }
//}
//
//signed main()
//{
//    n=read();
//    m=read();
//    build(1,n,1);
//    for(int i=1;i<=m;i++)
//    {
//        x=read();
//        y=read();
//        ans=0;
//        ask_max_query(1);
//        cout<<ans<<endl;
//    }
//    return 0;
//} 
P3865 【模板】ST表
相关文章
相关标签/搜索