通俗易懂的树状数组详解!请食用!qwq

数据结构之树状数组 ——详解 树状数组是一种维护前缀和、区间和的数据结构。它在原数组上添加索引,从而高效维护数据。神奇而小巧的数据结构,树状数组的下标必须从1开始!无论是他的修改还是查询,时间复杂度永远都是 logn,适合用于做区间和,前缀和,单点修改比前缀和标准做法的修改快一些。 阅读详情

前:我写的线段树深受好评。于是想写树状数组。持续更新。

树状数组与二进制位有关。和线段树有些相像之处,都是把序列转化成一棵树进行操作。但是有区别。

update 2021.1.3:发现咕了接近2个月,决定写写

part 1 :基本思想

1 二进制分解

如果1个数 a a a 的二进制表示中,为1的为分别为:
a k , 1 , a k , 2 , a k , 3 . . . a k , c n t a_{k,1},a_{k,2},a_{k,3}...a_{k,cnt} ak,1​,ak,2​,ak,3​...ak,cnt​

则这个数=
2 k , 1 + 2 k , 2 . . . + 2 k , c n t 2^{k,1}+2^{k,2}...+2^{k,cnt} 2k,1+2k,2...+2k,cnt

这就是二进制分解了。

2 树的由来

我们假设 k 1 > k 2 > k 3 . . . > k c n t k_1>k_2>k_3...>k_{cnt} k1​>k2​>k3​...>kcnt​,则区间 [ 1 , n ] [1,n] [1,n] 可以被分成 O ( l o g n ) O(log n) O(logn) 个小区间。

它们分别为:
[ 1 , 2 k 1 ] , [ 2 k 1 + 1 , 2 k 1 + 2 k 2 ] . . . [1,2^{k_1}],[2^{k_1}+1,2^{k_1}+2^{k_2}]... [1,2k1​],[2k1​+1,2k1​+2k2​]...

于是有了一棵树。

3 小区间特点

如果区间结尾为 r r r,则区间长度就等于 r r r 的二进制分解中最小的2的次幂。我们用函数 l o w b i t lowbit lowbit来求区间长度。

int lowbit(int x){return x & -x;}

有了这个函数,我们就可以用类似标记的整块修改来维护前缀和啦!!!

4 树的性质

我们用数组 s u m [ x ] sum[x] sum[x] 来保存序列 a a a 的区间 [ x − l o w b i t ( x ) + 1 , x ] [x-lowbit(x)+1,x] [x−lowbit(x)+1,x] 中所有数的和,则数组 s u m sum sum 就是一个树形结构。

这就是我们的树状数组啦!

图解:

图中红色节点忽略不计qwq

在这个结构中:

1.每个节点保存以它为根的子树中所有叶节点的和

2.每个节点 s u m [ x ] sum[x] sum[x] 的子节点(指最底层的叶子结点!)个数等于 l o w b i t ( x ) lowbit(x) lowbit(x) 的值。

笔者的书本上没有括号内容,然而我经过研究后发现,是指叶子结点的值。如4有1.2.3.4这4个叶子结点,对吧?所以 l o w b i t ( 4 ) = 4 lowbit(4)=4 lowbit(4)=4 。但是4有7个子节点(A4个,C3个)。

3.除了根节点,每个节点 s u m [ x ] sum[x] sum[x] 的父亲节点是 s u m [ x + l o w b i t ( x ) ] sum[x+lowbit(x)] sum[x+lowbit(x)]

4.一整颗树的深度为 O ( l o g N ) O(log N) O(logN)。

基本思想讲完了!

part 2 :常支持的操作

树状数组资瓷查询前缀和(自然可以区间和啦!),单点修改,求逆序对(和正序对),区间修改等。

好的,下一部分qwq。

part 3 :代码

像这种数据结构(线段树,分块…)基本都有整体修改的标记,对吧qwq?

前缀和:

遍历一个节点的子树中的子节点,就可以了。

int ask(int x){
	int res=0;
	for(;x;x-=lowbit(x))res+=sum[x];
	return res;
} 

