算法|题解

计蒜客 – 最甜的苹果

凝神长老 · 3月4日 · 2020年 · 765次已读

计蒜客 – 最甜的苹果

蒜头君有很多苹果,每个苹果都有对应的甜度值。

蒜头君现在想快速知道从第 $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;
}

更多线段树的题目

订阅评论动态
提醒
guest
0 评论
行内反馈
查看所有评论