[学习笔记]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\n",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\n",ans);
    }
    return 0;
}

 

 

树上ST表

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

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

 

 

 

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

用于卡常数还是不错的。

转载于:https://www.cnblogs.com/Miracevin/p/9856967.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值