P1531 I Hate It

解题思路

这道题目要求我们实现一个可以处理两种操作的数据结构:

  1. 查询操作(Q):查询区间[a,b]中的最大值

  2. 更新操作(U):有条件地更新某个位置的值(只有当新值大于原值时更新)

这是一个典型的区间查询与单点更新问题,适合使用线段树来解决。

方法选择

题目提供的代码使用了线段树解法,这是非常合适的选择,因为:

  1. 线段树可以高效处理区间查询(O(logn)时间)

  2. 支持单点更新(O(logn)时间)

  3. 对于n=2e5的数据规模完全适用

其他可能的解法

  1. 分块处理:将数组分成若干块,预处理每块的最大值

    • 查询时间O(√n)

    • 更新时间O(√n)

    • 实现比线段树简单,但效率较低

  2. ST表(稀疏表)

    • 查询时间O(1)

    • 但不支持高效更新,每次更新需要O(nlogn)重建

代码注释

#include<bits/stdc++.h>
#define lc rt << 1      // 左子节点索引
#define rc rt << 1 | 1  // 右子节点索引
#define lson lc,l,mid   // 左子树参数
#define rson rc,mid + 1,r // 右子树参数
#define ll long long 
using namespace std;

const int N = 2e6 + 10, inf = 0x3f3f3f3f;

// 线段树节点结构体
struct node{
    int maxx;  // 存储区间最大值
};

node t[N << 2];  // 线段树数组
int n, m;        // n-学生数量,m-操作数量
int a[N];        // 学生成绩数组

// 更新父节点的最大值
void pushup(int rt)
{
    t[rt].maxx = max(t[lc].maxx, t[rc].maxx);
}

// 构建线段树
void build(int rt, int l, int r)
{
    if(l == r) {  // 叶子节点
        t[rt].maxx = a[l];  // 存储单个学生的成绩
        return;
    }
    int mid = (l + r) / 2;  // 计算中点
    build(lson);  // 构建左子树
    build(rson);  // 构建右子树
    pushup(rt);   // 更新当前节点的最大值
}

// 单点更新函数
void change(int rt, int l, int r, int x, int y)
{
    if(r < x || x < l) return;  // 超出修改范围
    if(l == r){  // 找到目标位置
        t[rt].maxx = y;  // 更新成绩
        return;
    }
    int mid = (l + r) / 2;
    change(lson, x, y);  // 更新左子树
    change(rson, x, y);  // 更新右子树
    pushup(rt);          // 更新父节点的最大值
}

// 区间查询最大值
int query(int rt, int l, int r, int x, int y)
{
    if(r < x || y < l) return -inf;  // 区间无交集返回极小值
    if(x <= l && r <= y) return t[rt].maxx;  // 完全包含直接返回
    int mid = (l + r) / 2;
    // 返回左右子树查询结果的较大值
    return max(query(lson, x, y), query(rson, x, y));
}

int main()
{
    cin >> n >> m;  // 读取学生数量和操作数量
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);  // 读取初始成绩
    
    build(1, 1, n);  // 构建线段树
    
    while(m--)  // 处理每个操作
    {
        char op[2];  // 操作类型
        int x, y;    // 操作参数
        scanf("%s%d%d", op, &x, &y);  // 读取操作
        
        if(op[0] == 'Q'){  // 查询操作
            printf("%d\n", query(1, 1, n, x, y));
        }
        else if(op[0] == 'U' && a[x] < y)  // 更新操作(有条件)
        {
            a[x] = y;  // 更新原数组
            change(1, 1, n, x, a[x]);  // 更新线段树
        }
    }
    return 0;
}

 

posted @ 2025-05-21 09:33  CRt0729  阅读(14)  评论(0)    收藏  举报