RMQ-ST表 专题训练

Posted tldr

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RMQ-ST表 专题训练相关的知识,希望对你有一定的参考价值。

ST表简介

ST表示解决RMQ问题的一种暴力手段,处理时间\(O(n\log_2n)\),查询时间\(O(1)\),空间\(O(n\log_2n)\).

处理

ST表的第0列存放第一层数据,即原始数据;
ST表的第1列存放第二层数据,即步长为\(2^0\)\(min/max\)的数据;
ST表的第2列存放步长为\(2^1\)\(min/max\)的数据;
...
以此类推可以看出什么呢?
每一列维护的范围是上一列的2倍,类似树状数组。也就是说,第一列维护自己,第二列维护\([i,i+1]\),第三列维护\([i,i+3]\)...
到第\(\log_2n\)列时,维护所有的数据。

查询

如何查询呢?
假设查询\([x,y]\)区间内的\(min/max\),则我们需要查询的是层数是\(k=\log_2y-x+1\)
有一个定理:$ 2^\log_2diff>diff/2 $,因为 $n/2 < \log_xdiff<=n,(2^n=diff) $,因此此时第k层的步长为\(2^k>(y-x+1)/2\)正好大于需要查询区间的一半以上

而第k层的\(x\)行维护了\([x,x+2^k-1]\)的数据,\(y-2^k+1\)行维护了\([y-2^k+1,y]\)的区间,两者有重复,但是合起来正好覆盖\([x,y]\)的区域
只要取\(max([x][k],[y-2^k+1][k])\)即可完成。
经典题:
洛谷 P1816忠诚

#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<b;i++)
#define FOR2(i,a,b) for(int i=a;i<=b;i++)
#define sync ios::sync_with_stdio(false);cin.tie(0) 
#define ll long long
#define INF  0x3f3f3f3f;
#define MAXN 1000100
#define MOD 10007
#define sf(a,b) read(a),read(b)
using namespace std;
int n,m,arr[MAXN],dp[MAXN][60],x,y;
int main()

    cin>>n>>m;
    FOR2(i,1,n)cin>>arr[i],dp[i][0]=arr[i];
    for(int j=1;(1<<j)<=n;j++)
    
        for(int i=1;i+(1<<j)-1<=n;i++)
        
            dp[i][j]=min(dp[i][j-1],dp[i+(1<<j-1)][j-1]);//步长为1<<j-1 
        
    
    while(m--)
    
        scanf("%d%d",&x,&y);
        int k=log2(y-x+1);//求第几阶 
        cout<<min(dp[x][k],dp[y-(1<<k)+1][k])<<" ";
    
    return 0;
  

洛谷 P2880平衡的阵容

#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<b;i++)
#define FOR2(i,a,b) for(int i=a;i<=b;i++)
#define sync ios::sync_with_stdio(false);cin.tie(0) 
#define ll long long
#define INF  0x3f3f3f3f;
#define MAXN 1000100
#define MOD 10007
#define sf(a,b) read(a),read(b)
using namespace std;
int x,y,n,m,arr[MAXN],dpmax[MAXN][60],dpmin[MAXN][60];
int main()

    cin>>n>>m;
    FOR2(i,1,n)cin>>arr[i],dpmax[i][0]=dpmin[i][0]=arr[i];
    for(int j=1;(1<<j)<=n;j++)
        for(int i=1;i+(1<<j)-1<=n;i++)
        
            dpmax[i][j]=max(dpmax[i][j-1],dpmax[i+(1<<j-1)][j-1]);
            dpmin[i][j]=min(dpmin[i][j-1],dpmin[i+(1<<j-1)][j-1]);
        
    while(m--)
    
        cin>>x>>y;
        int k=log2(y-x+1);
        cout<<max(dpmax[x][k],dpmax[y-(1<<k)+1][k])-min(dpmin[x][k],dpmin[y-(1<<k)+1][k])<<endl;;
    
    return 0;

洛谷 P3865模板ST表

#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<b;i++)
#define FOR2(i,a,b) for(int i=a;i<=b;i++)
#define sync ios::sync_with_stdio(false);cin.tie(0) 
#define ll long long
#define INF  0x3f3f3f3f;
#define MAXN 1000100
#define MOD 10007
#define sf(a,b) read(a),read(b)
using namespace std;
int n,m,arr[MAXN],dp[MAXN][60],x,y;
int main()

    cin>>n>>m;
    FOR2(i,1,n)
    
        scanf("%d",&arr[i]);
        dp[i][0]=arr[i];
    
    for(int j=1;(1<<j)<=n;j++)
    
        for(int i=1;i+(1<<j)-1<=n;i++)
        
            dp[i][j]=max(dp[i][j-1],dp[i+(1<<j-1)][j-1]);//步进 
        
    
//  for(int i=0;i<=n;i++)
//  
//      for(int j=0;j<10;j++)
//      
//          cout<<dp[i][j]<<" ";
//      
//      cout<<endl;
//  
    while(m--)
    
        scanf("%d%d",&x,&y);
        int k=log2(y-x+1);//还原 
        printf("%d\n",max(dp[x][k],dp[y-(1<<k)+1][k]));
    
    return 0;

以上是关于RMQ-ST表 专题训练的主要内容,如果未能解决你的问题,请参考以下文章

《剑指offer》专题—算法训练 day02

Django ORM训练专题

Django ORM训练专题

图论专题训练 (更新中)

专题训练 1001 求全排列

数据并行:提升训练吞吐的高效方法 |深度学习分布式训练专题