rmq问题:
先贴一下定义
范围最值查询
范围最值查询(Range Minimum Query),是针对数据集的一种条件查询。若给定一个数组 A[1, n],范围最值查询指定一个范围条件 i 到 j,要求取出 A[i, j] 中最大/小的元素。
若 A = [3, 5, 2, 5, 4, 3, 1, 6, 3],条件为 [3, 8] 的范围最值查询返回 1,它是子数组 A[3, 8] = [2, 5, 4, 3, 1, 6]中最小的元素。
通常情况下,数组 A 是静态的,即元素不会变化,例如插入、删除和修改等,而所有的查询是以在线的方式给出的,即预先并不知道所有查询的参数。
RMQ 问题有预处理 O ( n ) {\displaystyle O(n)} 之后每次查询 O ( 1 ) {\displaystyle O(1)} 的算法[1]。
范围最值查询问题(RMQ)与最近公共祖先 (图论)(LCA)问题有直接联系,它们可以互相转化。RMQ 的算法常常应用在严格或者近似子串匹配等问题的处理中。
暴力的去查询,期望复杂度是O(N)查询,O(N)处理
用线段树维护,期望复杂度O(logN)查询,O(N)处理
当然还有更优秀的ST算法(稀疏表算法)
----以上均转自维基百科
相对比线段树维护,st算法可以做到O(1)回答,复杂度有了不少的优化
#pragma GCC optimize("O2")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<limits.h>
#include<ctime>
#define N 100001
typedef long long ll;
const int inf=0x3fffffff;
const int maxn=2017;
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch>'9'|ch<'0')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0')
{
x=(x<<3)+(x<<1)+ch-'0';
ch=getchar();
}
return f*x;
}
int rmq[30][N],lg[N];
void init(int n)
{
for(int i=2;i<=n;i++)
lg[i]=lg[i>>1]+1;
for(int i=1;i<=lg[n];i++)
for(int j=1;j<=n+1-(1<<i);j++)
rmq[i][j]=min(rmq[i-1][j],rmq[i-1][j+(1<<(i-1))]);
}
int rminq(int l,int r)
{
if(l>r)swap(l,r);
int x=lg[r-l+1];
return min(rmq[x][l],rmq[x][r+1-(1<<x)]);
}
int main()
{
int n=read(),m=read();
for(int i=1;i<=n;i++)
rmq[0][i]=read();
for(int i=1;i<=m;i++)
{
int l=read(),r=read();
printf("%d\n",rminq(l,r));
}
}
O ( N l o g N + Q ) {\displaystyle O(NlogN+Q)} ,Q 为查询数。