農夫約翰有 N (≤ 50,000) 隻奶牛按固定順序排隊。他有 Q (≤ 200,000) 個詢問,每個詢問給出區間 [A, B],要求輸出該區間內最高與最矮奶牛的身高差。身高範圍 1~1,000,000。
經典的區間最值查詢問題。線段樹每個節點存儲該區間的 Min 與 Max。查詢時合併左右子區間的最值,最終得到整個查詢區間的最值,相減即為答案。
struct Node { int Min, Max; } tree[4 * MAXN];
int height[MAXN];
void build(int node, int l, int r) {
if (l == r) {
tree[node].Min = tree[node].Max = height[l];
return;
}
int mid = (l + r) >> 1;
build(node<<1, l, mid);
build(node<<1|1, mid+1, r);
tree[node].Min = min(tree[node<<1].Min, tree[node<<1|1].Min);
tree[node].Max = max(tree[node<<1].Max, tree[node<<1|1].Max);
}
// flag=0 查最小值,flag=1 查最大值
int query(int node, int l, int r, int ql, int qr, int flag) {
if (qr < l || r < ql) return flag ? -1 : INF;
if (ql <= l && r <= qr) return flag ? tree[node].Max : tree[node].Min;
int mid = (l + r) >> 1;
int left = query(node<<1, l, mid, ql, qr, flag);
int right = query(node<<1|1, mid+1, r, ql, qr, flag);
return flag ? max(left, right) : min(left, right);
}
int main() {
int n, q;
while (~scanf("%d%d", &n, &q)) {
for (int i = 1; i <= n; ++i) scanf("%d", &height[i]);
build(1, 1, n);
while (q--) {
int a, b; scanf("%d%d", &a, &b);
int mx = query(1, 1, n, a, b, 1);
int mn = query(1, 1, n, a, b, 0);
printf("%d\n", mx - mn);
}
}
return 0;
}
scanf/printf 或快速 IO。POJ 3264 是線段樹維護區間最值的入門經典題。掌握「節點存什麼、怎麼合併、怎麼查詢」三步曲,即可輕鬆解決大多數區間最值/求和/區間最值差問題。