线段树 区间赋值 + 区间加减 + 求区间最值

这篇具有很好参考价值的文章主要介绍了线段树 区间赋值 + 区间加减 + 求区间最值。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

线段树好题:P1253 扶苏的问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

区间赋值 + 区间加减 + 求区间最大。

对于区间赋值和区间加减来说,需要两个懒标记,一个表示赋值cover,一个表示加减add

区间赋值的优先级大于区间加减。

对于区间赋值来说,需要将区间加减的标记重置,因为赋值完后,之前的区间加减队现在的值没有影响。

void coverdown(int u) {
    auto &root = tr[u], &right = tr[rs(u)], &left = tr[ls(u)];
    if(root.cover != -INF) {
        left.add = right.add = 0;
        left.ma = right.ma = root.cover;
        left.cover = right.cover = root.cover;
        root.cover = -INF;
    }
}

对于区间加减来说,需要先用区间赋值得到最新的值,之后再进行加减操作。

void sumdown(int u) {
    auto &root = tr[u], &right = tr[rs(u)], &left = tr[ls(u)];
    if(root.add) {
        coverdown(u);
        left.ma += root.add; right.ma += root.add;
        left.add += root.add; right.add += root.add;
        root.add = 0;
    }    
}

线段树中一般的pushdown的顺序不变,但是在pushdown函数中,需要先执行coverdown再执行sumdown。

void pushdown(int u) {
    coverdown(u); sumdown(u);
}

区间加减时,只需要先进行区间赋值就行。

void modify_add(int u, int l, int r, int d) {
    if(tr[u].l >= l && tr[u].r <= r) {
        coverdown(u);
        tr[u].ma += d;
        tr[u].add += d;
    }
    else {
        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        if(l <= mid) modify_add(ls(u), l ,r, d);
        if(r > mid) modify_add(rs(u), l, r, d);
        pushup(u);
    }
}

区间赋值时,需要先将区间加减懒标记重置,其他一样。

void modify_cover(int u, int l, int r, int d) {
    if(tr[u].l >= l && tr[u].r <= r) {
        tr[u].add = 0;
        tr[u].ma = d;
        tr[u].cover = d;
    } else {
        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        if(l <= mid) modify_cover(ls(u), l, r, d);
        if(r > mid) modify_cover(rs(u), l, r, d);
        pushup(u);
    }
}

AC代码:

#include <iostream>
#include <vector>
#include <string>
#include <cstring>
#include <set>
#include <map>
#include <queue>
#include <ctime>
#include <random>
#include <sstream>
#include <numeric>
#include <stdio.h>
#include <functional>
#include <bitset>
#include <algorithm>
using namespace std;

// #define Multiple_groups_of_examples
#define int_to_long_long
#define IOS std::cout.tie(0);std::cin.tie(0)->sync_with_stdio(false);
#define dbgnb(a) std::cout << #a << " = " << a << '\n';
#define dbgtt cout<<" !!!test!!! "<<endl;
#define rep(i,x,n) for(int i = x; i <= n; i++)

#define all(x) (x).begin(),(x).end()
#define pb push_back
#define vf first
#define vs second

typedef long long LL;
#ifdef int_to_long_long
#define int long long
#endif
typedef pair<int,int> PII;

const int INF = 1e18;
const int N = 1e6 + 21;


// 当输入数据大于 1e6 时用快读
inline int fread() // 快读
{
    int x = 0, f = 1; char ch = getchar();
    while(ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar(); }
    while(ch >= '0' && ch <= '9') {
        x = x * 10 + (ch - '0');
        ch = getchar();
    }
    return x * f;
}

int w[N],n,m; // 注意 w[N] 开LL ( https://www.luogu.com.cn/problem/P2357
struct adt {
    int l,r;
    int ma,add,cover;
}tr[N << 2];
// 左子树
inline int ls(int p) {return p<<1; }
// 右子树
inline int rs(int p) {return p<<1|1; }
// 向上更新
void pushup(int u) {
    tr[u].ma = max(tr[ls(u)].ma, tr[rs(u)].ma);
}

