P1816 忠诚

解题思路

这道题目要求我们处理多个区间最小值查询,属于典型的RMQ(Range Minimum Query)问题。题目中需要处理m笔账目和n个查询,每个查询要求找出[a, b]区间内的最小值。

方法选择

题目提供的代码使用了线段树解法,这是解决RMQ问题的经典方法之一。线段树的主要优势在于:

  1. 预处理时间O(n)

  2. 每个查询时间O(logn)

  3. 支持动态更新(虽然本题不需要)

对于n和m都是1e5的数据规模,线段树的O(n + mlogn)复杂度完全能够胜任。

其他可能的解法

  1. ST表(稀疏表):预处理O(nlogn),查询O(1),但不支持动态更新

  2. 单调队列:适用于滑动窗口最小值问题,但本题不是滑动窗口

  3. 分块处理:预处理O(n),查询O(√n),是线段树的简化版

代码注释

#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; // 定义常量,inf表示无穷大

// 线段树节点结构体
struct node{
    int maxx;  // 虽然变量名是maxx,但实际存储的是最小值
};

node t[N << 2];  // 线段树数组,大小是原数组的4倍
int n, m;        // n表示账目数量,m表示问题数量
int a[N];        // 存储账目金额的数组

// 更新父节点的值(取左右子树的最小值)
void pushup(int rt)
{
    t[rt].maxx = min(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 min(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;    // 查询区间[x,y]
        scanf("%d%d", &x, &y);  // 读取查询区间
        printf("%d ", query(1, 1, n, x, y));  // 查询并输出结果
    }
    return 0;
}

 

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