245. 你能回答这些问题吗——线段树

news2024/12/23 2:19:01

给定长度为 N 的数列 A,以及 M 条指令,每条指令可能是以下两种之一:

1 x y,查询区间 [x,y] 中的最大连续子段和,在这里插入图片描述

2 x y,把 A[x] 改成 y。
对于每个查询指令,输出一个整数表示答案。

输入格式
第一行两个整数 N,M。

第二行 N 个整数 A[i]。

接下来 M 行每行 3 个整数 k,x,y,k=1 表示查询(此时如果 x>y,请交换 x,y),k=2 表示修改。

输出格式
对于每个查询指令输出一个整数表示答案。

每个答案占一行。

数据范围
N≤500000,M≤100000,
−1000≤A[i]≤1000
输入样例:
5 3
1 2 -3 4 5
1 2 3
2 2 -1
1 3 2
输出样例:
2
-1

分析

  1. 首先此题是单点修改,区间查询问题,只需要pushup函数即可,然后分析所查询的是最大连续字段和tmax,想求根节点的tmax,分三种情况:①tmax仅在分界线左边取得,那么根节点的u.tmax直接等于左儿子的tmax即可;②tmax仅在分界线右边取得,那么根节点的u.tmax直接等于右儿子的tmax即可;③根节点的tmax跨越分界线(横跨区间),那么u.tmax由左儿子的最大后缀和t[l].rmax + 右儿子的最大前缀和组成t[r].lmax;(最大后缀和:以区间右端点为终点,方向向左的最大后缀和;最大前缀和:以区间做左端点开始,方向向右的最大前缀和)每个结点(包括每一个儿子)都有lmax,rmax; 所以根节点的tmax就是上面三种情况的max值;

在这里插入图片描述

  1. 想求tmax,用到了lmax,rmax,然后求得了tmax,那么如何求lmax,rmax,那么看下图;对于根节点来说,lmax分为两种情况:①从区间左端点开始,没越过分界线结束,那么根节点的lmax = 左儿子的lmax;②从区间左端点开始,越过分界线,那么根节点的lmax=左儿子的区间和(t[l].sum)+ 右儿子的最大前缀和(t[r].lmax);所以根节点的lmax取值为上面两种情况的max值;
    同理rmax的求法一样,也是上面两种情况,可以得到下图的结论;

在这里插入图片描述
3. 上面求lmax,rmax用到的sum怎么求呢,直接由左儿子、右儿子的sum加起来就行;
在这里插入图片描述
4. 那么通过上面3条对根节点的分析,可以求得tmax,那对于根的左儿子,他也算一个根,同样的做法来求,递归进行即可;
5. 这题由于有用于建立线段树的初始数组a,所以建树时候要注意初始化叶子结点,并且要pushup一下父节点,凡是修改了叶子结点,包括赋值,都要顺带给父亲更新一下;然后推荐一个大佬的讲解,讲的非常好:AcWing 245. 你能回答这些问题吗(线段树)

分析

#include <bits/stdc++.h>

using namespace std;

const int N = 500010;
struct node {
    int l, r;
    int tmax; //最大连续子段和
    int lmax; //最大前缀和(从区间左端点出发)
    int rmax; //最大后缀和(从区间右端点出发)
    int sum; //区间和
};
int n, m;
int a[N];
node t[4 * N];

void pushup(node &u, node &l, node &r) {
    //根据上面推导的结论求u的 tmax,lmax,rmax,sum
    u.tmax = max(max(l.tmax, r.tmax), l.rmax + r.lmax);
    u.lmax = max(l.lmax, l.sum + r.lmax);
    u.rmax = max(r.rmax, r.sum + l.rmax);
    u.sum = l.sum + r.sum;
}

//儿子结点向上更新父亲结点
void pushup(int u) {
    pushup(t[u], t[u << 1], t[u << 1 | 1]);
}

void build(int u, int l, int r) {
    t[u].l = l, t[u].r = r;
    //到叶子结点了
    if (l == r) {
        //本题有用于建立线段树的初始数组a,所以这里需要赋个值,对于单一一个点,这几个值相等
        t[u].tmax = t[u].lmax = t[u].rmax = t[u].sum = a[l];
        return;
    }
    int mid = l + r >> 1;
    build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
    //本题有用于建立线段树的初始数组a,所以需要更新下父亲
    pushup(u);
}

