题目地址:
https://www.luogu.com.cn/problem/P2880
每天,农夫John的 n ( 1 ≤ n ≤ 5 × 1 0 4 ) n(1\le n\le 5\times 10^4) n(1≤n≤5×104)头牛总是按同一序列排队。有一天,John决定让一些牛们玩一场飞盘比赛。他准备找一群在队列中位置连续的牛来进行比赛。但是为了避免水平悬殊,牛的身高不应该相差太大。John准备了 q ( 1 ≤ q ≤ 1.8 × 1 0 5 ) q(1\le q\le 1.8\times10^5) q(1≤q≤1.8×105)个可能的牛的选择和所有牛的身高 h i ( 1 ≤ h i ≤ 1 0 6 , 1 ≤ i ≤ n ) h_i(1\le h_i\le 10^6,1\le i\le n) hi(1≤hi≤106,1≤i≤n)。他想知道每一组里面最高和最低的牛的身高差。
输入格式:
第一行两个数
n
,
q
n,q
n,q。
接下来
n
n
n行,每行一个数
h
i
h_i
hi。
再接下来
q
q
q行,每行两个整数
a
a
a和
b
b
b,表示询问第
a
a
a头牛到第
b
b
b头牛里的最高和最低的牛的身高差。
输出格式:
输出共
q
q
q行,对于每一组询问,输出每一组中最高和最低的牛的身高差。
RMQ问题,可以直接用ST表。倍增处理出 f [ i ] [ k ] = max { h i , . . . , h i + 2 k − 1 } f[i][k]=\max\{h_i,...,h_{i+2^k-1}\} f[i][k]=max{hi,...,hi+2k−1}和 g [ i ] [ k ] = min { h i , . . . , h i + 2 k − 1 } g[i][k]=\min\{h_i,...,h_{i+2^k-1}\} g[i][k]=min{hi,...,hi+2k−1},可以 O ( 1 ) O(1) O(1)时间内应答询问。代码如下:
#include <iostream>
#include <cmath>
using namespace std;
const int N = 5e4 + 10;
int n, q;
int f[N][30], g[N][30];
void init() {
for (int i = 1; i <= n; i++) g[i][0] = f[i][0];
for (int k = 1; k <= log2(n); k++)
for (int l = 1; l + (1 << k) - 1 <= n; l++) {
f[l][k] = max(f[l][k - 1], f[l + (1 << k - 1)][k - 1]);
g[l][k] = min(g[l][k - 1], g[l + (1 << k - 1)][k - 1]);
}
}
int query(int l, int r) {
int k = log2(r - l + 1);
return max(f[l][k], f[r - (1 << k) + 1][k]) - min(g[l][k], g[r - (1 << k) + 1][k]);
}
int main() {
scanf("%d%d", &n, &q);
for (int i = 1; i <= n; i++) scanf("%d", &f[i][0]);
init();
while (q--) {
int l, r;
scanf("%d%d", &l, &r);
printf("%d\n", query(l, r));
}
}
预处理时间复杂度 O ( n log n ) O(n\log n) O(nlogn),每次询问时间 O ( 1 ) O(1) O(1),空间 O ( n log n ) O(n\log n) O(nlogn)。