单点修改:

这个操作除了修改,还要维护前缀和,所以我们要对一个节点的祖先进行遍历,从下往上修改。这样子修改完,前缀和一定也是正确维护的。

void add(int x,int val){
	for(;x<=n;x+=lowbit(x))sum[x]+=val;
}//n为原始数列中元素个数 

区间修改:

我们新建一个数组 b b b,把一次区间修改(在区间 [ l , r ] [l,r] [l,r] 中,把每一个值加上 v a l val val)转化为:

在 b [ l ] b[l] b[l] 处加上 v a l val val,在 b [ r + 1 ] b[r+1] b[r+1] 处减去 v a l val val。

原理是前缀和。在区间 [ 1 , l − 1 ] [1,l-1] [1,l−1] 中,前缀和不变;在区间 [ l , r ] [l,r] [l,r] 中,前缀和增加了 v a l val val;在区间 [ r + 1 , n ] [r+1,n] [r+1,n] 中,前缀和不变(加 v a l val val 和减去 v a l val val 抵消)。

正确性使然。

这里的加是指单点修改。

不要直接 s u m [ x ] + = v a l sum[x]+=val sum[x]+=val,会气死我的

区间和(区间查询):

这种题的区间修改和上面类似,但是要改一下,因为还要执行区间和操作。我们使用两个树状数组 c 1 c1 c1 和 c 2 c2 c2。

它们初始值为0。

对于修改区间 [ l , r ] [l,r] [l,r],我们执行四次操作:

在 c 1 c1 c1 中,add(l,val);add(r+1,-val);

在 c 2 c2 c2 中,add(l,l*val);add(r+1,-(r+1)*val);

我们还要用 一个 数组储存数列原本的前缀和。

下面,对于每一个区间查询,我们分成1到 r r r 和1到 l − 1 l-1 l−1两个部分,查询结果就是二者相减。

int ask_lr(int l,int r){
	int ans=sum[r]+(r+1)*ask_c1(r)-ask_c2(r);
	ans-=(sum[l-1]+l*ask_c1(l-1)-ask_c2(l-1));
	return ans;
} //ask_c1是对c1的操作,ask_c2是对c2的操作,sum记录原始前缀和

这个式子好好理解下吧!

讲完啦!(注意:根据不同的题目,大部分时候请开long long)

part 4 :练习题

一个比较不错的题单,做做吧

结:

写了怎么久,终于写完啦!

谢谢阅读。

离散数学---期末复习知识点 计网专业课,离散数学,期末复习题 阅读详情

相关推荐

Senior Data Structure·详解分块思想与树状数组

一、浅析数据结构之用处和高级数据结构之特性 数据结构者,谓之数据之关系。单论数据特性,也不过是数据之间的存储方式罢。但要说更深层次之作用,是运用其存储之特性,建立数学之模型,更方便地才处理数据尔。 以上是鲁迅同志说的(鲁迅:exmexmexm???),其实一切的数据结构不过就是一种用于处理数据的、成熟的、合理的结构封装。较低级的数据结构不会支持什么操作,仅是维护自身的存储秩序;而高级数据结构则...

Orchidany‘s blog 557

宋浩 概率统计 笔记_【概率论与数理统计期末复习笔记】-(五)离散型二维变量与连续性二维变量(上)...

1.已知二维离散型分布律,求???已知二维随机变量X,Y的分布律如下表XY12300.20.10.110.30.20.1求:(1)P(X=0),P(Y=2)(2)P(X<1,Y≤2)(3)P(X+Y=2)(4)X,Y的分布律(5)Z=X+Y的分布律解:(1)P(X=0)=0.2+0.1+0.1=0.4P(Y=2)=0.1+0.2=0.3(2)P(X<1,Y≤2)=0.2+0.1=0.3...

weixin_39589766的博客 923

在Simulink中进行基于模拟信号数字化处理的仿真