void modify(int u, int x, int v) {
    //找到叶子结点
    if (t[u].l == t[u].r) {
        t[u].tmax = t[u].lmax = t[u].rmax = t[u].sum = v;
        return;
    }
    //找叶子结点
    int mid = t[u].l + t[u].r >> 1;
    if (x <= mid)
        modify(u << 1, x, v);
    else
        modify(u << 1 | 1, x, v);
    //更新父亲(凡是修改了叶子结点,包括赋值,都要顺带给父亲更新一下)
    pushup(u);
}

node query(int u, int l, int r) {
    //1. [l,r]完全包含 u 的左右区间
    if (l <= t[u].l && r >= t[u].r)
        return t[u];
    int mid = t[u].l + t[u].r >> 1;
    //2. [l,r]完全在u的左儿子
    if (r <= mid)
        return query(u << 1, l, r);
        //3. [l,r]完全在u的右孩子
    else if (l >= mid + 1)
        return query(u << 1 | 1, l, r);
        //4. [l,r]横跨分界线(左右两边都有)
    else {
        auto left = query(u << 1, l, r);
        auto right = query(u << 1 | 1, l, r);
        node res;
        //计算res的tmax
        pushup(res, left, right);
        return res;
    }
}

int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
    }
    build(1, 1, n);
    while (m--) {
        int k, x, y;
        cin >> k >> x >> y;
        if (k == 1) {
            if (x > y)
                swap(x, y);
            cout << query(1, x, y).tmax << endl;
        } else {
            modify(1, x, y);
        }
    }
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/113934.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RabbitMQ 第二天 高级 9 RabbitMQ 集群搭建 9.3 集群管理 9.5 负载均衡-HAProxy

RabbitMQ 【黑马程序员RabbitMQ全套教程&#xff0c;rabbitmq消息中间件到实战】 文章目录RabbitMQ第二天 高级9 RabbitMQ 集群搭建9.3 集群管理9.5 负载均衡-HAProxy9.5.1 安装HAProxy9.5.2 配置HAProxy第二天 高级 9 RabbitMQ 集群搭建 9.3 集群管理 rabbitmqctl join_cl…

MariaDB上市:MySQL之父奋斗13年终敲钟 要写代码写到100岁

雷递网 雷建平 12月24日云数据库公司MariaDB日前与特殊目的公司Angel Pond Holdings完成合并&#xff0c;并在纽交所上市&#xff0c;新公司更名为MariaDB。MariaDB是2022年初与Angel Pond Holdings达成合并协议&#xff0c;对新公司的作价为6.72亿美元。MariaDB是MySQL之父Mic…

【技术应用】java基于UNIX域套接字(unix domain socket)连接redis

【技术应用】java基于UNIX域套接字unix domain socket连接redis一、前言二、实现思路三、代码实现1、java socket基于redis.sock连接redis2、Lettuce框架基于redis.sock连接redis一、前言 在公司工作中经常涉及到一些中小型项目&#xff0c;这些项目都会涉及使用redis数据库&a…

Redis5.0+——持久化——RDBAOF

Redis持久化-RDB 1.实现目标&#xff1a; 在redis持久化时&#xff0c;持久化dump.rdb文件放入到redis解压目录下的data目录下的6379目录下 2.前期准备 1.在redis-5.0.3解压目录下新建data数据目录 2.编辑前面配置的/etc/redis.conf配置文件 修改持久化文件位置 (1) 进入安…

MySQL热备之PXB备份与恢复

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&#x1f61…

