计蒜客 – 最甜的苹果
蒜头君有很多苹果,每个苹果都有对应的甜度值。
蒜头君现在想快速知道从第 $i$ 个苹果到第 $j$ 个苹果中,最甜的甜度值是多少。
因为存放时间久了,有的苹果会变甜,有的苹果会因为腐烂而变得不甜,所以蒜头君有时候还需要修改第 $i$ 个苹果的甜度值。
输入格式
第一行输入两个正整数 $N,M (0 < N \leq 200000, 0 < M < 5000)$,分别代表苹果的个数和蒜头君要进行的操作的数目。
每个苹果从 $1$ 到 $N$ 进行编号。
接下来一行共有 $N$ 个整数,分别代表这 $N$ 个苹果的初始甜度值。
接下来 $M$ 行。每一行有一个字符 $C$,和两个正整数 $X$,$Y$。
当 $C$ 为 Q 的时候,你需要输出从 $X$ 到 $Y$(包括 $X$, $Y$)的苹果当中,甜度值最高的苹果的甜度值。
当 $C$ 为 U 的时候,你需要把苹果 $X$ 的甜度值更改为 $Y$。
5 6 1 2 3 4 5 Q 1 5 U 3 6 Q 3 4 Q 4 5 U 2 9 Q 1 5
输出格式
在一行里面输出每次询问的最高甜度值。
5 6 5 9
对模板稍作变形。
在修改操作的最后,将 s[p] 的值修改为两个孩子的最大值。
s[p] = max(s[p * 2], s[p * 2 + 1]);
在查询过程中,始终以最大值作为结果。
if (x <= mid) res = max(res, query(p * 2, l, mid, x, y)); if (y > mid) res = max(res, query(p * 2 + 1, mid + 1, r, x, y));
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 200000 * 3 + 7; // 由于还要 2 倍的父节点,所以乘以 3
int s[MAX_N] = {0};
int n = 0, m = 0;
// 修改
void modify(int p, int l, int r, int x, int v)
{
s[p] = v;
if (l == r) return; // 叶结点则退出
int mid = (l + r) / 2;
if (x <= mid) // 判断 x 在左儿子还是右儿子
modify(p * 2, l, mid, x, v);
else
modify(p * 2 + 1, mid + 1, r, x, v);
s[p] = max(s[p * 2], s[p * 2 + 1]);
}
// 封装后的修改,以供调用
void modify(int x, int v) {
modify(1, 1, n, x, v);
}
// 查询
int query(int p, int l, int r, int x, int y)
{
if (x <= l && r <= y) return s[p]; // 若该结点被查询区间包含
int mid = (l + r) / 2, res = 0;
if (x <= mid) res = max(res, query(p * 2, l, mid, x, y));
if (y > mid) res = max(res, query(p * 2 + 1, mid + 1, r, x, y));
return res;
}
// 封装后的查询,以供调用
int query(int x, int y) {
return query(1, 1, n, x, y);
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
int v;
scanf("%d", &v);
modify(i, v);
}
for (int i = 0; i < m; i++) {
char c;
scanf("\n%c", &c);
int x, y;
scanf("%d%d", &x, &y);
switch (c) {
case 'Q':
printf("%d\n", query(x, y));
break;
case 'U':
modify(x, y);
break;
default:
break;
}
}
return 0;
}
更多线段树的题目

太棒了!