有关st表的学习

关于这个知识点的学习的契机是25年东北邀请赛的a题

2025东北邀请赛a题链接戳我

image

其中官方答案是二分加st表,但是也能用压缩加双指针;

有关st表 st表是一种稀疏表,第一个系数是起始点,第二个系数是当前区间的长度,能用O(1)的速度进行区间的有关量查询 代码如下:
点击查看代码
////求最小开启
#define max min
////求最大公倍数开启
#define max __gcd
////求最大均不开启
void solve_st(){
    int n;
    cin>>n;
    vector<int>a(n+1);
    int max_len=(int)log2(n);
    vector<vector<int>>st_(n+1,vector<int>(max_len+1));
////a[i][j]的意思是第i个元素开始,长度为2^j长度的闭区间数组的目标元素,简而言之就是区间[i,i+(1<<j)-1]的目标元素,这里是最大值;

////优先考虑数组长度
    for(int j=0;j<=max_len;j++){
////起始点位置
        for(int i=1;i+(1<<j)-1<=n;i++){
            if(j==0)st_[i][j]=a[i];
            else st_[i][j]=max(st_[i][j-1],st_[i+(1<<(j-1))][j-1]);
        }
    }
////查询[l,r]区间的目标值:
    auto find_st=[&](int l,int r){
        int len=r-l+1;
        len=(int)log2(len);
        return max(st_[l][len],st_[r-(1<<len)+1][len]);
    };
}

1.对于st表的创建
对于每一个开始的节点,一个大的区间的目标值等于【左端点和大区间的左端点重合,长度小于最大区间的最大区间】和【右端点和大区间的右端点重合,长度小于最大区间的最大区间】两个区间的目标值的目标值,其中长度为1的区间目标值为其本身,之后从小区间扩展到大区间。
2.对于st表区间的查询
取两个区间分别是左端点是l长度为2的幂次方的最长区间的值和右端点为r长度为2的幂次方的最长区间的值,之后直接求出两个目标值最优的值作为返回值。

对于上面那个a题的ac代码:

点击查看代码
void solve1(){
    int n;
    cin>>n;
    vector<int>a(n+1);
    for(int i=1;i<=n;i++)cin>>a[i];
    int maxlen=(int)log2(n);
    vector<vector<int>>gcds(n+1,vector<int>(maxlen+1));
    vector<vector<int>>mins(n+1,vector<int>(maxlen+1));
    for(int j=0;j<=maxlen;j++){
        for(int i=1;i+(1<<j)-1<=n;i++){
            if(j==0)mins[i][j]=a[i],gcds[i][j]=a[i];
            else mins[i][j]=min(mins[i][j-1],mins[i+(1<<(j-1))][j-1]),gcds[i][j]=__gcd(gcds[i][j-1],gcds[i+(1<<(j-1))][j-1]);
        }
    }
    auto chamin=[&](int l,int r){
        int len=r-l+1;
        len=(int)log2(len);
        return min(mins[l][len],mins[r-(1<<len)+1][len]);
    };
    auto chagcd=[&](int l,int r){
        int len=r-l+1;
        len=(int)log2(len);
        return __gcd(gcds[l][len],gcds[r-(1<<len)+1][len]);
    };
    ll ans=0;

    for(int i=1;i<=n;i++){
        int l=i,l1=0;
        int mid;
        while(l-l1!=1&&i!=1){
            mid=(l+l1)/2;
////左边取大于当前值的元素
            if(chamin(mid,i-1)>a[i]&&__gcd(chagcd(mid,i-1),a[i])==a[i]){
                l=mid;
            }else{
                l1=mid;
            }
        }
        int r=i,r1=n+1;
////右边取大于等于当前值的元素
        while(r1-r!=1&&i!=n){
            mid=(r+r1)/2;
            if(__gcd(chagcd(i+1,mid),a[i])==a[i]){
                r=mid;
            }else {
                r1=mid;
            }
        }
        ans+=(1LL*(i-l+1)*(r-i+1));
    }

    cout<<ans<<endl;
}

总结:st表作为稀疏表能快速多次查询区间目标值

posted on 2025-08-23 14:27  神奇猫猫侠  阅读(20)  评论(0)    收藏  举报

导航