void coverdown(int u) {
    auto &root = tr[u], &right = tr[rs(u)], &left = tr[ls(u)];
    if(root.cover != -INF) {
        left.add = right.add = 0;
        left.ma = right.ma = root.cover;
        left.cover = right.cover = root.cover;
        root.cover = -INF;
    }
}
void sumdown(int u) {
    auto &root = tr[u], &right = tr[rs(u)], &left = tr[ls(u)];
    if(root.add) {
        coverdown(u);
        left.ma += root.add; right.ma += root.add;
        left.add += root.add; right.add += root.add;
        root.add = 0;
    }    
}
void pushdown(int u) {
    coverdown(u); sumdown(u);
}
// 建树
void build(int u, int l, int r) {
    if(l == r) tr[u] = {l, r, w[r], 0, -INF};
    else {
        tr[u] = {l,r, 0, 0, -INF}; // 容易忘
        int mid = l + r >> 1;
        build(ls(u), l, mid), build(rs(u), mid + 1, r);
        pushup(u);
    }
}
// 修改
void modify_add(int u, int l, int r, int d) {
    if(tr[u].l >= l && tr[u].r <= r) {
        coverdown(u);
        tr[u].ma += d;
        tr[u].add += d;
    }
    else {
        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        if(l <= mid) modify_add(ls(u), l ,r, d);
        if(r > mid) modify_add(rs(u), l, r, d);
        pushup(u);
    }
}
void modify_cover(int u, int l, int r, int d) {
    if(tr[u].l >= l && tr[u].r <= r) {
        tr[u].add = 0;
        tr[u].ma = d;
        tr[u].cover = d;
    } else {
        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        if(l <= mid) modify_cover(ls(u), l, r, d);
        if(r > mid) modify_cover(rs(u), l, r, d);
        pushup(u);
    }
}
// 查询
LL query(int u, int l, int r) {
    if(tr[u].l >= l && tr[u].r <= r) {
        return tr[u].ma;
    }
    pushdown(u);
    int mid = tr[u].l + tr[u].r >> 1;
    LL res = -INF;
    if(l <= mid) res = query(ls(u), l, r);
    if(r > mid ) res =max(res, query(rs(u), l, r));
    return res;
}

void inpfile();
void solve() {
    int n,q; cin>>n>>q;
    for(int i = 1; i <= n; ++i) w[i] = fread();
    build(1,1,n);
    while(q--) {
        // int opt,l,r,x; cin>>opt>>l>>r;
        int opt = fread(), l = fread(), r = fread();
        if(opt == 1) {
            // cin>>x;
            int x = fread();
            modify_cover(1,l,r,x);
        } else if(opt == 2) {
            // cin>>x;
            int x = fread();
            modify_add(1,l,r,x);
        } else {
            cout<<query(1,l,r)<<'\n';
        }
    }
}
#ifdef int_to_long_long
signed main()
#else
int main()
#endif

{
    #ifdef Multiple_groups_of_examples
    int T; cin>>T;
    while(T--)
    #endif
    solve();
    return 0;
}
void inpfile() {
    #define mytest
    #ifdef mytest
    freopen("ANSWER.txt", "w",stdout);
    #endif
}

记录详情 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

线段树 区间赋值 + 区间加减 + 求区间最值,算法题,c++,算法,数据结构

P1253 扶苏的问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)文章来源地址https://www.toymoban.com/news/detail-737930.html

