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问题的解决方法,我们可以提高自己的编程能力和算法思维。

posted @ 2025-12-28 11:06  jtbg  阅读(1)  评论(0)    收藏  举报