码迷,mamicode.com
首页 > 其他好文 > 详细

RMQ-ST表 专题训练

时间:2019-07-29 00:05:11      阅读:129      评论:0      收藏:0      [点我收藏+]

标签:st表   维护   简介   如何   一个   efi   long   false   inf   

ST表简介

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

处理

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

查询

如何查询呢?
假设查询\([x,y]\)区间内的\(min/max\),则我们需要查询的是层数是\(k=\log_{2}{y-x+1}\)
有一个定理:$ 2^{\log_{2}{diff}}>diff/2 $,因为 $n/2 < \log_{x}{diff}<=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表 专题训练

标签:st表   维护   简介   如何   一个   efi   long   false   inf   

原文地址:https://www.cnblogs.com/tldr/p/11261351.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!