到了这里,关于线段树 区间赋值 + 区间加减 + 求区间最值的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++数据结构稀疏矩阵运算(含加减乘及快速转置)

    题目: 内容:稀疏矩阵运算器 要求:使用三元组顺序表存储矩阵;实现矩阵的逆置、加、减、乘运算;具有相应的报错处理。 本人采用C++来书写该数据结构的题目,有兴趣的同学可以了解一下需要掌握一定的封装的能力。 类的结果存储如下所示: 加减法的函数内容如下所

    2023年04月10日
    浏览(28)
  • 【leetcode难题】2569. 更新数组后处理求和查询【线段树实现01翻转和区间求和模版】

    关键就是记录每次操作2时,nums1中的1的个数 这就需要实现线段树进行区间反转以及区间求和

    2024年02月15日
    浏览(32)
  • 数据结构:图文详解顺序表的各种操作(新增元素,查找元素,删除元素,给指定位置元素赋值)

      目录 一.顺序表的概念 二.顺序表的实现 新增元素 默认尾部新增 指定位置添加元素 查找元素 查找是否存在 查找元素对应的位置 查找指定位置对应的元素 删除元素 获取顺序表长度 清空顺序表 在线性数据结构中,我们一般分为俩类:顺序表和链表         顺序表是一

    2024年02月05日
    浏览(50)
  • 从数组中查找最值(三种基本算法)

    程序中,我们经常使用数组(列表)存储给定的线性序列(例如 {1,2,3,4}),那么如何查找数组(序列)中的最大值或者最小值呢? 所以这里简单提供了三种比较常见的算法来查找数组中的最值(这里以查找最大值为例) 普通算法 排序算法 分治算法 1)普通算法 普通算法的

    2024年02月07日
    浏览(28)
  • 数学建模--退火算法求解最值的Python实现

    目录 1.算法流程简介 2.算法核心代码 3.算法效果展示

    2024年02月09日
    浏览(26)
  • 基于Python实现的遗传算法求最值问题

    遗传算法求最值问题 目录 人工智能第三次实验报告 1 遗传算法求最值问题 1 一 、遗传算法 1 1.1 遗传算法简介 1 1.2 遗传算法基本要素 2 4. 设定遗传操作: 2 1.3 遗传算法一般步骤 2 二 、程序说明 2 2.1 控制参数 2 2.2 编码规则 3 2.3 选择初始群体 3 2.4 适应度函数 4 三 、参数测试

    2023年04月25日
    浏览(26)
  • 【算法】树状数组和线段树

    O ( l o g n ) O(logn) O ( l o g n ) :单点修改、区间查询 与前缀和的区别: 前缀和是离线的,每次动态修改原数组某个元素,都需要重新求一遍前缀和,因此单点修改是 O ( n ) O(n) O ( n ) 的,区间查询则是 O ( 1 ) O(1) O ( 1 ) 树状数组是在线的,单点修改和区间查询都是 O ( l o g n ) O(

    2024年02月19日
    浏览(35)
  • Segment Tree 线段树算法(java)

    什么是线段树算法: 线段树(Segment Tree)是一种基于树结构的数据结构,用于解决区间查询问题,例如区间最大值、最小值、区间和等。线段树是一种高度平衡的二叉树,每个节点都代表了一个区间。下面我们来详细了解一下线段树算法。 线段树的构建 线段树的构建过程可

    2024年02月16日
    浏览(29)
  • 算法41:掉落的方块(力扣699题)----线段树

    题目: https://leetcode.cn/problems/falling-squares/description/ 在二维平面上的 x 轴上,放置着一些方块。 给你一个二维整数数组  positions  ,其中  positions[i] = [lefti, sideLengthi]  表示:第  i  个方块边长为  sideLengthi  ,其左侧边与 x 轴上坐标点  lefti  对齐。 每个方块都从一个比目

    2024年02月22日
    浏览(33)
  • 一、基础算法9:区间合并 模板题+算法模板(区间合并)

    原题链接 https://www.acwing.com/problem/content/805/ 题目 803 . 区间合并 给定 n 个区间 [li,ri] ,要求合并所有有交集的区间。 注意如果在端点处相交,也算有交集。 输出合并完成后的区间个数。 例如:[1,3] 和 [2,6] 可以合并为一个区间 [1,6] 。 输入格式 第一行包含整数 n 。 接下来 n

    2024年02月04日
    浏览(25)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包