首页 > 其他分享 >p1253

p1253

时间:2025-01-16 16:04:09浏览次数:3  
标签:node lazy set p1253 int tree add

题目描述

给定一个长度为 nn 的序列 aa,要求支持如下三个操作:

  1. 给定区间 [l,r][l,r],将区间内每个数都修改为 xx。
  2. 给定区间 [l,r][l,r],将区间内每个数都加上 xx。
  3. 给定区间 [l,r][l,r],求区间内的最大值。

输入格式

第一行是两个整数,依次表示序列的长度 nn 和操作的个数 qq。
第二行有 nn 个整数,第 ii 个整数表示序列中的第 ii 个数 aiai​。
接下来 qq 行,每行表示一个操作。每行首先有一个整数 opop,表示操作的类型。

  • 若 op=1op=1,则接下来有三个整数 l,r,xl,r,x,表示将区间 [l,r][l,r] 内的每个数都修改为 xx。
  • 若 op=2op=2,则接下来有三个整数 l,r,xl,r,x,表示将区间 [l,r][l,r] 内的每个数都加上 xx。
  • 若 op=3op=3,则接下来有两个整数 l,rl,r,表示查询区间 [l,r][l,r] 内的最大值。

输出格式

对于每个 op=3op=3 的操作,输出一行一个整数表示答案。

输入输出样例

输入 #1复制

6 6
1 1 4 5 1 4
1 1 2 6
2 3 4 2
3 1 4
3 2 3
1 1 6 -1
3 1 6

输出 #1复制

7
6
-1

输入 #2复制

4 4
10 4 -3 -7
1 1 3 0
2 3 4 -4
1 2 4 -9
3 1 4

输出 #2复制

0

说明/提示

数据规模与约定

  • 对于 10%10% 的数据,n=q=1n=q=1。
  • 对于 40%40% 的数据,n,q≤103n,q≤103。
  • 对于 50%50% 的数据,0≤ai,x≤1040≤ai​,x≤104。
  • 对于 60%60% 的数据,op≠1op=1。
  • 对于 90%90% 的数据,n,q≤105n,q≤105。
  • 对于 100%100% 的数据,1≤n,q≤1061≤n,q≤106,1≤l,r≤n1≤l,r≤n,op∈{1,2,3}op∈{1,2,3},∣ai∣,∣x∣≤109∣ai​∣,∣x∣≤109。

提示

请注意大量数据读入对程序效率造成的影响。

#include <iostream>
#include <vector>
#include <algorithm>
#include <climits> // 包含 climits 头文件以使用 LLONG_MIN

using namespace std;

// 定义线段树节点结构体
struct Node {
    long long max_val;     // 当前区间的最大值
    long long lazy_set;    // 懒惰标记,表示区间内的所有元素都被设置为某个值(-1 表示无此操作)
    long long lazy_add;    // 懒惰标记,表示区间内的所有元素都加上某个值
};

// 线段树类
class SegmentTree {
public:
    int n;                 // 序列长度
    vector<Node> tree;     // 线段树数组

    // 构造函数,初始化线段树
    SegmentTree(int size) : n(size), tree(4 * size, Node{LLONG_MIN, -1, 0}) {}

    // 构建线段树
    void build(const vector<long long>& arr, int node, int start, int end) {
        if (start == end) {
            tree[node].max_val = arr[start]; // 叶子节点直接赋值
        } else {
            int mid = (start + end) / 2;
            build(arr, 2 * node, start, mid);       // 构建左子树
            build(arr, 2 * node + 1, mid + 1, end); // 构建右子树
            tree[node].max_val = max(tree[2 * node].max_val, tree[2 * node + 1].max_val); // 更新当前节点的最大值
        }
    }

    // 下推懒惰标记
    void push_down(int node, int start, int end) {
        if (tree[node].lazy_set != -1) {
            // 如果存在区间设置操作,将该操作应用到子节点
            tree[2 * node].max_val = tree[node].lazy_set;
            tree[2 * node + 1].max_val = tree[node].lazy_set;
            tree[2 * node].lazy_set = tree[node].lazy_set;
            tree[2 * node + 1].lazy_set = tree[node].lazy_set;
            tree[2 * node].lazy_add = 0;
            tree[2 * node + 1].lazy_add = 0;
            tree[node].lazy_set = -1; // 清除当前节点的设置标记
        }
        if (tree[node].lazy_add != 0) {
            // 如果存在区间加法操作,将该操作应用到子节点
            tree[2 * node].max_val += tree[node].lazy_add;
            tree[2 * node + 1].max_val += tree[node].lazy_add;
            if (tree[2 * node].lazy_set == -1)
                tree[2 * node].lazy_add += tree[node].lazy_add;
            else
                tree[2 * node].lazy_set += tree[node].lazy_add;
            if (tree[2 * node + 1].lazy_set == -1)
                tree[2 * node + 1].lazy_add += tree[node].lazy_add;
            else
                tree[2 * node + 1].lazy_set += tree[node].lazy_add;
            tree[node].lazy_add = 0; // 清除当前节点的加法标记
        }
    }

    // 区间设置操作
    void update_range_set(int l, int r, long long val, int node, int start, int end) {
        if (l > end || r < start) return; // 区间不相交,无需更新
        if (l <= start && end <= r) {
            // 当前区间完全包含于目标区间,进行设置操作
            tree[node].max_val = val;
            tree[node].lazy_set = val;
            tree[node].lazy_add = 0;
            return;
        }
        push_down(node, start, end); // 下推懒惰标记
        int mid = (start + end) / 2;
        update_range_set(l, r, val, 2 * node, start, mid);       // 更新左子树
        update_range_set(l, r, val, 2 * node + 1, mid + 1, end); // 更新右子树
        tree[node].max_val = max(tree[2 * node].max_val, tree[2 * node + 1].max_val); // 更新当前节点的最大值
    }

