问题:
输入一串数字,给你 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
ST算法:ST算法是解决RMQ(区间最值)问题,它能在O(nlogn)的时间预处理,然后O(1)回答。其原理是倍增,h[i][j]表示从i位起的2^j个数中的最大数,即[i,i+2^j-1]中的最大值。
流程:h[i][0]表示从 i 开始到2^0个数之间中的最大值,只能是 a[i],故 h[i][0]=a[i]。
对于任意的 h[i][j],我们分成两段相等长度的数列来看,[ i , i+2^(j-1)-1] 和 [ i+2^(j-1) , i+2^j-1 ],分别对应 h[i][j-1] 和 h[i+(1<<j-1)][j-1]。遍历一遍之后直接求区间最大值即可。
例如 x 到 y 之间的最大值。
k=log2(y-x+1);//区间的长度
max(h[x][k],h[y-(1<<k)+1][k]);第1个区间:x 到 x+(1<<k)-1;第2个区间:y-(1<<k)+1到y。
可以代数尝试一下,推一下就明白了我代的数是x=2,y=20,k=4,也就是(2~17)和(5~20)这两个区间。
模板代码:
#include<stdio.h> #include<string.h> #include<math.h> #define N 100005 #include<algorithm> using namespace std; const int M=25; int h[N][M],a[N];//h[i][j]表示从i位起的2^j个数中的最大数 int main() { int n,m,x,y; scanf("%d%d",&n,&m); for(int i=1; i<=n; i++) { scanf("%d",&a[i]); h[i][0]=a[i];//h[i][0]表示[i,i]中的最大值,只能是a[i],故h[i][0]=a[i]。 } for(int j=1; j<=log2(n); j++) for(int i=1; i+(1<<j)-1<=n; i++)//注意i的右端点为i+(1<<j)-1,不能越界 h[i][j]=max(h[i][j-1],h[i+(1<<(j-1))][j-1]); for(int i=1; i<=m; i++) { scanf("%d%d",&x,&y); int k=log2(y-x+1); printf("%d\n",max(h[x][k],h[y-(1<<k)+1][k]));//第1个区间:x 到 x+(1<<k)-1;第2个区间:y-(1<<k)+1 到 y 。 //求出这两个的最大值即可 } return 0; }