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表 专题训练的主要内容,如果未能解决你的问题,请参考以下文章