基础数据结构--线段树(Python版本)
文章目录
- 前言
- 特点
- 操作
- 数据存储
- update
- Lazy下移
- 查询
- 实现
前言
月末了,划个水,赶一下指标(更新一些活跃值,狗头)
本文主要是关于线段树的内容。这个线段树的话,主要是适合求解我们一个数组的一些区间的问题,例如区间之和,区间乘机,区间最大,最小值等(当然求和,求乘机啥的,直接用前缀数组,如果是一些区间的大小的问题的话,当然用这个是比较合适的,当然这依然是空间换取时间的操作。例如一个数组长度为N,那么当我们构建这颗线段树时,我们所需要花费的空间为4N(为了保证不越界).
特点
首先的话,要说的关于线段树的特点其实就几个,第一就是数据存放在叶子节点,非叶子节点表示的是我们想要求取的目标值,例如我们想要求取一个区间和,那么非叶子节点存储的就是这个小区间内的值。
第二个特点就是Lazy懒惰更新,这个有点类似于摊还分析当中提到的第二种方式,每个元素的花费需要考虑到当前的消费和将来的消费,将来的消费,用于将来的花费。这个Lazy其实也有类似的意思,我先标记一下,然后我要用的到的时候,我再进行操作,起到了一个预知未来,延迟操作的意思。同样的,代码实现比较简单,至少比红黑树,斐波那契堆简单。
那么关于这个特点的话,这里先插一个眼,具体的将在下面进行阐述。
本文的话,就从区间求和为案例进行说明,这里面可以覆盖到较多的操作。
操作
数据存储
首先的话,这个数据的存储其实就是下面的样子。
然后这个叶子节点的话就是我们的这个数据,然后的话,这里也是对半砍掉一组数据,然后递归,跟那个归并有点像。
update
然后就是修改,这个的话就开始体现到Lazy的作用了,首先我们知道一个节点,他其实表示了当前这个节点表示的是哪个区间的一个值,用代码表示他的一个数据结构其实就是这样的:
class __Node():l: int = 0r: int = 0v: int = 0lazy: int = 0def __str__(self):return "left:{},right{},value:{},lazy:{}".format(self.l, self.r, self.v, self.lazy)
所以这个Update的话,明确一个区间,然后呢,我们找到这个区间,然后秉承着lazy的原则,如果我们发现,如果我们要更新的区间能够覆盖我们当前的这个节点的区间,我们就直接更新好这个节点的值,然后这个Lazy,记录一些我们修改的值是啥。
def update(self, i, l, r, k):if (self.tree[i].l >= l and self.tree[i].r <= r):self.tree[i].v += k * (self.tree[i].r - self.tree[i].l + 1)self.tree[i].lazy = kreturnif (self.tree[i].lazy != 0):self.__putdown(i)if (self.tree[2 * i].r >= l): #和左孩子还有交集self.update(2 * i, l, r, k)if (self.tree[2 * i + 1].l <= r): #和右孩子还有交集self.update(2 * i + 1, l, r, k)self.tree[i].v = self.tree[2*i].v+self.tree[2*i+1].v
之后的话,我们跟新一下,当然这里还需要注意的是,就是如果没有完全覆盖的话,我们需要更新一下Lazy,此时给到孩子节点,为什么要更新呢,原因的话就是当前的节点已经不能覆盖了,需要用到孩子节点,但是原来孩子节点没有更新值,现在要用了,就得把孩子赶紧更新一下,然后重新更新当前作为父节点的i。
Lazy下移
这个下移的话就是刚刚提到的,因为这个Lazy就相当于一个标记。他是这样的。
def __putdown(self, i):self.tree[2 * i].lazy += self.tree[i].lazyself.tree[2 * i + 1].lazy += self.tree[i].lazymid = (self.tree[i].l + self.tree[i].r) // 2self.tree[2 * i].v += self.tree[i].lazy * (mid - self.tree[i].l + 1)self.tree[2 * i + 1].v += self.tree[i].lazy * (self.tree[i].r - mid)self.tree[i].lazy = 0
更新孩子的Lazy,然后去掉父节点的Lazy,然后更新值。
查询
查询也是一致的,和更新一样,只是少了元素的更新,这里依然需要这个Lazy的下移,而且其实这个Lazy的下移其实就是在重新计算我们的修改,假设一直都没有用到,就一直不会更新,这样就节省了运算。就比如,你买了一张4080ti,但是你一直没有时间happy,那么在你没有happy时间的情况下就提前买了显卡,那么就浪费了这个money,因为早买没有享受到,但是当你有happy time的时候,你再去买,那么就是及时享乐了,没有造成资源的空闲浪费,搞不好还降价了,嘿嘿~
def search(self, i, l, r):if (self.tree[i].l >= l and self.tree[i].r <= r):return self.tree[i].vif (self.tree[i].lazy != 0):self.__putdown(i)t = 0if (self.tree[2 * i].r >= l):t += self.search(2 * i, l, r)if (self.tree[2 * i + 1].l <= r):t += self.search(2 * i + 1, l, r)return t
实现
"""
为了方便建树,这里的话我们将从1开始作为我们的下标
"""
class SegmentTree(object):def __init__(self, date):self.date = [0] + dateself.len_date = len(self.date)self.tree = [self.__Node() for _ in range(4 * self.len_date)]self.__build(1, 1, self.len_date - 1)def __build(self, i, l, r):self.tree[i].l = lself.tree[i].r = rif (l == r):self.tree[i].v = self.date[r]returnmid = (l + r) // 2self.__build(2*i, l, mid)self.__build(2*i+1, mid + 1, r)self.tree[i].v = self.tree[i * 2].v + self.tree[i * 2 + 1].vdef search(self, i, l, r):if (self.tree[i].l >= l and self.tree[i].r <= r):return self.tree[i].vif (self.tree[i].lazy != 0):self.__putdown(i)t = 0if (self.tree[2 * i].r >= l):t += self.search(2 * i, l, r)if (self.tree[2 * i + 1].l <= r):t += self.search(2 * i + 1, l, r)return tdef update(self, i, l, r, k):if (self.tree[i].l >= l and self.tree[i].r <= r):self.tree[i].v += k * (self.tree[i].r - self.tree[i].l + 1)self.tree[i].lazy = kreturnif (self.tree[i].lazy != 0):self.__putdown(i)if (self.tree[2 * i].r >= l):self.update(2 * i, l, r, k)if (self.tree[2 * i + 1].l <= r):self.update(2 * i + 1, l, r, k)self.tree[i].v = self.tree[2*i].v+self.tree[2*i+1].vdef __putdown(self, i):self.tree[2 * i].lazy = self.tree[i].lazyself.tree[2 * i + 1].lazy = self.tree[i].lazymid = (self.tree[i].l + self.tree[i].r) // 2self.tree[2 * i].v += self.tree[i].lazy * (mid - self.tree[i].l + 1)self.tree[2 * i + 1].v += self.tree[i].lazy * (self.tree[i].r - mid)self.tree[i].lazy = 0class __Node():l: int = 0r: int = 0v: int = 0lazy: int = 0def __str__(self):return "left:{},right{},value:{},lazy:{}".format(self.l, self.r, self.v, self.lazy)
这里的话,注意,找的时候呢,是从1号节点开始的,1号节点不等于第一个元素!
if __name__ == '__main__':a = [1,2,3,4,5]seg = SegmentTree(a)seg.update(1,5,5,5) #从根节点开始找,更新区间为[5,5]的元素+5,也就是第五个元素+5print(seg.search(1, 4, 5))#从根节点开始找,查找区间为[4,5]的区间和
🆗,over!
相关文章:
基础数据结构--线段树(Python版本)
文章目录前言特点操作数据存储updateLazy下移查询实现前言 月末了,划个水,赶一下指标(更新一些活跃值,狗头) 本文主要是关于线段树的内容。这个线段树的话,主要是适合求解我们一个数组的一些区间的问题&am…...
【micropython】SPI触摸屏开发
背景:最近买了几块ESP32模块,看了下mircopython支持还不错,所以买了个SPI触摸屏试试水,记录一下使用过程。硬件相关:SPI触摸屏使用2.4寸屏幕,常见淘宝均可买到,驱动为ILI9341,具体参…...
【云原生】k8s中Pod进阶资源限制与探针
一、Pod 进阶 1、资源限制 当定义 Pod 时可以选择性地为每个容器设定所需要的资源数量。 最常见的可设定资源是 CPU 和内存大小,以及其他类型的资源。 当为 Pod 中的容器指定了 request 资源时,调度器就使用该信息来决定将 Pod 调度到哪个节点上。当还…...
AI - stable-diffusion(AI绘画)的搭建与使用
最近 AI 火的一塌糊涂,除了 ChatGPT 以外,AI 绘画领域也有很大的进步,以下几张图片都是 AI 绘制的,你能看出来么? 一、环境搭建 上面的效果图其实是使用了开源的 AI 绘画项目 stable-diffusion 绘制的,这是…...
应用场景五: 西门子PLC通过Modbus协议连接DCS系统
应用描述: 西门子PLC(S7200/300/400/200SMART)通过桥接器可以支持ModbusRTU串口和ModbusTCP以太网(有线和无线WIFI同时支持)两种通讯方式连接DCS系统,不需要编程PLC通讯程序,直接在模块中进行地…...
我继续问了ChatGPT关于SAP顾问职业发展前景的问题,大家感受一下
目录 SAP 顾问 跟其他IT工作收入情况相比是怎么样的? 如何成为SAP FICO 优秀的顾问 要想成为SAP FICO 优秀的顾问 ,需要ABA开发技能吗 SAP 顾问中哪个类型收入最多? 中国的ERP软件能够取代SAP吗? 今天我继续撩 ChatGPT。随便问…...
Python小白入门---00开篇介绍(简单了解一下)
Python 小白入门 系列教程 第一部分:Python 基础 介绍 Python 编程语言安装 Python 环境变量和数据类型运算符和表达式控制流程语句函数和模块异常处理 第二部分:Python 标准库和常用模块 Python 标准库简介文本处理和正则表达式文件操作和目录操作时…...
【算法基础】C++STL容器
一、Vector 1. 初始化(定义) (1)vector最基本的初始化: vector <int> a;(2)定义长度为10的vector: vector <int> a(10);(3)定义长度为10的vector,并且把所有元素都初始化为-3: vector <int...
【经典蓝牙】蓝牙 A2DP协议分析
A2DP 介绍 A2DP(Advanced Audio Distribution Profile)是蓝牙高音质音频传输协议, 用于传输单声道, 双声道音乐(一般在 A2DP 中用于 stereo 双声道) , 典型应用为蓝牙耳机。 A2DP旨在通过蓝牙连接传输高质量的立体声音…...
Objective-C 构造方法的定义和声明规范
总目录 iOS开发笔记目录 从一无所知到入门 文章目录源码中 NSArray 的构造方法与命名规律自定义类的构造方法命名截图代码输出源码中 NSArray 的构造方法与命名规律 interface NSArray<ObjectType> (NSArrayCreation) (instancetype)array;(instancetype)arrayWithObject…...
Matlab图像处理学习笔记
Matlab图像处理 Matlab基础 数组 1、向量 生成方式1: x = [值] x = [1 2 3] % 行向量 y = [4; 5; 6] % 列向量 z = x % 行向量转列向量...
笔记(三)——迭代器的基础理论知识
迭代器是一种检查容器内元素并且遍历容器内元素的数据类型。它提供对一个容器中的对象的访问方法,并且定义了容器中对象的范围。一、vector容器的iterator类型vector容器的迭代器属于随机访问迭代器,一次可以移动多个位置。vector<int>::iterator …...
没有公网ip怎么外网访问nas?快解析内网端口映射到公网
对于NAS用户而言,外网访问是永远绕不开的话题。拥有NAS后的第一个问题,就是搞定NAS的外网访问。不过众所周知,并不是所有的小伙伴都能得到公网IP,由于IPV4资源的枯竭,一般不会被分配到公网IP。公网IP在很大程度上除了让…...
spring integration使用:消息转换器
系列文章目录 …TODO spring integration开篇:说明 …TODO spring integration使用:消息路由 spring integration使用:消息转换器 spring integration使用:消息转换器系列文章目录前言消息转换器(或者叫翻译器&#x…...
Vue3电商项目实战-商品详情模块7【21-商品详情-评价组件-头部渲染、22-商品详情-评价组件-实现列表】
文章目录21-商品详情-评价组件-头部渲染22-商品详情-评价组件-实现列表21-商品详情-评价组件-头部渲染 目的:根据后台返回的评价信息渲染评价头部内容。 yapi 平台可提供模拟接口,当后台接口未开发完毕或者没有数据的情况下,可以支持前端的开…...
地址,指针,指针变量是什么?他们的区别?符号(*)在不同位置的解释?
指针是C语言中的一个重要概念,也是C语言的一个重要特色;使用指针,可以使程序简洁、紧凑、高效。不掌握指针,就没有掌握C语言的精华。 目录 一、定义 1.1地址 1.2指针 1.3指针变量 1.4指针和指针变量的区别 二、使用指针变量…...
【MongoDB】一、MongoDB的安装与部署
【MongoDB】一、MongoDB的安装与部署实验目的实验内容实验步骤一、下载MongoDB安装包二、创建文件夹data及子文件夹db和log三、启动MongDB服务1. 在命令行窗口执行启动MongoDB服务命令2. 打开mongodb.log3. 打开浏览器进行启动验证四、登录MongoDB五、配置环境变量六、将MongDB…...
《爆肝整理》保姆级系列教程python接口自动化(二十三)--unittest断言——上(详解)
简介 在测试用例中,执行完测试用例后,最后一步是判断测试结果是 pass 还是 fail,自动化测试脚本里面一般把这种生成测试结果的方法称为断言(assert)。用 unittest 组件测试用例的时候,断言的方法还是很多的…...
MySQL的mvcc
mvcc(多版本并发控制) MVCC 是通过数据行的多个版本管理来实现数据库的并发控制 。使得在InnoDB的事务隔离级别下执行 一致性读操作有了保证。可以认为是行级锁的变种,在很多情况下可以避免加锁,开销更低 mvcc没有正式的标准&…...
vite:常见的配置
最近在捣鼓一下vite,因为自己一直在使用react,就选择vite、react来体验一下vite。 使用最简单的方法创建一个应用:yarn create vite,然后选择react框架。 vite默认配置是使用了defineConfig工具函数: import { defi…...
计算机图形学:liang算法和Cyrus-Beck算法
其中Cyrus-Beck算法呢,是计算一根直线一个多边形的交线段;liang算法是Cyrus的一个特例,即多边形刚好是矩形;先看看Cyrus算法的思路【从别的博客找的图片】:这很容易理解,点积>0时就可能中内部嘛…...
React组件之间的通信方式总结(上)
先来几个术语: 官方我的说法对应代码React elementReact元素let element<span>A爆了</span>Component组件class App extends React.Component {}无App为父元素,App1为子元素<App><App1></App1></App> 本文重点&…...
C++17 nodiscard标记符
文章目录前言弃值表达式nodiscard标记符函数非弃值声明类/枚举类/结构 非弃值声明返回类引用与类指针前言 在C 17中引入了一个标记符nodiscard,用于声明一个 “非弃值(no-discard)表达式”。那么在开始之前,我们需要了解一下什么是弃值表达式。 弃值表…...
SAP 寄售业务的标准流程
SAP的标准寄售业务,供应商提供的物料只有在公司使用之后才需支付应付账款,类似是一种先吃后付钱的餐饮流程。 SAP的寄售流程把实际业务中的供应商,采购方收货,采购方消耗物料,采购方依据消耗物料数量进行付款ÿ…...
操作系统高频知识
目录 一、线程与进程的区别 区别: 二、多进程和多线程区别 三、进程与程序的区别 三、死锁 1、是什么 2、产生的原因 3、产生的必要条件(4个) 4、如何预防 5、如何避免 6、如何检测 7、如何解除 一、线程与进程的区别 1、线程&a…...
加载预训练模型,模型微调,在自己的数据集上快速出效果
针对于某个任务,自己的训练数据不多,先找到一个同类的别人训练好的模型,把别人现成的训练好了的模型拿过来,换成自己的数据,调整一下参数,再训练一遍,这就是微调(fine-tuneÿ…...
VScode远程连接服务器-过程试图写入的管道不存在-could not establist connection to【已解决】
问题描述 使用服务器的过程中突然与服务器断连,报错如下:could not establist connection to [20:23:39.487] > ssh: connect to host 10.201.0.131 port 22: Connection timed out > [20:23:39.495] > 过程试图写入的管道不存在。 > [20…...
电子技术——B类输出阶
电子技术——B类输出阶 下图展示了一个B类输出阶的原理图,B类输出阶由两个互补的BJT组成,不同时导通。 原理 当输入电压 vI0v_I 0vI0 的时候,两个晶体管都截止输出电压为零。当 vIv_IvI 上升至超过0.5V的时候,此时 QNQ_NQN…...
【老卫搬砖】034期:HarmonyOS 3.1 Beta 1初体验,我在本地模拟器里面刷短视频
今天啊打开这个DevEco Studio的话,已经提示有3.1Beta1版本的一个更新啊。然后看一下它的一些特性。本文也演示了如何在本地模拟器里面运行HarmonyOS版短视频。 主要特性 新特性包括: Added support for Windows 11 64-bit and macOS 13.x OSs, as well…...
Day901.内部临时表 -MySQL实战
内部临时表 Hi,我是阿昌,今天学习记录的是关于内部临时表的内容。 sort buffer、内存临时表和 join buffer。这三个数据结构都是用来存放语句执行过程中的中间数据,以辅助 SQL 语句的执行的。 其中,在排序的时候用到了 sort bu…...
建站用Wordpress还是/电商平台有哪些
虚拟机的网卡配置指的是在虚拟机中配置网络接口卡的过程。这一过程可以通过虚拟机管理软件来完成,如 VMware、VirtualBox 等。 通常情况下,虚拟机网卡的配置过程包括以下几个步骤: 在虚拟机管理软件中打开虚拟机设置界面。 在虚拟机设置界面中࿰…...
诗敏家具网站是谁做的/seo是干嘛的
Jenkins1.190.0升级到Jenkins2.303.2 jenkinsci/blueocean镜像是优化界面化的一个版本 目前镜像版本: jenkinsci/blueocean:1.19.0,对应的jenkins版本为:1.190.2 升级后的版本: jenkinsci/blueocean:1.24.3,对应的jenkins版本为:2.263.2 注:如果不是这个版本的镜像不…...
深圳建立网站的公司/今天的病毒感染情况
part组员 工作 工作耗时/h明日计划工作耗时/h UI冯晓云 完善页面切换,尝试子页面设计 4 完善页面切换和子页面,修补弹窗bug 4foxit PDF Reader朱玉影 尝试添加pdf页面预览功能 4 尝试添加pdf页面预览功能 4login周以舟 …...
宝塔面板怎么做自己的网站/免费网页设计制作网站
再来看饮料厂在“原始时代”如何管理生产过程的吧。首先总经理须根据对需求的预测来安排生产计划,并根据物料和生产能力将此生产计划转为精确到时间、数量的详细的产品计划;在确定了生产计划之后,,就会把生产产品的数量转化为所需物料的数量&…...
最安全的网站语言/活动策划方案
ZooKeeper CAP定理: 一个分布式系统不可能同时满足以下三种,一致性(C:Consistency),可用性(A:Available),分区容错性(P:Partition Tolerance).在此ZooKeeper保证的是CP,ZooKeeper不…...
吴中公司网站建设找哪家/各大免费推广网站
3.9 闲聊数据类型 字符串: 单引号 双引号 三引号 数值: 整数 浮点 布尔 复数类型3.9.1 整型(整数) Python3的整型和长整型无缝结合 不再区分 长度取决于内存 优点-利于大数计算3.9.2 浮点型(小数) 科学记数法 E记法 也可以是e 源码…...