数列区间最大值 (RMQ入门)
题目描述:
输入一串数字,然后再给你M个询问,每次询问给你两个数x,y,要求你说出从x到y这段区间内的最大数。
输入格式:
一个整数N表示数字的个数,一个数M,表示要询问的次数。
接下来一行为N个数。
接下来M行,每行都有两个整数x和y。
输出格式:
共M行,每行输出一个数。
样例输入:
10 2
3 2 4 5 6 8 1 2 9 7
1 4
3 8
样例输出:
5
8
提示:
1<=n<=100000,1<=m<=1000000
时间限制: 1000ms
空间限制: 256MB
正解我已经在网上找到了,但看不懂,说是倍增法,求解读……
#include<bits/stdc++.h>
using namespace std;
int n,m,f[100001][17],two[100001];
int query(int x,int y){
int i=two[y-x+1];
return max(f[x][i],f[y-(1<<i)+1][i]);
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>f[i][0];
for(int i=2;i<=n;i++){
if(i&i-1)two[i]=two[i-1];
else two[i]=two[i-1]+1;
}
for(int i=1;i<=two[n];i++){
for(int j=1;j+(1<<i)-1<=n;j++){
f[j][i]=max(f[j][i-1],f[j+(1<<i-1)][i-1]);
}
}
for(int i=1;i<=m;i++){
int x,y;
cin>>x>>y;
cout<<query(x,y)<<'\n';
}
return 0;
}
你去查一下st表
以下内容引用自GPT,有用望采纳:
这段代码是一个求区间最大值的问题,使用了ST表(Sparse Table)的算法来解决。让我详细解释一下。
首先,让我们来看一下代码的主要部分。
int n,m,f[100001][17],two[100001];
int query(int x,int y){
int i=two[y-x+1];
return max(f[x][i],f[y-(1<<i)+1][i]);
}
int main(){
// 输入n和m的值
cin>>n>>m;
// 输入数组f的元素
for(int i=1;i<=n;i++)cin>>f[i][0];
// 计算two数组
for(int i=2;i<=n;i++){
if(i&i-1)two[i]=two[i-1];
else two[i]=two[i-1]+1;
}
// 构建ST表
for(int i=1;i<=two[n];i++){
for(int j=1;j+(1<<i)-1<=n;j++){
f[j][i]=max(f[j][i-1],f[j+(1<<i-1)][i-1]);
}
}
// 进行查询并输出结果
for(int i=1;i<=m;i++){
int x,y;
cin>>x>>y;
cout<<query(x,y)<<'\n';
}
return 0;
}
让我们逐步分解这段代码的功能来解释它的作用:
声明了变量n和m,分别代表数组的大小和查询的次数。f
是一个二维数组,用于存储输入的数组元素。two
是一个辅助数组,用于计算最大二进制位数。
定义了一个名为query
的函数,用于查询指定区间的最大值。函数接受两个参数x和y,分别表示查询的区间的起始位置和结束位置。
在main
函数中,首先读取n和m的值。
然后,通过循环读取数组f
的元素。
接下来,使用一个for循环计算数组two
的数值。这里的two[i]
表示2的幂次方的最大整数。
然后,使用两个嵌套的for循环来构建ST表。外层循环控制区间的长度,内层循环用于遍历每个区间内的元素。
a. 在每个区间内,我们使用动态规划的思想,通过比较上一层区间的两个子区间的最大值,来更新当前区间的最大值。
最后,使用一个for循环进行查询操作。每次查询给定的区间,并调用query
函数返回最大值,并将结果输出。
非常抱歉中断了你的解释,让我继续解释接下来的代码部分。
在query
函数中,我们首先计算了区间的长度y - x + 1
。然后通过two
数组找到该长度对应的最大2的幂次方,保存在变量i
中。
最后,我们使用max
函数来比较两个位置的值,以获取区间内的最大值。具体来说,我们分别访问f[x][i]
和f[y - (1 << i) + 1][i]
两个位置上的值,然后返回其中较大的值。
这段代码实现了使用ST表进行区间最大值查询的功能。首先,我们通过两个嵌套的循环构建了一个ST表,用于保存每个区间内的最大值。然后,通过调用query
函数,可以快速地查询给定区间内的最大值。
需要注意的是,该代码中的数组索引从1开始,所以数组的大小是100001
而不是100000
。此外,函数query
中的二进制位操作(1 << i)
表示计算2的幂次方2^i
。
希望这次的解释能够帮助你更好地理解这段代码。如果你还有其他问题或需要进一步解释,请随时提问。祝你在学习C++的过程中取得进步!