数列区间最大值
输入一串数字,给你 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;
}