数列区间最大值 LibreOJ - 10119RMQ (Range Minimum/Maximum Query)问题

输入一串数字,给你 MM 个询问,每次询问就给你两个数字 X,YX,Y,要求你说出 XX 到 YY 这段区间内的最大数。

Input

第一行两个整数 N,MN,M 表示数字的个数和要询问的次数; 
接下来一行为 NN 个数; 
接下来 MM 行,每行都有两个整数 X,YX,Y。

Output

输出共 MM 行,每行输出一个数。

Example

样例输入

10 2
3 2 4 5 6 8 1 2 9 7
1 4
3 8

样例输出

5
8

Hint

对于全部数据,1N105,1M106,1XYN1≤N≤105,1≤M≤106,1≤X≤Y≤N。数字不超过 C/C++ 的 int 范围。

主要方法及复杂度如下:
1、朴素(即搜索),O(n)-O(qn) online。
2、线段树,O(n)-O(qlogn) online。
3、ST(实质是动态规划),O(nlogn)-O(q) online。
ST算法(Sparse Table),以求最大值为例,设d[i,j]表示[i,i+2^j-1]这个区间内的最大值,那么在询问到[a,b]区间的最大值时答案就是max(d[a,k], d[b-2^k+1,k]),其中k是满足2^k<=b-a+1(即长度)的最大的k,即k=[ln(b-a+1)/ln(2)]。
d的求法可以用动态规划,d[i, j]=max(d[i, j-1],d[i+2^(j-1), j-1])。
4、RMQ标准算法:先规约成LCA(Lowest Common Ancestor),再规约成约束RMQ,O(n)-O(q) online。
首先根据原数列,建立笛卡尔树,从而将问题在线性时间内规约为LCA问题。LCA问题可以在线性时间内规约为约束RMQ,也就是数列中任意两个相邻的数的差都是+1或-1的RMQ问题。约束RMQ有O(n)-O(1)的在线解法,故整个算法的时间复杂度为O(n)-O(1)。
#include <bits/stdc++.h>
using namespace std;
inline int read(){
    char ch=getchar();int res=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar();
    return res*f;
}
inline void write(int zx){
    if(zx<0) zx=-zx,putchar('-');
    if(zx<10) putchar(zx+'0');
    else{
        write(zx/10);
        putchar(zx%10+'0');
    }
}
int n,m,a[100010],f[100010][20];
void ST(){
    for(int i=1;i<=n;i++) f[i][0]=a[i];
    for(int j=1;(1<<j)<=n;j++){
        for(int i=1;i+(1<<j)-1<=n;i++){
            f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
        }
    }
}
int RMQ(int l,int r){
    int k=0;
    while((1<<(k+1))<=r-l+1) k++;
    return max(f[l][k],f[r-(1<<k)+1][k]);
}
int main(){
    n=read();m=read();
    for(int i=1;i<=n;i++) a[i]=read();
    ST();
    for(int i=1;i<=m;i++){
        int l=read(),r=read();
        write(RMQ(l,r));
        putchar('\n');
    }
    return 0;
}

 

posted @ 2020-04-21 20:43  XXXSANS  阅读(318)  评论(0编辑  收藏  举报