RMQ 倍增法 求解读……

数列区间最大值 (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;
}

让我们逐步分解这段代码的功能来解释它的作用:

  1. 声明了变量n和m,分别代表数组的大小和查询的次数。f是一个二维数组,用于存储输入的数组元素。two是一个辅助数组,用于计算最大二进制位数。

  2. 定义了一个名为query的函数,用于查询指定区间的最大值。函数接受两个参数x和y,分别表示查询的区间的起始位置和结束位置。

  3. main函数中,首先读取n和m的值。

  4. 然后,通过循环读取数组f的元素。

  5. 接下来,使用一个for循环计算数组two的数值。这里的two[i]表示2的幂次方的最大整数。

  6. 然后,使用两个嵌套的for循环来构建ST表。外层循环控制区间的长度,内层循环用于遍历每个区间内的元素。

    a. 在每个区间内,我们使用动态规划的思想,通过比较上一层区间的两个子区间的最大值,来更新当前区间的最大值。

  7. 最后,使用一个for循环进行查询操作。每次查询给定的区间,并调用query函数返回最大值,并将结果输出。

非常抱歉中断了你的解释,让我继续解释接下来的代码部分。

  1. query函数中,我们首先计算了区间的长度y - x + 1。然后通过two数组找到该长度对应的最大2的幂次方,保存在变量i中。

  2. 最后,我们使用max函数来比较两个位置的值,以获取区间内的最大值。具体来说,我们分别访问f[x][i]f[y - (1 << i) + 1][i]两个位置上的值,然后返回其中较大的值。

这段代码实现了使用ST表进行区间最大值查询的功能。首先,我们通过两个嵌套的循环构建了一个ST表,用于保存每个区间内的最大值。然后,通过调用query函数,可以快速地查询给定区间内的最大值。

需要注意的是,该代码中的数组索引从1开始,所以数组的大小是100001而不是100000。此外,函数query中的二进制位操作(1 << i)表示计算2的幂次方2^i

希望这次的解释能够帮助你更好地理解这段代码。如果你还有其他问题或需要进一步解释,请随时提问。祝你在学习C++的过程中取得进步!