P1253 扶苏的问题

扶苏的问题 - 线段树解法

解题思路

这道题需要处理三种区间操作:区间赋值、区间加法、区间最大值查询。线段树是解决这类区间操作问题的理想数据结构。

关键点分析:

  1. 双标记处理:同时存在赋值和加法两种操作,需要设计合理的标记处理顺序

  2. 标记优先级:赋值操作会覆盖之前的加法标记,但加法操作不会影响赋值标记

  3. 高效查询:需要维护区间最大值信息,支持快速查询

解决策略:

  • 使用线段树节点存储区间最大值、加法标记和赋值标记

  • 赋值操作时,清空加法标记

  • 下推标记时,先处理赋值标记再处理加法标记

  • 每次操作后维护区间最大值信息

代码注释

#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        // 定义long long类型别名
using namespace std;

const ll N = 1e6 + 10, inf = 1e18;

// 线段树节点结构体
struct node {
    ll maxx, k, lazy;      // maxx:区间最大值,k:赋值标记,lazy:加法标记
};

node t[N * 4];             // 线段树数组,4倍空间
ll n, m, a[N];             // n:序列长度,m:操作次数,a:原始数组

// 下推标记函数
void pushdown(int rt, int l, int r) {
    // 如果没有标记则直接返回
    if(t[rt].lazy == 0 && t[rt].k == -inf) return;
    
    // 优先处理赋值标记(优先级高于加法标记)
    if(t[rt].k != -inf) {
        t[lc].maxx = t[rc].maxx = t[rt].k;  // 更新左右子树最大值
        t[lc].lazy = t[rc].lazy = 0;        // 清空左右子树的加法标记
        t[lc].k = t[rc].k = t[rt].k;       // 设置左右子树的赋值标记
        t[rt].k = -inf;                     // 清空当前节点的赋值标记
    }
    
    // 处理加法标记
    if(t[rt].lazy != 0) {
        t[lc].maxx += t[rt].lazy;           // 左子树最大值增加
        t[rc].maxx += t[rt].lazy;           // 右子树最大值增加
        t[lc].lazy += t[rt].lazy;           // 左子树加法标记累加
        t[rc].lazy += t[rt].lazy;           // 右子树加法标记累加
        t[rt].lazy = 0;                     // 清空当前节点的加法标记
    }
}

// 上推信息函数
void pushup(int rt) {
    // 用左右子树的最大值更新当前节点的最大值
    t[rt].maxx = max(t[lc].maxx, t[rc].maxx);
}

// 构建线段树
void build(int rt, int l, int r) {
    t[rt].lazy = 0, t[rt].k = -inf;  // 初始化标记
    if(l == r) {                     // 叶子节点
        t[rt].maxx = a[l];           // 存储原始数组值
        return;
    }
    int mid = (l + r) / 2;
    build(lson);                     // 构建左子树
    build(rson);                     // 构建右子树
    pushup(rt);                      // 更新当前节点信息
}

// 区间加法操作
void add(int rt, int l, int r, int x, int y, int z) {
    if(r < x || y < l) return;       // 区间无交集
    if(x <= l && r <= y) {           // 当前区间完全包含在目标区间内
        t[rt].maxx += z;             // 更新区间最大值
        t[rt].lazy += z;             // 累加加法标记
        return;
    }
    pushdown(rt, l, r);              // 下推标记
    int mid = (l + r) / 2;
    add(lson, x, y, z);              // 更新左子树
    add(rson, x, y, z);              // 更新右子树
    pushup(rt);                      // 更新当前节点信息
}

// 区间赋值操作
void change(int rt, int l, int r, int x, int y, int z) {
    if(r < x || y < l) return;       // 区间无交集
    if(x <= l && r <= y) {           // 当前区间完全包含在目标区间内
        t[rt].maxx = z;              // 更新区间最大值
        t[rt].lazy = 0;              // 清空加法标记(赋值操作优先级更高)
        t[rt].k = z;                 // 设置赋值标记
        return;
    }
    pushdown(rt, l, r);              // 下推标记
    int mid = (l + r) / 2;
    change(lson, x, y, z);           // 更新左子树
    change(rson, x, y, z);           // 更新右子树
    pushup(rt);                      // 更新当前节点信息
}

// 区间最大值查询
ll 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;  // 直接返回区间最大值
    pushdown(rt, l, r);              // 下推标记
    int mid = (l + r) / 2;
    // 返回左右子树查询结果的较大值
    return max(query(lson, x, y), query(rson, x, y));
}

int main() {
    scanf("%lld%lld", &n, &m);       // 读取序列长度和操作次数
    for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);  // 读取初始序列
    build(1, 1, n);                  // 构建线段树
    
    while(m--) {
        int op, x, y, z;
        scanf("%d", &op);            // 读取操作类型
        if(op == 1) {                // 区间赋值操作
            scanf("%d%d%d", &x, &y, &z);
            change(1, 1, n, x, y, z);
        }
        else if(op == 2) {           // 区间加法操作
            scanf("%d%d%d", &x, &y, &z);
            add(1, 1, n, x, y, z);
        }
        else if(op == 3) {           // 区间最大值查询
            scanf("%d%d", &x, &y);
            ll ans = query(1, 1, n, x, y);
            printf("%lld\n", ans);
        }
    }
    return 0;
}

 

posted @ 2025-05-27 15:14  CRt0729  阅读(29)  评论(0)    收藏  举报