模拟信号数字化处理通常包括以下几个步骤:采样、量化、编码以及数字信号处理(如滤波、变换等)。Simulink提供了丰富的模块库,可以方便地实现这些步骤,并支持对整个系统的实时仿真与调试。首先明确你的系统需求,比如输入信号类型(正弦波、方波等)、采样率、需要执行的数字信号处理操作(低通滤波、频谱分析等)。假设我们需要处理一个50Hz的正弦波信号,采样率为1kHz,并希望对该信号进行低通滤波以去除高频噪声。本文介绍了如何在Simulink中进行基于模拟信号数字化处理的仿真。

xiaoheshang_123的博客 623

树状数组讲解(简洁好懂)

树状数组 树状数组是用于维护前缀和的数据结构,支持单点的查询和修改,如果要修改区间的值则需要用到差分数组。数字太大时可以在排序后进行离散化。 树状数组原理详解: 首先我们需要知道lowbit(x)是返回x的最后一个1,例如二进制数10100就返回100. 树状数组的核心思想是将一个数分解成若干零件,在维护的时候,直接对这些零件进行处理,在查询的时候再将这些零件组装成我们想要的数。 我们先来看看树状数组是如何查询的: ll query(int p) { ll ans = 0; for (; p; p -=

qwqgood的博客 949

康耐视VisionPro必学技巧:用CogCopyRegionTool实现图像拼接与局部替换

本文深入探讨了康耐视VisionPro中CogCopyRegionTool的高级应用,重点解析如何利用其精确的像素级复制与坐标对齐功能,实现工业视觉中的多相机图像拼接与印刷品局部替换。通过实战案例与代码示例,详细指导了从坐标标定、画布创建到顺序复制的完整流程,并分享了性能优化与常见避坑指南,帮助工程师高效解决复杂图像合成难题。

weixin_29204121的博客 500

STM32H745xI双核芯片SMPS/LDO配置误区:从复位失败到精准排查的实战复盘

本文详细分析了STM32H745xI双核芯片在SMPS/LDO配置中的常见误区,特别是复位失败问题的排查过程。通过对比参考板与故障板的波形数据,揭示了电感选型不当导致的电源稳定性问题,并提供了硬件设计检查清单和调试技巧,帮助开发者避免类似陷阱。

weixin_42531588的博客 264

【学习笔记】详解树状数组

详解树状数组

weq2011的博客 3301

解决Android 14兼容性问题:NDK中arm64-v8a的正确配置方法

本文详细解析Android 14系统架构变化对NDK开发的影响,重点介绍arm64-v8a架构的正确配置方法。针对常见的兼容性问题如so库缺失、ABI不匹配等提供解决方案,并分享性能优化与自动化测试实践,助力开发者高效适配Android 14设备。

algae的博客 1219

szu 寒训第二天 树状数组 二维树状数组详解,以及树状数组扩展应用【求逆序对,以及动态第k小数】

树状数组(Binary Index Tree) ---------这是一类用以解决动态前缀和的问题 (有点像线段树简版) **1.对于 a1 + a2 + a3 + … + an 1)询问 aj + … + am (1 <= j <= m <= n ); 2) 修改 ai ( 1<= i <= n); (yxc大佬说任何问题都要树立暴力思想) 那么暴力的复杂度是多...

weixin_45630722的博客 450

Python 爬虫高级实战:HTTPS 证书忽略与代理抓包配置

本文深入解析了HTTPS加密与SSL证书校验机制在爬虫开发中的核心问题及解决方案。文章首先剖析了HTTPS协议架构和证书校验流程,指出爬虫开发中常见的证书异常场景及其负面影响。随后详细介绍了Python主流请求库(requests、httpx、aiohttp)的证书忽略配置方法,包括同步/异步模式下的实现方案。针对代理环境,文章系统比较了HTTP、HTTPS、SOCKS5等代理类型的特性差异,并提供了完整的代理配置示例。特别对中间人抓包场景,阐述了Mitmproxy的工作原理和配置要点。最后提出了工程级爬虫

2503_91057718的博客 85

