zoukankan      html  css  js  c++  java
  • 洛谷 P3865 ST表

    ST表

    ST表的功能很简单

    它是解决RMQ问题(区间最值问题)的一种强有力的工具

    它可以做到O(nlogn)预处理,O(1)查询最值

    是一种处理静态区间可重复计算问题的数据结构,一般也就求求最大最小值辣。

    ST表的思想是先求出每个[i, i + 2^k)的最值。

    注意到这样区间的总数是O(N log N)的.


    预处理

    不妨令fi,j为[i, i + 2^j)的最小值。

    那么首先fi,0的值都是它本身。

    而fi,j = min(fi,j−1, fi+2^j−1,j−1)

    这样在O(N log N)的时间内就处理好了整个ST表

    询问

    比如我们要询问[l, r]这个区间的最小值.

    找到最大的k满足2^k ≤ r − l + 1.

    取[l, l + 2^k), [r − 2^k + 1, r + 1)这两个区间。

    注意到这两个区间完全覆盖了[l, r],所以这两个区间最小值

    较小的一个就是[l, r]的最小值。

    注意到每次询问只要找区间就行了,所以复杂度是O(1).

    解释一下数组含义:

    ST[j][i]为从j开始的长度为2^i的区间的最大值

    Log[x]为比x小的最大的2^y 的y值(或者说是log x 下去整

    代码: 

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<iomanip>
    #include<cmath>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<time.h>
    #include<queue>
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef pair<int,int> pr;
    const double pi=acos(-1);
    #define rep(i,a,n) for(int i=a;i<=n;i++)
    #define per(i,n,a) for(int i=n;i>=a;i--)
    #define Rep(i,u) for(int i=head[u];i;i=Next[i])
    #define clr(a) memset(a,0,sizeof a)
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define sc second
    ld eps=1e-9;
    ll pp=1000000007;
    ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;}
    ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;}
    ll read(){
        ll ans=0;
        char last=' ',ch=getchar();
        while(ch<'0' || ch>'9')last=ch,ch=getchar();
        while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
        if(last=='-')ans=-ans;
        return ans;
    }
    //head
    
    int m,n,a[100001],st[100001][17],Log[100001];
    
    int find(int a,int b)
    {
        int t=Log[b-a+1];
        return max(st[a][t],st[b-(1<<t)+1][t]);
        //注意到对于[l,r],[l,l+2^x-1],[r-2^x+1,r]并起来是[l,r] 
    }
    
    int main()
    {
        n=read(),m=read();
        rep(i,1,n)  a[i]=read();
        rep(i,1,n)  st[i][0]=a[i];
        rep(i,1,18) 
        {
            for(int j=1;j+(1<<i)-1<=n;j++)
            {
                st[j][i]=max(st[j][i-1],st[j+(1<<(i-1))][i-1]);
                //ST[j][i]为从j开始的长度为2^i的区间的最大值 
    //显然[j,j+2^i)=[j,j+2^(i-1))+[j+2^(i-1),j+2^i)=max(ST[i-1][j],ST[i-1][j+2^(i-1)])
            }
        }
        for(int i=1;(1<<i)<100001;i++) Log[1<<i]=i;
        for(int i=1;i<100001;i++) 
        {
            if(Log[i]==0) Log[i]=Log[i-1]; 
            //令Log[x]为比x小的最大的2^y 
        }
        for(int i=1;i<=m;i++)
        {
            int x,y;
            x=read(),y=read();
            printf("%d
    ",find(x,y));
        }
        return 0;
    }

     

  • 相关阅读:
    推荐有关微信开发的十个开源项目
    curl 常见错误码
    mysql修改root密码
    BAT批处理之文件与文件夹操作代码(附xcopy命令详解)
    UE4 Pak包加载
    libcurl 文件上传
    win7右键在目录当前打开命令cmd窗口
    SQLiteDeveloper破解
    Excel替换应用
    解决局域网2级路由互相连接共享的问题
  • 原文地址:https://www.cnblogs.com/lcezych/p/10951982.html
Copyright © 2011-2022 走看看