【题解】Acwing 1270 数列区间最大值

数列区间最大值

题目传送门

输入一串数字,给你 M 个询问,每次询问就给你两个数字 X,Y,
要求你说出 X 到 Y 这段区间内的最大数。

输入格式

第一行两个整数 N,M 表示数字的个数和要询问的次数;
接下来一行为 N 个数;
接下来 M 行,每行都有两个整数 X,Y。

输出格式

输出共 M 行,每行输出一个数。

数据范围

1 ≤ N ≤ 10^5,
1 ≤ M ≤ 10^6,
1 ≤ X ≤ Y ≤ N,
数列中的数字均不超过2^31 − 1

输入样例:

10 2
3 2 4 5 6 8 1 2 9 7
1 4
3 8

输出样例:

5
8

思路分析:

我就把它当作线段树的练习题了。

就是求区间最大值,所以我们开个结构体存下它的区间、区间的最大值就好了。

代码展示:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll; typedef unsigned long long ull;
struct Node {int l, r, dat;};

const int N = 5e5 + 10;
int n, m, op, x, y, v, a[N];
Node t[N << 2];

inline void build(int l, int r, int pos) {
	t[pos].l = l, t[pos].r = r;
	if(l == r) {t[pos].dat = a[l]; return;} // 找到叶节点了,叶结点最大值为自己
	int mid = l+r >> 1;
	build(l, mid, pos << 1), build(mid + 1, r, pos<<1 | 1); // 往下找叶结点
	t[pos].dat = max(t[pos << 1].dat, t[pos<<1 | 1].dat); // 子节点的最大值
}
inline void change(int x, int v, int pos) {
	if(t[pos].l == t[pos].r) { t[pos].dat = v; return;} // 找到要修改的点
	int mid = t[pos].l+t[pos].r >> 1;
	if(x <= mid) change(x, v, pos << 1); // 要修改的点在当前点的左区间 =号和我建树有关
	else change(x, v, pos<<1 | 1); // 要修改的点在当前点的右区间
	t[pos].dat = max(t[pos << 1].dat, t[pos<<1 | 1].dat); // 找到叶结点后向上更新
}
inline int query(int l, int r, int pos) {
	if(l <= t[pos].l && r >= t[pos].r) return t[pos].dat; // 当前点的区间完全在询问的区间中
	int mid = t[pos].l+t[pos].r >> 1;
	int val = -(1 << 30);
	if(l <= mid) val = max(val, query(l, r, pos << 1) ); // 当前点的区间在询问点的左区间的部分的最大值 = 上下的有无是与建树方式有关
	if(r > mid) val = max(val, query(l, r, pos<<1 | 1) ); // 当前点的区间在询问点的右区间的部分的最大值
	return val;
}
//
int main() {
	//freopen("data1.in","r",stdin);
	//freopen("data1.out","w",stdout);
	//ios::sync_with_stdio(false);
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
	build(1, n, 1); //建树
	for(int i = 0; i < m; i ++) {
		scanf("%d%d", &x, &y);
		if(x > y) swap(x, y); // 确保 x <= y
		printf("%d
", query(x, y, 1));
	}
	return 0;
}
原文地址:https://www.cnblogs.com/RemnantDreammm/p/14127855.html