基于DynamicHead的YOLOv8四头版本改进:面向复杂场景的多目标检测优化【YOLOv8】

YOLOv8的检测头是通过不同尺度的特征层输出检测结果。这些检测头通常包括三个:用于大物体、中等物体和小物体的检测。然而,这种单一结构可能会在复杂场景下失去针对性和灵活性,特别是当多个目标之间差异较大时。为了进一步提升模型在特定目标上的检测性能,DynamicHead的引入为我们提供了一个多检测头的优化方案。本文提出了一种基于DynamicHead的四头版本YOLOv8改进方案,以解决复杂场景下多目标检测的挑战。通过引入四个独立检测头,分别针对不同目标特征进行优化,实现了更灵活的检测结构。

博客 1717

树状数组优化 DP

树状数组优化DP

cz_0118的博客 1288

Flatten 层的深度理解与运用

Flatten 层的深度理解与运用

你要拥有一个你喜欢并且热爱的人生 7028

树状数组

树状数组复杂度 O(logn). 树状数组是一种维护前缀和,区间最大值,区间最小值,区间异或和等满足交换律的东西的数据结构,其支持单点修改和区间查询。 树状数组其实并不算一棵树,它是由数组+二进制的操作实现的,只是在实现的过程中我们借助了树形结构的思想,因此树状数组并不需要建树等操作。 一,认识树状数组* 树状数组也是一棵二叉树,长相类似于一棵偏沉的线段树,其中最下面一排数组a代表给...

dcaqnjmx39255的博客 278

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

树状数组详细解析

本文中或许会引进部分图片来自网络,但大多数内容均为原创qwq。 树状数组或者二叉索引树也称作Binary Indexed Tree,又叫做Fenwick树。 它的查询和修改的时间复杂度都是log(n),空间复杂度则为O(n). (这也是我们为什么使用树状数组的原因) 树状数组可以将线性结构转化成树状结构,从而进行跳跃式扫描,通常使用在高效的计算数列的前缀和,区间和,同时,我们在运...

anjie1937的博客 283

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

c++ 树状数组三种方法

树状数组 初识树状数组 树状数组用的是树结构的思想(也就是树型逻辑结构),而不是真正的“树形结构”,(换句话说,从某种意义上,树状数组跟树其实没有特别大的关系) 树状数组支持的操作: 区间和、区间异或和、区间乘积和RMQ(显然,支持的操作都具有交换律) 2.单点修改和区间修改。 树状数组的优点:树状数组的维护是(logn)的,并且查询、修改是O(1)。 树状数组被称为树的原因:维护以(logn),而这个log底是2;就是二进制表示法,也就是二叉树上数据之间的特殊逻辑关系。 还是不懂的人可以结合下面的图理

Mo_1034923393的博客 2086

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

树状数组+逆序数实战