    // 区间加法操作
    void update_range_add(int l, int r, long long val, int node, int start, int end) {
        if (l > end || r < start) return; // 区间不相交,无需更新
        if (l <= start && end <= r) {
            // 当前区间完全包含于目标区间,进行加法操作
            tree[node].max_val += val;
            if (tree[node].lazy_set == -1)
                tree[node].lazy_add += val;
            else
                tree[node].lazy_set += val;
            return;
        }
        push_down(node, start, end); // 下推懒惰标记
        int mid = (start + end) / 2;
        update_range_add(l, r, val, 2 * node, start, mid);       // 更新左子树
        update_range_add(l, r, val, 2 * node + 1, mid + 1, end); // 更新右子树
        tree[node].max_val = max(tree[2 * node].max_val, tree[2 * node + 1].max_val); // 更新当前节点的最大值
    }

    // 区间查询最大值操作
    long long query_max(int l, int r, int node, int start, int end) {
        if (l > end || r < start) return LLONG_MIN; // 区间不相交,返回最小值
        if (l <= start && end <= r) return tree[node].max_val; // 当前区间完全包含于目标区间,返回最大值
        push_down(node, start, end); // 下推懒惰标记
        int mid = (start + end) / 2;
        long long left_max = query_max(l, r, 2 * node, start, mid);       // 查询左子树
        long long right_max = query_max(l, r, 2 * node + 1, mid + 1, end); // 查询右子树
        return max(left_max, right_max); // 返回左右子树的最大值
    }
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, q;
    cin >> n >> q;
    vector<long long> a(n);
    for (auto& x : a) cin >> x;

    SegmentTree st(n);
    st.build(a, 1, 0, n - 1); // 构建线段树

    while (q--) {
        int op, l, r;
        long long x;
        cin >> op >> l >> r;
        --l, --r; // 将索引转换为 0 基础
        if (op == 1) {
            cin >> x;
            st.update_range_set(l, r, x, 1, 0, n - 1); // 执行区间设置操作
        } else if (op == 2) {
            cin >> x;
            st.update_range_add(l, r, x, 1, 0, n - 1); // 执行区间加法操作
        } else if (op == 3) {
            cout << st.query_max(l, r, 1, 0, n - 1) << "\n"; // 执行区间查询最大值操作
        }
    }

    return 0;
}



标签:node,lazy,set,p1253,int,tree,add
From: https://blog.csdn.net/2402_86997774/article/details/145166933

相关文章

  • 洛谷题单指南-线段树-P1253 扶苏的问题
    原题链接:https://www.luogu.com.cn/problem/P1253题意解读:对于一个序列a[n],支持三种操作:1.将区间[l,r]所有数设置为x;2.将区间[l,r]所有数加上x;3.查询区间[l,r]的最大值解题思路:典型的线段树求解区间问题。线段树节点需要维护如下关键信息:1、区间l,r2、区间最大值v3、懒标记se......
  • 洛谷P1253 扶苏的问题(区间加值,区间修改,求区间max)
    题目Description给定一个长度为 nn 的序列 aa,要求支持如下三个操作:给定区间 [l,r][l,r],将区间内每个数都修改为 xx。给定区间 [l,r][l,r],将区间内每个数都加上 xx。给定区间 [l,r][l,r],求区间内的最大值。Input第一行是两个整数,依次表示序列的长度 nn 和操......
  • lgP1253 扶苏的问题
    给定长度为n的序列A,有如下3种操作:1lrx,将区间[l,r]中的每个数都修改为x。2lrx,将区间[l,r]中的每个数都加上x。3lr,查询区间[l,r]内的最大值。分析:设置2个懒标记,先处理赋值标记,再处理增加标记。#include<bits/stdc++.h>usingllong=longlong;constllonginf=......
  • 【线段树/懒标】-【LG】P1253 扶苏的问题
    \(\mathtt{TAGS}\):懒标线段树\(\mathtt{ESTIMATION}\):Tag*2题意实现:区间\(\max\)区间修改某个值区间加First.确定数据结构很显然,区间修改+区间查询所以——线段树。Second.LazyTag由于区间修改和区间加两个操作会互相干扰,所以对于每一个节点给两个Tag,一个......
  • P1253 扶苏的问题
    \(P1253\)一、题目描述给定一个长度为\(n\)的序列\(a\),要求支持如下三个操作:给定区间\([l,r]\),将区间内每个数都修改为\(x\)。给定区间\([l,r]\),将区间内每个数都加上\(x\)。给定区间\([l,r]\),求区间内的最大值。输入格式第一行是两个整数,依次表示序列的长度\(n\)和操......
  • P1253 扶苏的问题
    \(P1253\)扶苏的问题一、题目描述给定一个长度为\(n\)的序列\(a\),要求支持如下三个操作:给定区间\([l,r]\),将区间内每个数都修改为\(x\)。给定区间\([l,r]\),将区间内每个数都加上\(x\)。给定区间\([l,r]\),求区间内的最大值。输入格式第一行是两个整数,依次表示......
  • P1253 扶苏的问题
    link非常直白的线段树题目要注意负数的问题以及吮吸#include<iostream>#include<cstring>#include<cstdio>#defineintlonglongusingnamespacestd;inttree[8000002];intlazyre[8000002];intlazyad[8000002];intn,q;intop;intminn;intx,y,z;voidpushdow......