• [学习笔记]ST表


    前言:某次模拟赛T1被二维ST坑了。于是决心总结下。

    ST表:O(常数)查询静态区间最值。

    思想:利用倍增预处理。然后拼凑。

    一维ST表:

    f[i][j]表示,[i,i+(1<<j)-1]的区间最值。

    lg[i]表示,log2i

    #include<bits/stdc++.h>
    using namespace std;
    const int N=100000+10;
    int n,m;
    int a[N];
    int f[N][30];
    int lg[N];
    int main()
    {
        scanf("%d%d",&n,&m);
        int t;
        for(int i=1;i<=n;i++) scanf("%d",&t),f[i][0]=t;
        for(int i=1;i<=n;i++) lg[i]=(i>>lg[i-1]+1)?lg[i-1]+1:lg[i-1];
        for(int j=1;(1<<j)<=n;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]);
            }
        int l,r;
        for(int i=1;i<=m;i++){
            scanf("%d%d",&l,&r);
            int len=lg[r-l+1];
            printf("%d
    ",max(f[l][len],f[r-(1<<len)+1][len]));
        }
        return 0;
    }

    二维ST表:

    类似处理二维前缀和。

    先求出每行单独的,然后再把行并起来。

    f[i][j][k][l]表示,行[i,i+(1<<k)-1]与列[j,j+(1<<l)-1]围成的矩形的数的最值。

    lg[i]同上。

    #include<bits/stdc++.h>
    #define ri register int 
    #define numb (ch^'0')
    using namespace std;
    typedef long long ll;
    const int N=303;
    void rd(int &x){
        x=0;char ch;
        while(!isdigit(ch=getchar()));
        for(x=numb;isdigit(ch=getchar());x=(x<<1)+(x<<3)+numb);
    }
    int a[N][N];
    int f[N][N][12][12];
    int n,m,q;
    int lg[N];
    inline int Max(const int &a,const int &b){
        return a>b?a:b;
    }
    int main(){
        scanf("%d%d",&n,&m);
        int now=1,id=0;
        for(ri i=1;i<=max(n,m);++i){
            if(i==now) lg[i]=id,now*=2,++id;
            else lg[i]=lg[i-1];
        }
        for(ri i=1;i<=n;++i){
            for(ri j=1;j<=m;++j){
                rd(a[i][j]);
                f[i][j][0][0]=a[i][j];
            }
        }
        for(ri l=1;l<=10;++l){
            for(ri i=1;i<=n;++i){
                for(ri j=1;j+(1<<l)-1<=m;++j){
                        f[i][j][0][l]=Max(f[i][j][0][l-1],f[i][j+(1<<(l-1))][0][l-1]);
                }
            }
        }
        for(ri k=1;k<=10;++k){
            for(ri l=0;l<=10;++l)
            for(ri i=1;i+(1<<k)-1<=n;++i){
                for(ri j=1;j+(1<<l)-1<=m;++j){
                        f[i][j][k][l]=Max(f[i][j][k-1][l],f[i+(1<<(k-1))][j][k-1][l]);
                }
            }
        }
        scanf("%d",&q);
        int x1,x2,y1,y2;
        while(q--){
            rd(x1);rd(y1);rd(x2);rd(y2);
            int l1=x2-x1+1;
            int l2=y2-y1+1;
            int g1=lg[l1],g2=lg[l2];
            //cout<<g1<<" "<<l1<<" "<<g2<<" "<<l2<<endl;
            int ans=0;
            ans=Max(ans,f[x1][y1][g1][g2]);
            //cout<<ans<<endl;
            ans=Max(ans,f[x1][y2-(1<<g2)+1][g1][g2]);//cout<<ans<<endl;
            ans=Max(ans,f[x2-(1<<g1)+1][y1][g1][g2]);//cout<<ans<<endl;
            ans=Max(ans,f[x2-(1<<g1)+1][y2-(1<<g2)+1][g1][g2]);
            printf("%d
    ",ans);
        }
        return 0;
    }

    树上ST表

    O(logn)查询树上两点链之间的最值。logn因为要找LCA

    处理方法类比倍增LCA。跳LCA的时候顺便求出。

    基于倍增思想的预处理。O(常数)查询。

    用于卡常数还是不错的。

  • 相关阅读:
    .Net魔法堂:史上最全的ActiveX开发教程——发布篇
    .Net魔法堂:史上最全的ActiveX开发教程——开发篇
    JS魔法堂:浏览器模式和文档模式怎么玩?
    JS魔法堂:精确判断IE的文档模式by特征嗅探
    JS魔法堂:追忆那些原始的选择器
    意译:自调用函数表达式
    一起Polyfill系列:让Date识别ISO 8601日期时间格式
    一起Polyfill系列:Function.prototype.bind的四个阶段
    poco 线程库
    CDN理解<转>
  • 原文地址:https://www.cnblogs.com/Miracevin/p/9856967.html
Copyright © 2020-2023  润新知