【语音处理】使用块反射器的基于DFT的系统中用于旁瓣抑制的正交预编码(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

Java中的多线程(下)

作者&#xff1a;~小明学编程 文章专栏&#xff1a;JavaEE 格言&#xff1a;热爱编程的&#xff0c;终将被编程所厚爱。 目录 多线程案例 单例模式 饿汉模式 懒汉模式 阻塞式队列 为什么要引入阻塞队列 Java中的阻塞队列 模拟实现阻塞队列 定时器 标准库中的定时器 …

docker的虚悬镜像是什么?

虚悬镜像是什么? 答:仓库名、标签都是<none>的镜像,俗称:dangling image 我们使用Dockerfile写一个: 1:编写 from ubuntu CMD echo action is success2:构建 docker build . 注意没有 -t 产生原因: 1:构建时候因为编写错误导致 2:删除的时候 对于这样…

数据溢出的二进制原理

char 类型的数据占一个字节&#xff0c;一个字节有 8 位&#xff0c;最高位为符号位&#xff0c;1表示负数&#xff0c;0表示正数。在计算机中&#xff0c;数据用补码表示&#xff0c;正数的补码是它本身&#xff0c;负数的补码为 “符号位不变&#xff0c;其他位取反后再加1”…

Spring Cloud 系列之OpenFeign:(4)集成OpenFeign

目录 传送门 服务间调用 集成OpenFeign 说明文档 添加pom依赖 启用OpenFeign 声明OpenFeign接口 改造远程调用 定义OpenFeign接口 测试OpenFeign调用 传送门 Spring Cloud Alibaba系列之nacos&#xff1a;(1)安装 Spring Cloud Alibaba系列之nacos&#xff1a;(2)单…

离散数学数理逻辑部分【2】

文章目录命题逻辑等值演算公式的使用【重点】析取范式和合取范式【重点】范式存在定义【了解】求公式A的范式的步骤&#xff1a;【重点】极大项和极小项【重点】主合取范式和主析取范式【重点】等式演算求主析取范式【重点】真值表求主析取范式【了解】主范式的应用【重点】推理…

Python : 使用python实现教务管理系统(GUI界面+数据库)

一、设计目的 1.熟悉Python和相关软件的操作。 2.基于本学期所学Python知识&#xff0c;熟练应用掌握&#xff0c;制作符合要求的教务管理系统。 3.会对程序运行中的错误代码进行分析&#xff0c;找出合理的解决方案。 4.掌握tkinter开发流程&#xff0c;布局方法和主要组件&a…

C语言位域

如果程序的结构中包含多个开关量&#xff0c;只有 TRUE/FALSE 变量&#xff0c;如下&#xff1a; struct {unsigned int widthValidated;unsigned int heightValidated; } status; 这种结构需要 8 字节的内存空间&#xff0c;但在实际上&#xff0c;在每个变量中&#xff0c;…

JavaScript游戏开发(4)(笔记)

文章目录八、角色动作状态的管理8.1 准备部分8.2 角色状态改变的基本方式8.3 完善整个代码8.4 存在的问题九、简单的横板动作卷轴游戏9.1 准备部分9.2 输入管理器9.3 状态管理器9.4 背景管理器9.5 敌人管理器9.6 碰撞检测、UI绘制9.7 更多的角色状态与特效9.8 完善游戏附录素材…

跳槽、换房、不忘输出,与你分享我匆忙的 2022~

前些日子下班回家的瞬间&#xff0c;忽然想起去年春节还在跟老爸吐露职场的困境和对房子的无奈。哪曾想过了不到半年的时间竟全部解决&#xff0c;令我不禁感叹人生的捉摸不透。 让我姑且花点文字记录下&#xff0c;与你分享我这一年的匆匆忙忙&#xff5e; 目录前瞻&#xf…

Listener监听器 | 监听域对象创建和销毁、使用监听器统计网站在线人数

目录 一&#xff1a;监听域对象创建和销毁 1、什么是监听器&#xff1f;监听器有什么用&#xff1f; 2、Servlet规范中提供了哪些监听器&#xff1f; 3、实现一个监听器的步骤 4、HttpSessionBindingListener 5、HttpSessionIdListener & HttpSessionActivationList…

【编译原理】实验二:NFA到DFA

目录 实验二 NFA 到 DFA 一、实验目的 二、预备知识 三、实验内容 NFA向DFA的转换的思路 NFA和DFA之间的联系 NFAToDFA.h 文件 main.c 文件 RegexpToPost.c 文件 PostToNFA.c 文件 NFAFragmentStack.c 文件 PostToNFA.h 文件 NFAFragmentStack.h 文件 NFAStateStack.h 文件 dem…

【C++】使用yaml-cpp操作yaml文件

目录 1 安装yaml-cpp 2 工程结构 &#xff08;1&#xff09;test.yaml的内容 &#xff08;2&#xff09;CmakeLists.txt &#xff08;3&#xff09;代码 3 运行结果 4 报错处理 1 安装yaml-cpp &#xff08;1&#xff09;cd 到yaml-cpp下载的目的路径 例如&#xff1a;…

spring之反射机制之Spring-DI核心实现

文章目录前言一、回顾反射机制之反射调用方法1、编写一个方法类SomeService2、通过反射机制调用SomeService类中的方法二、反射机制之Spring-DI核心实现前言 调用一个方法当中含有几个要素&#xff1f; 1、调用哪个对象 2、调用哪个方法 3、调用方法的时候传什么参数 4、方法执…

一文弄懂 React ref

前言 对于 Ref 理解与使用&#xff0c;一些读者可能还停留在用 ref 获取真实 DOM 元素和获取类组件实例层面上 其实 ref 除了这两项常用功能之外&#xff0c;还有很多别的小技巧 通过本篇文章的学习&#xff0c;你将收获 React ref 的基本和进阶用法&#xff0c;并且能够明白…