RMQ问题细解
RMQ的介绍
RMQ(Range Minimum/Maximum Query) 问题是一种常见的数据结构问题,它涉及查询一个数组中某个区间的最小值或最大值。这个问题在很多场景中都非常有用,比如在处理最优化问题或者数据分析时。在解决 RMQ 问题时,通常会涉及到一些预处理技术和高效的查询方法。 基本概念和方法 在处理 RMQ 问题时,我们通常会遇到两个主要的操作:预处理和查询。预处理是指对原始数据进行一些计算和存储,以便于后续能够快速回答查询请求。查询则是指在预处理的基础上,快速找到指定区间内的最小值或最大值。 预处理方法 单调栈:单调栈是一种特殊的栈结构,它可以在 \(O(n)\) 的时间复杂度内完成预处理。单调栈的主要思想是维护一个元素单调递增或递减的栈,这样可以快速找到每个元素的前驱和后继,从而解决一些区间最值问题。
RMQ算法
维护一个数组\(f[maxn][log2(maxn)]\), \(f[i][j]\) 表示从第i个数起连续 \(2^j\) 个数中的最值(最大或最小值),状态转移方程为 f[i][j]=max/min(f[i][j-1],f[i+(1<<j-1)][j-1])(\(2^i\)可以表示为1<<i) 。
当查询 \(s\) 到 \(t\) 这一段的最值时,先求出一个最大的 \(k\) ,使得 \(k\) 满足 \(2^ k<=(t−s+1)\) ,于是我们就可以把 \([s,t]\) 分成 \([s,s+2^k−1],[t−2^k+1,t]\)。
例题1
题目
【题目描述】
输入一串数字,给你 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≤10^5 , 1≤M≤10^6 , 1≤X≤Y≤N。数字不超过 C/C++ 的 int 范围。
代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+5,LN=20;
int l[N],f[N][LN+5],a[N];
int n,m,x,y;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i]);
}
l[0]=-1; //l->log 只有log[0]=-1,log[1]才是0
for(int i=1;i<=n;++i)
{
f[i][0]=a[i];
l[i]=l[i>>1]+1;//预处理1~n的log值 (log2)
}
for(int j=1;j<=LN;++j)
{
for(int i=1;i+(1<<j)-1<=n;++i)//注意边界不能超过n
{
f[i][j]=max(f[i][j-1],f[i+(1<<j-1)][j-1]);//状态转移方程
//2^i == 1<<i
}
}
while(m--)
{
scanf("%d%d",&x,&y);//求a[x]~a[y]之间的最大值
int s=l[y-x+1];//求log2(y-x+1)
printf("%d\n",max(f[x][s],f[y-(1<<s)+1][s]));
}
return 0;
}
RMQ应用示例
RMQ问题在实际应用中非常广泛,比如在编程竞赛、算法设计和软件开发中都有它的身影。通过理解和掌握RMQ问题的解决方法,可以帮助我们更好地处理复杂的数据结构问题,并提高算法的效率和性能。 总的来说,RMQ问题是数据结构领域的一个基础问题,它不仅涉及到算法的设计和实现,还涉及到数据结构的选择和优化。通过学习和实践RMQ问题的解决方法,我们可以提高自己的编程能力和算法思维。
本文来自博客园,作者:jtbg,转载请注明原文链接:https://www.cnblogs.com/jtbg/articles/19411276
博客最新公告
浙公网安备 33010602011771号