计蒜客 – 最甜的苹果
蒜头君有很多苹果,每个苹果都有对应的甜度值。
蒜头君现在想快速知道从第 $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; }
更多线段树的题目
太棒了!