题解:P3865 【模板】ST 表 && RMQ 问题
Xiaonao_Dali · · 题解
算法说明
这是一个非常经典的 ST 表问题。我们可以看到限制时间可知,这个模版题对我们的查询复杂度需要控制在
第一步-建表
第一步,建表,写 ST 表首先是要建表,根据题可知,他要求我们求的是区间最大值,那么我们需要建的是最大值的 ST 表。具体实现代码如下,时间复杂度是
第一步正确性说明
而在这里,需要一点点的正确性的证明:如果该区间长度为
建表步骤代码实现
void jb(){
for(int i=1;i<=n;i++) F[i][0]=a[i];
int k=log2(n);
for(int j=1;j<=k;j++){
for(int i=1;i<=n-(1<<j)+1;i++){
F[i][j]=max(F[i][j-1],F[i+(1<<(j-1))][j-1]);
}
}
}
第二步-查询
第二步,查询,我们可以通过一个公式去得出他的结果。我们可以知道他可以在 max(F[l][k],F[r-(1<<k)+1][k]); 进行一次求值。那么我们就需要考虑
证明
这里稍微证明了一下,我们在不断右移时知道仅剩下一位,那么右移次数即为答案,每次除以
查询步骤代码实现
int cx(int l,int r){
int k=log2(r-l+1);
return max(F[l][k],F[r-(1<<k)+1][k]);
}
整合代码
根据上述两步,那么我们可以得出下列代码,注意建表是需要把所有待处理的数输入好以后在进行建表。
#include<bits/stdc++.h>
using namespace std;
int n,m;
int F[100005][25];
int a[100005];
int x,y;
void jb(){
for(int i=1;i<=n;i++) F[i][0]=a[i];
int k=log2(n);
for(int j=1;j<=k;j++){
for(int i=1;i<=n-(1<<j)+1;i++){
F[i][j]=max(F[i][j-1],F[i+(1<<(j-1))][j-1]);
}
}
}
int cx(int l,int r){
int k=log2(r-l+1);
return max(F[l][k],F[r-(1<<k)+1][k]);
}
int main() {
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
jb();
for(int i=1;i<=m;i++){
cin>>x>>y;
cout<<cx(x,y)<<endl;
}
return 0;
}
快读
但可以那份发现超时了,具体请见链接,那么我们可以发现,我们没法在该算法上的时间复杂度进行优化,只能在输入输出进行优化,由于题目所给的函数不会用,所以我将使用如下
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
所以将这三行贴入那份代码,我们可以就可以通过本题了。务必要注意的是,需要在主函数的前三行去贴,才能保证每次输入均能被优化。这三行加入后,即可得到完美的正解。提示的已经很明显了。那么就可以得出如下代码。
AC 代码
#include<bits/stdc++.h>
using namespace std;
int n,m;
int F[100005][25];
int a[100005];
int x,y;
void jb(){
for(int i=1;i<=n;i++) F[i][0]=a[i];
int k=log2(n);
for(int j=1;j<=k;j++){
for(int i=1;i<=n-(1<<j)+1;i++){
F[i][j]=max(F[i][j-1],F[i+(1<<(j-1))][j-1]);
}
}
}
int cx(int l,int r){
int k=log2(r-l+1);
return max(F[l][k],F[r-(1<<k)+1][k]);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
jb();
for(int i=1;i<=m;i++){
cin>>x>>y;
cout<<cx(x,y)<<endl;
}
return 0;
}
ST 表补充说明
但是做 ST 表时,需要注意,就需要静态区间的,如果有变动,就非常占时间,因为动态可能导致数会发生变化,从而导致 ST 表需要重新建表,但因为题目说是静态区间的,所以可以使用 ST 表完成本题。