zoukankan      html  css  js  c++  java
  • 倍增RMQ(ST表)

    #include<iostream>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #define maxn 100010
    #define maxm 2000010
    using namespace std;
    template<typename T>
    inline void read(T &x){
        x=0; bool flag=0; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') flag=1;
        for(;isdigit(c);c=getchar()) x=x*10+(c^48);
        if(flag) x=-x;
    }
    
    int n,m,a[maxn],l,r,f[maxn][20];
    int len,c,ans;
    
    inline void ST(){
        for(int i=1;i<=n;i++) f[i][0]=a[i];
        for(int j=1;j<=19;j++){//相当于区间DP,注意j一定要在i外面 
            for(int i=1;i+(1<<j)-1<=n;i++){//范围为[i,i+(2^j)-1],所以保证i+(2^j)-1<=n不越界 
                f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]); 
            }
        }
    }
    
    int main(){
        read(n);read(m);
        for(int i=1;i<=n;i++) read(a[i]);
        ST(); 
        for(int i=1;i<=m;i++) {
            read(l),read(r);
            len=r-l+1;
            c=log2(len);//满足2^c<=len的最大的c,把原区间拆成[l,l+2^c-1]and[r-(2^c)+1,r]这两段区间  
            ans=max(f[l][c],f[r-(1<<c)+1][c]);
            cout<<ans<<endl;
        }
        return 0;
    }

    区间最值问题,预处理O(nlogn),以O(1)的时间复杂度在线回答“区间[l,r]之间的数的最大值是多少”

    因为[l,l+2^c-1]和[r-(2^c)+1,r]有交集,所以ans的计算不会漏东西(有交集不影响结果,只要不会少算某一部分就好了)

    ·“有交集”的证明:

    ∵2^c<=len

    ∴2^(c+1)>len

    ∴2^(c+1)-1>=len

    ∴[l,l+2^c-1]和[r-(2^c)+1,r]有交集,证毕

    洛谷P3865卡常卡死了qaq

    贴一个爆改n遍终于过了的惨不忍睹的代码:

    #include<iostream>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #define maxn 100010
    #define maxm 2000010
    using namespace std;
    inline int read(void)
    {
        int x=0,f=1;char ch=getchar();
        while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
        while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
        return x*f;
    }
    
    int n,m,a[maxn],l,r,f[20][maxn];
    int len,c,ans;
    
    //inline void ST(){
    //    for(int i=1;i<=n;i++) f[i][0]=a[i];
    //    for(int j=1;j<=19;j++){//相当于区间DP,注意j一定要在i外面 
    //        for(int i=1;i+(1<<j)-1<=n;i++){//范围为[i,i+(2^j)-1],所以保证i+(2^j)-1<=n不越界 
    //            f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]); 
    //        }
    //    }
    //}
    
    int main(){
        n=read();m=read();
        for(int i=1;i<=n;i++) a[i]=read();
    //    ST(); 
        for(int i=1;i<=n;i++) f[0][i]=a[i];
        for(int j=1;j<=17;j++){//相当于区间DP,注意j一定要在i外面 
            for(int i=1;i+(1<<j)-1<=n;i++){//范围为[i,i+(2^j)-1],所以保证i+(2^j)-1<=n不越界 
                f[j][i]=max(f[j-1][i],f[j-1][i+(1<<(j-1))]); 
            }
        }
        for(int i=1;i<=m;i++) {
            l=read(),r=read();
    //        len=r-l+1;
            c=log2(r-l+1);//满足2^c<=len的最大的c,把原区间拆成[l,l+2^c-1]and[r-(2^c)+1,r]这两段区间  
    //        ans=max(f[l][c],f[r-(1<<c)+1][c]);
            printf("%d
    ",max(f[c][l],f[c][r-(1<<c)+1]));
        }
        return 0;
    }

    ·upd:卡常小技巧:论怎样从4.91s->886ms

    1.不要cin/cout!!!输入输出很多的时候用时能翻好几倍!!!切记快读+printf!!!

    2.f的两维换一下也能快很多,比如这样:f[maxn][20]->f[20][maxn](亲测有效)

     原理大概这样:

     访问内存是连续的。

  • 相关阅读:
    deep_learning_Function_numpy_random.normal()
    deep_learning_Function_np.newaxis参数理解
    deep_learning_Function_numpy.linspace()
    deep_learning_Function_tf.identity()
    deep_learning_Function_tf.control_dependencies([])
    deep_learning_Function_tf.train.ExponentialMovingAverage()滑动平均
    deep_learning_Function_bath_normalization()
    deep_learning_PCA主成分分析
    deep_learning_Function_numpy_argmax()函数
    deep_learning_Function_matpotlib_scatter()函数
  • 原文地址:https://www.cnblogs.com/DReamLion/p/14383504.html
Copyright © 2011-2022 走看看