博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

ST表

ST表是用来维护RMQ的.

主要利用了倍增的思想,令f[i][j]表示从i开始向后2^j长度的RMQ值。

转移时由前一半和后一半进行转移:f[i][j]=max/min(f[i][j-1],f[i+(1<<(j-1))][j-1]);

然后查询[l,r]的时候:

我们来考虑一下:记k=log2(r-l+1)。k为log2(区间长度)再下取整。所以从l向后扩展(1<<k)长,从r向前扩展(1<<k)长。

设从r向前扩展(1<<k)长的位置为x,则x+(1<<k)-1=r  -> x=r-(1<<k)+1。

然后return max/min(f[l][k],f[r-(1<<k)+1][k])就好了。

模板代码(最大值):

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
#define ll long long
#define space putchar(' ')
#define endl putchar('\n')
#define debug puts("------------------------")
#define F(i,x,n) for(int i=x;i<=n;++i)
#define F_(i,x,n) for(int i=x;i>=n;--i)
using namespace std;
inline void read(int &a) {a=0;int c=getchar(),b=1; while(c>'9'||c<'0') {if(c=='-')b=-1;c=getchar();} while(c>='0'&&c<='9') a=(a<<3)+(a<<1)+c-48,c=getchar();a*=b; }
inline int  Rem() {int a=0,c=getchar(),b=1; while(c>'9'||c<'0') {if(c=='-')b=-1;c=getchar();} while(c>='0'&&c<='9') a=(a<<3)+(a<<1)+c-48,c=getchar();return a*=b; }
inline void write(int x) {if(x>9)write(x/10);putchar('0'+x%10);}
inline void W(int x) {if(x<0){putchar('-'),x=-x;}write(x);}
/**/
const int N=1e5+5;
int f[N][21];
int n,m;
/**/
int query(int l,int r)
{
    int len=log2(r-l+1);
    return max(f[l][len],f[r-(1<<len)+1][len]);
}
int main()
{
    // freopen("test.in","r",stdin);
    // freopen("test.out","w",stdout);
    read(n);read(m);
    for(int i=1;i<=n;i++) read(f[i][0]);
    for(int j=1;j<=20;j++)
    {
        for(int i=1;i+(1<<j)-1<=n;i++)
        {
            f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
        }
    }
    for(int i=1,l,r;i<=m;i++)
    {
        read(l);read(r);
        cout<<query(l,r)<<'\n';
    }
}
View Code

 

注意一下不要再傻逼的把log2(r-l+1)写成log(r-l+1)了。。。

 

posted @ 2019-03-11 20:49  楚泫  阅读(117)  评论(0编辑  收藏  举报