树状数组学习笔记
树状数组
拜读了大佬的讲解博文(树状数组(详细分析+应用),看不懂打死我!),写一篇Python版的笔记巩固消化,附带蓝桥杯历年真题作为例题演示
一、作用
用于快速读取列表中 某个区间内所有元素的和 实现单点修改,区间查询
若以差分数组作为a[]则可实现 区间修改,单点查询 操作,是一个常用技巧
二、时间复杂度
传统方式
- 访问某个元素: O ( 1 ) O(1) O(1)
- 获得某区间元素和: O ( n ) O(n) O(n)
树状数组
- 访问某个元素: O ( l o g n ) O(logn) O(logn)
- 获得某区间元素和: O ( l o g n ) O(logn) O(logn)
三、规则
通过创建一个列表t,记录以二进制划分的区间内元素的和,其中lowbit(x)的位数决定本节点所处的层数,t[x]保存了以x为根的子树中叶节点的值(即区间的元素和)
通过观察,
a数组具有以下性质:
- 下标索引从1开始(切记!!!)
- 长度为n
t数组具有以下性质: - t [ x ] t[x] t[x] 节点覆盖的长度是 l o w b i t ( x ) lowbit(x) lowbit(x)
- t [ x ] t[x] t[x] 的父节点是 t [ x + l o w b i t ( x ) ] t[x + lowbit(x)] t[x+lowbit(x)]
- 树的深度为 l o g 2 n + 1 log_2n + 1 log2n+1
- t [ x ] t[x] t[x] 节点覆盖的区间为 [ x − l o w b i t ( x ) + 1 , x ] [x-lowbit(x)+1, x] [x−lowbit(x)+1,x], t [ x ] t[x] t[x] 也即等于 t [ x ] t[x] t[x] 的子节点区间以后到$ a[x]$ 的所有元素之和!
t [ x ] ≡ ∑ i = x − l o w b i t ( x ) + 1 x a [ i ] t[x] \equiv \sum_{i = x-lowbit(x)+1}^x a[i] t[x]≡∑i=x−lowbit(x)+1xa[i]
四、创建和维护树状数组的三个基本函数
树状数组不是标准库中的数据结构,而是一个通过特殊函数维护和操作的一维数组。要想在题目中使用树状数组,首先需要创建三个操作函数。以下是这三个函数的详解。
(1)取最低二进制位函数 lowbit()
lowbit()函数用于获取一个正整数在二进制表示下最低位的1与其右侧所有的0所构成的二进制数的数值。
例如 12 = 2 ′ b 1100 , l o w b i t ( 12 ) = 2 ′ b 100 = 4 12 = 2'b1100, lowbit(12) = 2'b100 = 4 12=2′b1100,lowbit(12)=2′b100=4
# 正负x按位与
def lowbit(x):return (-x)&x
(2)单点修改函数 add()
为了实现树状数组的单点修改操作,需要创建一个函数add()。
由于每一个树上节点的祖先节点的值都包含了该节点的值,所以在修改某一个点的时候需要从叶子节点开始逐级向上递归修改它所有祖先节点的值。
这里就需要根据当前节点的序号 i i i 找出其双亲节点的序号,由树状数组的性质可知其双亲结点的序号为 i + l o w b i t ( i ) i+lowbit(i) i+lowbit(i)(见规则2)
def add(x,v):global n # n = len(t)while x < n:t[x] += vx += lowbit(x)
(3)区间查询函数 ckeck()
建立树状数组后,就可以利用其性质进行快速的区间查询了,由 规则4 可推知,区间[1,x]的元素和等于 t [ 1 ] + ⋅ ⋅ ⋅ + t [ x − l o w b i t ( x ) ] + t [ x ] t[1] + ··· + t[x-lowbit(x)] + t[x] t[1]+⋅⋅⋅+t[x−lowbit(x)]+t[x],由此可以使用递推求出区间和
# 求出区间[1:x+1]内所有元素的和
def check(x):ans = 0while x > 0:ans += t[x]x -= lowbit(x)return ans
以上函数无法指定区间的左端点,为了求出指定端点的区间和,可以使用类似于前缀和的方法求出指定区间的和值
# 求出区间[x:y]内所有元素的和
def check(left,right):ans = 0x = right - 1# 先使用原方法求出区间[1:right]的区间和while x > 0:ans += t[x]x -= lowbit(x)# 然后减去区间[1:left]的元素和,即可获得答案x = left-1while x > 0:ans -= t[x]x -= lowbit(x)return ans
五、树状数组整体模板
(1)单点修改、区间查询模板
def lowbit(x):return x&(-x)def add(x,v):global n,twhile x < n:t[x] += vx += lowbit(x)def check(left, right):global tx = right - 1ans = 0while x > 0:ans += t[x]x -= lowbit(x)x = left - 1while x > 0:ans -= t[x]x -= lowbit(x)return ans # 创建原数组和树状数组
# 注意树状数组的序号从1开始
a = [0] + [int(i) for i in input().split()]
n = len(a)
t = [0]*n
# 初始化树状数组
# 方法和初始化前缀和数组类似,将每一位的元素加到t[]中
for i in range(1,n):add(i,a[i])
# 查询修改前的区间和
print(check(2,6))
# 修改原数组中某一元素的值(单点修改)
index,value = map(int,input().split())
add(index, value)
# 查询修改后的区间和(区间查询)
print(check(2,6))
# 具体功能(略),按照题目要求编写
(2)区间修改、单点查询模板
def lowbit(x):return x&(-x)
def add(x,v):global x,twhile x < n:t[x] += v
def check(left,right):global n,tx = right - 1while x > 0:ans += t[x]x -= lowbit(x)x = left - 1while x > 0:ans -= t[x]x -= lowbit(x)return
# 初始化原数组和树状数组
a = [0] + [int(i) for i in input().split()]
n = len(a)
t = [0]*(n+1)
d = [0]*(n+1)
# 用树状数组维护差分数组
for i in range(1,n):d[i] = a[i] - a[i-1]add(i,d[i])
# 区间修改
l,r,v = map(int,input().split())
# 结合差分数组修改的原理在树状数组上进行单点修改
# 修改d[l],d[r+1]
add(l,v)
add(r+1,-v)
# 单点查询
# 查询原数组第三个元素的值
print(check(3))
六、例题
例题一:异或和(蓝桥杯第14届省赛)
问题描述:
给一棵含有 n n n 个结点的有根树,根结点为 1 1 1 ,编号为 i i i 的点有点权 a i a_i ai ( i ∈ [ 1 , n ] ) (i \in [1,n]) (i∈[1,n])。现在有两种操作,格式如下:
1 x y 1 x y 1xy :该操作表示将点 x x x 的点权改为 y y y。
2 x 2 x 2x :该操作表示查询以结点 x x x 为根的子树内的所有点的点权的异或和。
现有长度为 m m m 的操作序列,请对于每个第二类操作给出正确的结果。
输入格式:
输入的第一行包含两个正整数 n , m n,m n,m 用一个空格分隔。第二行包含 n n n 个整数 $a_1, a_2, … ,a_n
,相邻整数之间使用一个空格分隔。接下来 n − 1 n−1 n−1 行,每行包含两个正整数 u i , v i u_i, v_i ui,vi,表示结点 u i u_i ui 和 v i v_i vi之间有一条边。接下来 m m m 行,每行包含一个操作。
输出格式:
输出若干行,每行对应一个查询操作的答案。
# 求 DFS 序,以便建立树状数组
cnt = 0
def dfs(cur,pre):# cur 是当前节点的序号,pre是上一个节点的序号global cntcnt += 1# 记录将当前节点压入栈中的时间戳seq[cur][0] = cnt for i in tree[cur]:if pre != i:dfs(i,cur)# 记录将当前元素出栈的时间戳,自此以后的时间戳均与以cur为根节点的树无关seq[cur][1] = cnt # 树状数组函数三件套
def lowbit(x):return x&(-x)def modify(x,v):global nwhile x <= n:t[x] ^= v # 计算异或和x += lowbit(x)def query(x):global nans = 0while x > 0:ans ^= t[x]x -= lowbit(x)return ans# 接收输入,创建数据结构
n,m = map(int,input().split())
# a[]存储每一个点的权值
a = [0] + [int(i) for i in input().split()]# 用邻接表存储树结构
tree = [[] for i in range(n+1)]
for _ in range(n-1):u,v = map(int,input().split())# 注意没说方向,是一个无向边tree[u].append(v)tree[v].append(u)# 创建一个二维数组seq[][]记录DFS序
# 其中seq[i]是有2个元素的列表,两个元素分别是第i个节点入栈和出栈的时间戳
seq = [[0,0] for i in range(n+1)]
dfs(1,0)# 为DFS序数组创建树状数组,并用a[]的值初始化
t = [0]*(n+1)
for i in range(1,n+1):modify(seq[i][0], a[i])
for _ in range(m):instr = [int(i) for i in input().split()]if instr[0] == 1:# 修改元素,注意到需要在赋值的同时清除原有元素,所以将原值与新值异或,相当于清除原值modify(seq[instr[1]][0], a[instr[1]]^instr[2])# 维护a[],确保其始终保存着每一个节点的当前值a[instr[1]] = instr[2]else:# 输出单点查询结果 print(query(seq[instr[1]][1]) ^ query(seq[instr[1]][0] - 1))
相关文章:
树状数组学习笔记
树状数组 拜读了大佬的讲解博文(树状数组(详细分析应用),看不懂打死我!),写一篇Python版的笔记巩固消化,附带蓝桥杯历年真题作为例题演示 一、作用 用于快速读取列表中 某个区间内所有元素的和 实现单点修改ÿ…...
【bugfix】如何解决svg到线上显示空白或者svg的viewBox为空
svgo的默认机制是当width和height和viewbox一样会删除viewbox,这都是为了svg的压缩做的,详情可以看issue中的讨论,我们可以通过更改babel的配置来解决 https://github.com/svg/svgo/issues/1128 https://github.com/ant-design/ant-design-we…...
docker基础学习指令
文章目录 [toc] docker基础常用指令一、docker 基础命令二、docker 镜像命令1. docker images2. docker search3. docker pull4. docker system df5. docker rmi1. Commit 命令 三、 docker 容器命令1. docker run2. docker logs3. docker top4. docker inspect5. docker cp6. …...
回溯大学生活
回顾一下大学四年 bg:湖南大学 20级计科,成绩60%,无考研考公打算 四年之前,怀着激动的心情来到了大学校园,经过了太久的压抑终于迎来了高中老师口中的美好的大学生活,然而呢事实并非如此。恋爱呢…...
Android Fence机制
Android Fence机制 Android中的GraphicBuffer同步机制-Fence (最全最详细,推荐) AndroidQ 图形系统(5)Fence机制简介 Android P 图形显示系统(十一) BufferQueue(二)...
sa-token非Web上下文无法获取Request
0x02 非Web上下文无法获取Request 问题定位 在我们使用sa-token安全框架的时候,有时候会提示:**SaTokenException:非Web上下文无法获取Request**** 错误截图: 在官方网站中,查看常见问题排查: 非Web上下文无法获取…...
tomcat 常见优化方案
tomcat作为Web服务器,它的处理性能直接关系到用户体验,下面是几种常见的优化措施: 对web.xml的监视,把jsp提前编辑成Servlet。有富余物理内存的情况,加大tomcat使用的jvm的内存 服务器所能提供CPU、内存、硬盘的性能…...
前端导出文本内容为csv文件,excel乱码
原因:编码格式问题,需要改为utf-8 bom // Create blob with utf8-bom 编码 const createBlobWithBOM(data, mimeType)> {const bom [0xEF, 0xBB, 0xBF];const bomArray new Uint8Array(bom);const dataArray new TextEncoder().encode(data);const…...
36---USB HUB电路设计
视频链接 USB HUB电路设计01_哔哩哔哩_bilibili USB HUB 电路设计 1、USB HUB基本介绍 USB Hub,指的是一种可以将一个USB接口扩展为多个,并可以使这些接口同时使用的装置。 Hub也是大家常说的集线器,它使用星型拓扑结构连接多个USB接口设…...
FPGA在深度学习领域的应用的优势
FPGA(Field-Programmable Gate Array)是一种可编程逻辑芯片,可以根据需要重新配置其内部的逻辑电路和功能。在深度学习领域,FPGA被广泛用于加速模型训练和推理任务。 首先,FPGA可以提供高度定制化的计算架构ÿ…...
Windows Edge 兼容性问题修复 基本解决方案
Windows Edge 浏览器兼容性问题可能源于多个方面,以下是一些常见的问题及其处理结果: 插件或扩展冲突:某些第三方插件或扩展可能与Edge浏览器不兼容,导致崩溃或运行异常。处理结果为,尝试禁用所有插件和扩展ÿ…...
【Servlet】服务器内部转发以及客户端重定向
文章目录 一、服务器内部转发:request.getRequestDispatcher("...").forward(request, response);二、客户端重定向:response.sendRedirect("");三、服务器内部转发代码示例四、客户端重定向代码示例 一、服务器内部转发:…...
是否有替代U盘,可安全交换的医院文件摆渡方案?
医院内部网络存储着大量的敏感医疗数据,包括患者的个人信息、病历记录、诊断结果等。网络隔离可以有效防止未经授权的访问和数据泄露,确保这些敏感信息的安全。随着法律法规的不断完善,如《网络安全法》、《个人信息保护法》等,医…...
Java设计模式详解:单例模式
设计模式详解:单例模式 文章目录 设计模式详解:单例模式一、单例模式的原理二、单例模式的实现推荐1、饿汉模式2、静态内部类 三、单例模式的案例四、单例模式的使用场景推荐总结 一、单例模式的原理 单例模式听起来很高大上,但其实它的核心…...
Pointnet++改进即插即用系列:全网首发OREPA在线重新参数化卷积,替代普通卷积 |即插即用,提升特征提取模块性能
简介:1.该教程提供大量的首发改进的方式,降低上手难度,多种结构改进,助力寻找创新点!2.本篇文章对Pointnet++特征提取模块进行改进,加入OREPA,提升性能。3.专栏持续更新,紧随最新的研究内容。 目录 1.理论介绍 2.修改步骤 2.1 步骤一 2.2 步骤二 2.3 步骤三...
XRDP登录ubuntu桌面闪退问题
修改 /etc/xrdp/startwm.sh unset DBUS_SESSION_BUS_ADDRESS unset XDG_RUNTIME_DIR . $HOME/.profile...
【Node】使用Node.js构建简单的静态页面生成器
使用Node.js构建简单的静态页面生成器 在现代的Web开发中,静态网站因其速度快、安全性高而越来越受到开发者的青睐。本文将介绍如何使用Node.js构建一个简单的静态页面生成器,通过这个小项目,你将了解到静态网站生成的基本原理和实现方法。 …...
AI智能客服机器人是什么?对企业重要吗?
在数字化时代,客户服务是企业与客户建立牢不可破关系的重要桥梁。AI智能客服机器人,顾名思义,就是利用人工智能技术提升客户服务体验的自动化工具。今天,就让我们来揭开AI智能客服机器人的神秘面纱,并讨论它对企业的重…...
InfluxDB2的数据查询示例
有用influxdb2 不支持sql,并且实质是个列存储数据库,这里基于 influxdb-client-java 和 beanutils反射,写了个数据查询,把结果以行对象的形式返回的工具类。 package com.joy.malltools.influxdb2;import com.influxdb.client.Q…...
CSS基础语法-黑马跟课笔记-供记录与查询
一.CSS简介 1.1HTML局限性 只关注内容的语义,可以做简单的样式但是很臃肿且繁琐 1.2CSS优势 CSS层叠样式表,标记语言 设置HTML页面中的文本内容,图片外形,可以美化HTML,让页面布局更美观 HTML做框架,…...
第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...
如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
MySQL 部分重点知识篇
一、数据库对象 1. 主键 定义 :主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 :确保数据的完整性,便于数据的查询和管理。 示例 :在学生信息表中,学号可以作为主键ÿ…...
