题目大意:
给定一个长度为 N 的序列,和 M 次询问,每次询问求
区间的最大值。
Input
8 8 9 3 1 7 5 6 0 8 1 6 1 5 2 7 2 6 1 8 4 8 3 7 1 8
Output
9 9 7 7 9 8 7 9
解题思路 :
此题是最经典的 RMQ (区间最值问题),于是可以通过ST表这种强有力的工具来实现。
如何求解RMQ:
ST表,可以用ST[i][j]来表示:
从i开始,一共
个元素中的最值。
其实相当于是动态规划的状态。
那么状态转移方程可以采纳分治的思想,分成两个更小的区间。
查询的时候也比较简单,我们直接计算出区间长度。
这样可以保证一定可以覆盖查询的区间。
刚开始学的时候我不太理解为什么从右端点开始查的时候左端点是 ,实际上就是因为我们需要找到一个点
,使得
。
Code:
#include <bits/stdc++.h>
typedef long long ll;
#define INF 0x7f7f7f7f
using namespace std;
inline int read() {
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
int ST[100010][30];
inline void RMQ(int n) {
for (int i = 1; i <= n; i++) {
ST[i][0] = read();
}
for (int P = 1; P <= 21; P++) {
for (int i = 1; i + (1 << P) <= n + 1; i++) {
ST[i][P] = max(ST[i][P - 1], ST[i + (1 << (P - 1))][P - 1]);
}
}
}
int main() {
int n = read(), m = read();
RMQ(n);
while (m--) {
int l = read(), r = read();
int lg = log2(r - l + 1);
cout << max(ST[l][lg], ST[r - (1 << lg) + 1][lg]) << "\n";
}
return 0;
}