输入一串数字,给你 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
对于全部数据,1≤N≤105,1≤M≤106,1≤X≤Y≤N1≤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; }