本题要求处理多个区间查询,每次查询需要快速得到区间内最大值与最小值的差值。由于数据规模较大(n ≤ 5×10⁴, q ≤ 1.8×10⁵),需要使用高效的区间查询算法。这里采用 ST表(Sparse Table) 算法,其特点是在 O(n log n) 时间内预处理,之后每个查询可在 O(1) 时间内完成,非常适合本题的多次查询需求。
ST表原理
ST表的核心思想是倍增和动态规划:
- 预处理:构建两个二维数组
max_st和min_st,其中:max_st[k][i]表示区间[i, i + 2ᵏ - 1]中的最大值。min_st[k][i]表示区间[i, i + 2ᵏ - 1]中的最小值。
- 状态转移方程:
max_st[k][i] = max(max_st[k-1][i], max_st[k-1][i + 2^{k-1}])min_st[k][i] = min(min_st[k-1][i], min_st[k-1][i + 2^{k-1}])
- 查询:对于区间
[l, r],令k = floor(log2(r - l + 1)),则:- 最大值 =
max(max_st[k][l], max_st[k][r - 2^k + 1]) - 最小值 =
min(min_st[k][l], min_st[k][r - 2^k + 1]) - 答案 = 最大值 - 最小值
- 最大值 =
步骤
- 输入处理:
- 读取牛的数量
n和查询次数q。 - 读取每头牛的身高
h[1..n]。
- 读取牛的数量
- 预处理 log2 数组:
- 构建数组
log_table,其中log_table[i] = floor(log2(i)),用于快速计算区间长度对应的k值。
- 构建数组
- 构建ST表:
- 初始化
k=0时的ST表(即单个元素)。 - 递推计算
k=1到k_max(k_max = log_table[n])的ST表。
- 初始化
- 处理查询:
- 对于每个查询
[a, b],调整区间为[l, r](l = min(a, b),r = max(a, b))。 - 计算
k = log_table[r - l + 1]。 - 通过ST表查询区间最大值和最小值,输出差值。
- 对于每个查询
复杂度分析
- 预处理:O(n log n),其中
log n ≈ 16(n=50000 时)。 - 查询:O(1) 每次,总 O(q)。
- 总复杂度:O(n log n + q),可高效处理最大规模数据。
代码实现
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
const int MAXN = 50010;
const int MAXK = 17; // 2^16 = 65536 > 50000
int n, q;
int h[MAXN];
int log_table[MAXN];
int max_st[MAXK][MAXN];
int min_st[MAXK][MAXN];
void build_st() {
// 初始化 k=0
for (int i = 1; i <= n; i++) {
max_st[0][i] = h[i];
min_st[0][i] = h[i];
}
// 预处理 log_table
log_table[1] = 0;
for (int i = 2; i <= n; i++) {
log_table[i] = log_table[i / 2] + 1;
}
int k_max = log_table[n];
// 递推构建ST表
for (int k = 1; k <= k_max; k++) {
int step = 1 << (k - 1); // 2^(k-1)
for (int i = 1; i + (1 << k) - 1 <= n; i++) {
max_st[k][i] = max(max_st[k - 1][i], max_st[k - 1][i + step]);
min_st[k][i] = min(min_st[k - 1][i], min_st[k - 1][i + step]);
}
}
}
int query(int l, int r) {
int len = r - l + 1;
int k = log_table[len];
int max_val = max(max_st[k][l], max_st[k][r - (1 << k) + 1]);
int min_val = min(min_st[k][l], min_st[k][r - (1 << k) + 1]);
return max_val - min_val;
}
int main() {
scanf("%d %d", &n, &q);
for (int i = 1; i <= n; i++) {
scanf("%d", &h[i]);
}
build_st();
while (q--) {
int a, b;
scanf("%d %d", &a, &b);
int l = min(a, b);
int r = max(a, b);
printf("%d\n", query(l, r));
}
return 0;
}

京公网安备 11010502036488号