树状数组顾名思义,就是一个树状的数组(X其形式如下图所示其中数组t[i]为我们的树状数组,它的意义是以i为根,其自身与所有子节点的和如 t[4] = a[4] + t[2] + t[3] = a[4] + a[2] + a[1] + a[3]我们再来分析一下图中的t对于任意的一个t[i],我们可以知道其所覆盖的长度是lowbit(i)什么是lowbit呢?lowbit指的是对于一个数将其转化为二进制后,从后先前找出第一个为1的位置 (假设为j)

qq_61422664的博客 1053

【逆序对】 —— 树状数组+离散化

逆序对 —(树状数组+离散化) 洛谷传送门qwq 首先,想谈谈什么是树状数组,当然如果特别了解的话可以直接跳过。 我理解的树状数组,其实就是一个求前缀和的工具,能够实现动态求和,边插入边求和,而且求和的方式变得简单了很多。但许多需要使用树状数组的题目,都不是难在树状数组本身上面,而是如何构造和定义你所使用的数组,如何将问题转化为数组的模型。 当然前辈们所构造的树状数组本身,也是十分精巧,且并不难于...

TTTiko's blog 324

树状数组区间修改和区间求和

最一般树状数组能做到的操作是单点修改,区间求和,都是log(n)级别的。原理就是用树状数组维护a[i]的部分和。 想要做到修改区间,求单点值也很简单,用树状数组维护a[i]的差分数组d[i]的部分和既可。 那么,如何同时做到区间求和,区间修改呢? 有人可能会说了,如果是区间求和区间修改的话,直接写线段树不就好了吗? 但是,从代码长度来看(dalao请无视),显然使用树状数组在考...

weixin_30835649的博客 1542

qwq

可优化dp:转移、状态都是一维的 优化思路:单调栈、单调队列、数据结构、斜率优化 T1: 无限制:C(x+y-1,x) 不可行:C(x+y-1,x-1) 目标,顺序,剪枝 树状数组: O(logn):单点修改、求前缀和、区间修改、区间求和 堆: 快速插入删除、查询最大最小 并查集: 代表元、优化:路径压缩+按秩合并O(n*alpha(n))+启发式合并O(nlogn)+随机合并 SET: 有序集合...

人生如逆旅 1660

差分思想在树状数组中的应用: luogu3368 树状数组+差分

题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数数加上x 2.求出某一个数的和 输入输出格式 输入格式: 第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。 接下来M行每行包含2或4个整数,表示一个操作,具体如下: 操作1: 格式:1 x y k 含义:将区间[x,y]内...

gzcszzx 213

树状数组优化DP

比如,对序列 $\{1,4,2,5,6,3,2,5,7,3\}$, `LIS` = $\{1,2,3,5,7\}$ = $5$, `S[1]` = $\{1,7,10\}$, `S[2]` = $\{3,6,8,9\}$, `S[3]` = $\{2,4,5\},$2. 设 `S[n]=` 以 $a$ 开头的 `LNIS` 长度为 $n$ 的 $a$ 的下标 构成的集合 ,共有 $S_1 \cdots S_n$ 这些。假设 `LNIS` 的划分数 为 $a$ ,`LIS` 的长度为 $b$

cz_0118的博客 900

蒟蒻の树状数组学习总结

定义 树状数组(Binary Indexed Tree(B.I.T), Fenwick Tree)是一个查询和修改复杂度都为log(n)的数据结构。主要用于查询任意两位之间的所有元素之和,但是每次只能修改一个元素的值;经过简单修改可以在log(n)的复杂度下进行范围修改,但是这时只能查询其中一个元素的值(如果加入多个辅助数组则可以实现区间修改与区间查询)。 这种数据结构(算法)并没有C++和Java的库支持,需要自己手动实现。在Competitive Programming的竞赛中被广泛的使用。树状数

wei_wu_xian_的博客 174

OI学习笔记之数据结构——树状数组

树状数组复杂度 O(logn). 树状数组是一种维护前缀和,区间最大值,区间最小值,区间异或和等满足交换律的东西的数据结构,其支持单点修改和区间查询。 树状数组其实并不算一棵树,它是由数组+二进制的操作实现的,只是在实现的过程中我们借助了树形结构的思想,因此树状数组并不需要建树等操作。 一,认识树状数组 树状数组也是一棵二叉树,长相类似于一棵偏沉的线段树,其中最下面一排数组a代表给定的序列a1,...

Hoyoak的博客 596

树状数组小总结

树状数组的小总结 话不多说,直接开始 定义及实现 树状数组这种数据结构是维护序列的前缀和的一个数组,比如,我们给定一个序列aaa,并建立一个数组ccc,其中 c[x]c[x]c[x] 保存序列aaa的区间[x−lowbit(x)+1,x][x-lowbit(x)+1,x][x−lowbit(x)+1,x]中所有数的和,即∑i=x−lowbit(x)+1xa[i]\sum_{i=x-lowbit(x)+1}^{x}a[i]∑i=x−lowbit(x)+1x​a[i]. 其基本实现如下图: 这是实现以上的代

weixin_45703553的博客 145
上一篇: DFS的双向搜索
下一篇: 线性基学习笔记
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值