树状数组学习笔记

树状数组

拜读了大佬的讲解博文(树状数组(详细分析+应用),看不懂打死我!),写一篇Python版的笔记巩固消化,附带蓝桥杯历年真题作为例题演示

一、作用

用于快速读取列表中 某个区间内所有元素的和 实现单点修改区间查询
若以差分数组作为a[]则可实现 区间修改单点查询 操作,是一个常用技巧

二、时间复杂度

传统方式

  1. 访问某个元素: O ( 1 ) O(1) O(1)
  2. 获得某区间元素和: O ( n ) O(n) O(n)

树状数组

  1. 访问某个元素: O ( l o g n ) O(logn) O(logn)
  2. 获得某区间元素和: O ( l o g n ) O(logn) O(logn)

三、规则

通过创建一个列表t,记录以二进制划分的区间内元素的和,其中lowbit(x)的位数决定本节点所处的层数,t[x]保存了以x为根的子树中叶节点的值(即区间的元素和)
通过观察,
a数组具有以下性质:

  1. 下标索引从1开始(切记!!!)
  2. 长度为n
    t数组具有以下性质:
  3. t [ x ] t[x] t[x] 节点覆盖的长度是 l o w b i t ( x ) lowbit(x) lowbit(x)
  4. t [ x ] t[x] t[x] 的父节点是 t [ x + l o w b i t ( x ) ] t[x + lowbit(x)] t[x+lowbit(x)]
  5. 树的深度为 l o g 2 n + 1 log_2n + 1 log2n+1
  6. t [ x ] t[x] t[x] 节点覆盖的区间为 [ x − l o w b i t ( x ) + 1 , x ] [x-lowbit(x)+1, x] [xlowbit(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=xlowbit(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=2b1100,lowbit(12)=2b100=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[xlowbit(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 n1 行,每行包含两个正整数 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))

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

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

相关文章

【VSCode】修改插件地址

不想放在原始C盘下面C:\Users\{用户}\.vscode\extensions为了后续存储空间考虑&#xff0c;想通过添加环境变量创建名为VSCODE_EXTENSIONS的环境变量&#xff0c;内容指向vs Code扩展所在目录即可 直接配置环境变量&#xff0c;不要在有空格的文件夹下面 变量名称&#xff1a;…

jvm的垃圾回收策略

垃圾回收回收的是什么 对象 类元数据&#xff1a; 类的元数据包括类的结构信息、方法信息、字段信息等&#xff0c;它们存储在方法区&#xff08;Metaspace&#xff09;中。当一个类不再被引用时&#xff0c;垃圾回收器会卸载这个类&#xff0c;并释放其在方法区中占用的内存空…

TCP的十个重要的机制

注&#xff1a;TCP不是只有十个机制 TCP 可靠传输是tcp最为重要的核心&#xff08;初心&#xff09; 可靠传输&#xff0c;并不是发送方把数据能够100%的传输给接收方 而是退而求其次 让发送方发送出去数据之后&#xff0c;能够知道接收方是否收到数据。 一但发现对方没有…

[RK3566-Android11] 关于 a2dpsink -蓝牙支持接收播放/无PIN码连接

问题描述 1.蓝牙支持接收播放 2.蓝牙支持无PIN码连接&#xff08;不需要弹出pin配对码请求弹窗&#xff09; 3.蓝牙支持播放歌曲信息并应用层获取 解决方案&#xff1a; 1.a2dpsink-蓝牙需要支持接收播放补丁 1、device/rockchip/common/overlay/overlay/packages/apps/Blue…

CVE-2021-30517:Type confusion bug in LoadSuperIC

前言 这个漏洞是一个比较老的洞&#xff0c;之所以分析这个漏洞&#xff0c;只要是想再学习一下 ICs 相关的知识。并该漏洞的利用是利用与 String/Function 之间的混淆&#xff0c;比较有意思。 环境搭建 sudo apt install python git checkout 7d5e5f6c62c3f38acee12dc4114…

浅谈深度学习的学习方法

深度学习作为人工智能领域的一大热门技术&#xff0c;吸引了越来越多的开发者和研究者投身其中。然而&#xff0c;对于初学者来说&#xff0c;如何高效地入门深度学习并不是一件容易的事情。 一、基础知识准备 在开始学习深度学习之前&#xff0c;建议先掌握一些基础知识&…

vite.config.js

Vue3vite vite和webpack区别&#xff1f; 1.vite服务器启动速度比webpack快&#xff0c;由于vite启动的时候不需要打包&#xff0c;也就无需分析模块依赖、编译&#xff0c;所以启动速度非常快。当浏览器请求需要的模块时&#xff0c;再对模块进行编译&#xff0c;这种按需动态…

AI智能涂抹修补解决方案助力企业高效创作

传统的手动涂抹修补方式不仅效率低下&#xff0c;而且往往难以达到理想的视觉效果。美摄科技凭借深厚的AI技术研发实力&#xff0c;推出了面向企业的AI智能涂抹修补解决方案&#xff0c;为企业带来前所未有的创作体验。 美摄科技的AI智能涂抹修补解决方案&#xff0c;具备强大…

集群式无人机仿真环境和数据集

仿真环境和数据集 Quick StartAcknowledgementsSwarmSim Quick Start Compiling tests passed on 20.04 with ros installed. You can just execute the following commands one by one. # Download the Simulator and run it wget https://cloud.tsinghua.edu.cn/library/34…

年少不知EFCore好,错把SqlSugar当成宝

背景&#xff1a;依然记得我的第一份WebApi项目使用得是SqlSugar&#xff0c;当时还没有系统学习b/s这边的知识&#xff0c;跟着别人做项目用SqlSugar觉得非常方便&#xff0c;减少了自己手写ADO.Net的痛苦。但是今天发现这个EFCore也是巨好用啊&#xff0c;下面写一下他的简单…

DDD 的四层领域模型是怎样的?包含哪些基础概念?

DDD的四层领域模型如下所示&#xff1a; 展现层&#xff1a;这一层负责向用户显示信息和解释用户命令&#xff0c;完成前端界面逻辑。并将用户请求传递给应用层。应用层&#xff1a;这一层是很薄的一层&#xff0c;负责协调领域层中的领域对象&#xff0c;组成具体应用场景。应…

svn cannot set LC_CTYPE locale

svn报警告 svn: warning: cannot set LC_CTYPE locale svn: warning: environment variable LC_CTYPE is en_US.UTF-8 svn: warning: please check that your locale name is correct 使用命令 sudo dpkg-reconfigure locales 选择en_US.UTF-8&#xff0c;我的警告就好了 参…

vue3从精通到入门12:vue3的生命周期和组件

生命周期&#xff1a; 生命周期钩子主要包括&#xff1a; beforeCreate&#xff1a;组件实例被创建之前调用。在这个阶段&#xff0c;组件的 props 和 data 还未被初始化。created&#xff1a;组件实例创建完成后调用。在这个阶段&#xff0c;组件的 props 和 data 已经被初始…

Linux空洞文件

起因 今天在学习RandomAccessFile这个类时&#xff0c;看到里面有一个方法 public void seek(long pos) throws IOException {if (pos < 0) {throw new IOException("Negative seek offset");} else {seek0(pos);}}这个方法没有对文件的长度的校验&#xff0c;如…

springcloud==openfeign+springboot仿照openfeign自定义注解和使用

我的目的是参照原本openfeign的注解&#xff0c;但是我想实现每个外部服务的URL可以自己指定生成的规则。 自定义EnableMyFeignClients 自定义MyImportBeanDefinitionRegistrar&#xff0c;更改获取URL的逻辑。这个应该是个可行的方式&#xff0c;但是RIBBON的视线方式应该会…

LangChain入门:11.Pydantic(JSON)解析器实战

摘要 在数字化营销的浪潮中&#xff0c;自动化内容生成成为了提升效率和用户参与度的利器。本文将详细介绍如何利用LangChain的自然语言处理能力和Pydantic的数据验证特性&#xff0c;构建一个自动化的花店文案生成器。通过这个工具&#xff0c;您可以快速为各种花卉生成吸引人…

Gateway是什么?(SpringCloudAlibaba组件)

1、网关介绍 **网关(Gateway)又称网间连接器、协议转换器。网关在传输层上以实现网络互连&#xff0c;是最复杂的网络互连设备&#xff0c;仅用于两个高层协议不同的网络互连。**网关的结构也和路由器类似&#xff0c;不同的是互连层。网关既可以用于广域网互连&#xff0c;也可…

截稿倒计时 CCF-B COCOON’24论文延期至4月8日提交

会议之眼 快讯 第30届COCOON 2024 (International Computing and Combinatorics Conference)即国际计算与组合学会议将于 2024 年 8月23日-25日在中国上海举行&#xff01;COCOON是一个专注于计算机科学理论领域的国际性学术会议&#xff01;COCOON会议自1995年起举办&#xf…

Promise-以往的异步编程模式

要理解这个 double 函数在调度异步操作后为什么会立即退出&#xff0c;我们可以一步一步拆解它的执行流程。 首先&#xff0c;看一下 double 函数的定义&#xff1a; function double(value) {setTimeout(() > setTimeout(console.log, 0, value * 2), 1000); }当你调用 d…

JDK下载安装配置

一.JDK安装配置。 1.安装注意路径,其他直接下一步。 2.配置。 下接第4步. 代码复制: JAVA_HOME D:\Program Files\Java\jdk1.8.0_91 D:\Program Files\Java\jdk1.8.0_91\bin 3.验证(CMD)。 java javac java -version 二.下载 1.下载JDK1.5-1.9(所有版本)下载: https://www.…