侵权投诉

一文详解什么是树状数组

FPGA开发圈 2021-06-11 10:03 次阅读

Part 1 我学它干啥?

树状数组,Binary Indexed Tree(简称BIT),是由Peter M. Fenwick在1994年发明的名字十分高大上,那么它是干什么的呢?

求和

求和是树状数组中的一个应用,并不是只能求和,本文使用求和作为例子。

现在有一个数组a,我们需要求很多次数组中不同区间的和,而且多次对a中随意一项进行更改。

比如说a = {0, 1, 5, 3, 2, 4}

第一次求[1, 3],得到1 + 5 + 3 = 9

第二次求[2, 4],得到5 + 3 + 2 = 10

第三次,这时候我把a[2] += 2

第四次求[1, 5],得到1 + 7 + 3 + 2 + 4 = 17

[l, r]表示从下标l开始,到r结束的区间,包含l和r。

l: left

r: right

这时候很多同学想到的第一个方法,就是直接挨个加起来不就好了吗?

可此题暗藏玄机,我们要进行多次求和啊,每一次都重新计算太慢,能不能提前加好一些区域,反复使用呢?

这就要请出我们的主角了——树状数组

Part 2 lowbit

树状数组的结构十分精妙,其中离不开一个基本运算——lowbit

pYYBAGDCyUmAI-2UAACcjSxNWmQ629.jpg

lowbit(i) 可以解释为:i中最低位的1以及后面的0;或者你可以把它理解成i能被n整除,n还可以写成2k

一种lowbit的实现方式为lowbit(x) = x & -x

long long lowbit(long long x) {

return x & -x;

}

还是拿172举例子,化成二进制后我们发现除了尾部的100相同之外,其他位都不同,使用按位与能得到lowbit的值

poYBAGDCyVOAeJ9-AACEjV_ECQk145.jpg

Part 3 树状数组

既然名字叫树状数组,那它必然是个数组,可外表下藏着二叉树的结构。

精巧的结构与lowbit密不可分,真是妙极了。

以下内容中,我们在这里管原始的数组叫做a,树状数组(经过处理)叫做bit,三个图中的数字均为下标,不是值!

结构

pYYBAGDCyWGAU882AADclEz7wyc194.jpg

bit中存放了多个数的和,那么具体存了几个,在哪里呢?

我们规定,bit[i]中存从右往左数lowbit(i)个数。

bit[i] = 在数组a中从 i - lowbit(i) + 1 到 i 求和

更改单个数值

首先,更改数据可以转换成加法,我们这里讨论加法,和更改是一样的。

挨个加起来时,更改a[i]只需要动它一个就可以了。

可是在树状数组中,可能有好几项,都包括这个a[i]。

拿a[3]来举例子吧。

bit[3] 对应 a的[3, 3] 的和

bit[4] 对应 a的[1, 4] 的和

bit[8] 对应 a的[1, 8] 的和

bit[16] 对应 a的[1, 16] 的和

以上四个bit中的值都需要更改

pYYBAGDCyWiAd2hpAAEYesD_dPM603.jpg

在图中,我们可以看出,4在3头上,8在4头上,16在8头上。我们只需要找到一种方式,得到一个块 头上的块,然后使用循环能推出整串。

如何找到自己头上的数呢?

pYYBAGDCyieAc64XAAE4G2m5LLc951.jpg

图中的6和橘色没关系,是第二组例子

我们发现,在当前块的位置加上当前块的长度之后能跳到头上。

我是这么理解的:加上一个当前块后会把局部的空缺补上,合并成了一块,而这块也许也补了更大的空缺,这样就一次跳了好几级

上文定义规定了第i个块长度 = lowbit(i),拿来用即可。

c++++实现:

void add(int index, long long value) {

while (index 《= n) { // 更新直到最大的块

node[index] += value; // 更新当前的块

index += lowbit(index); // 加上一个自己的长度,补上空缺,得到下一个块

}

}

区间求和

poYBAGDCyZeAYN7UAAD4XEu3eaw265.jpg

先考虑[1, r]的求和

从右往左取块,将块代表的数值加起来即可

图中的例子:

第一次取到13,长度为lowbit(13) = 1

第二次13取完了从12开始取,长度为4,一次性将[9, 12]取完

第三次[9, 13]取完了从8开始,长度为8,取走[1, 8],到此[1, 13]全部取走c++实现

long long sum(int index) {

long long sum = 0;

while (index 》 0) {

sum += node[index];

index -= lowbit(index);

}

return sum;

}

那如果求和左端点不在1处呢?

对[l, r]求和,可以写成sum(r) - sum(l - 1)

先把大区域[1, r]求出来,然后扣掉[1, l - 1]的部分,不就是[l, r]吗?

构造

以上的“幻想”只是存在于树已经有了之后,如何根据数组a(原始数组),来构造一棵树呢?

一个简单的方法:

把数组bit全初始化为0

遍历整个数组a

对于每一个数组a[i],都对bit进行add(i, a[i])每一次add之后都能保证树状数组是正确的,全加一遍后自然构建出一整棵树。

时间复杂度对比

下面的暴力指的是开头提到的挨个相加。

求和

暴力:O(n)(挨个相加,加n次)

树状数组:O(log n)(结构与二叉树相仿)更改

暴力:O(1)(改一次即可)

树状数组:O(log n)(需要改一串,但结构与二叉树相仿)构造

暴力:O(n)(当做是读入的复杂度)

树状数组:O(n log n)(做n次加法,每次加法为log n)树状数组适合在:多次求和,多次修改,数据量大的场景下使用。

如果无需支持修改,建议使用前缀和,构造O(n),求和O(1)

代码

下面给出的是C++代码。

BITMain为树状数组的使用案例,对应洛谷 树状数组https://www.luogu.com.cn/problem/P3374。

//

// Created by Cat-shao on 2021/2/9.

//

#include 《cstdio》

#include 《cstring》

using namespace std;

const long long MAX_N = 5000100;

long long lowbit(long long x) {

return x & -x;

}

class BIT {

public:

long long node[MAX_N], n;

BIT(int _n) {

memset(node, 0, sizeof(node));

n = _n;

}

long long sum(int index) {

long long sum = 0;

while (index 》 0) {

sum += node[index];

index -= lowbit(index);

}

return sum;

}

void add(int index, long long value) {

while (index 《= n) {

node[index] += value;

index += lowbit(index);

}

}

};

int BITMain()

{

// https://www.luogu.com.cn/problem/P3374

int n, m, op, x, y;

long long value;

scanf(“%d%d”, &n, &m);

BIT tree = BIT(n);

for (int i = 1; i 《= n; ++i) {

scanf(“%lld”, &value);

tree.add(i, value);

}

for (int i = 0; i 《 m; ++i) {

scanf(“%d%d%d”, &op, &x, &y);

if (op == 1) {

tree.add(x, y);

} else if (op == 2) {

printf(“%lld

”, (tree.sum(y) - tree.sum(x - 1)));

}

}

return 0;

}

int main()

{

BITMain();

}

文章来源: 程序员小灰

图片来源:编程的最初梦想
责任编辑:lq6

原文标题:什么是树状数组?让这个12岁年轻人为你讲解

文章出处:【微信号:TheAlgorithm,微信公众号:FPGA开发圈】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
分享:

评论

相关推荐

bit位标量是什么意思?有什么作用?

bit是什么?sbit又是什么? bit位标量是什么意思?有什么作用? sfr与sfr16有什么区别? ...
发表于 07-15 07:53 0次 阅读
bit位标量是什么意思?有什么作用?

可否分享一下64bit环境能用的TSMC130 PDK?

坛友们,有没有64bit环境能用的TSMC130 PDK?可否分享一下 ...
发表于 06-22 08:10 0次 阅读
可否分享一下64bit环境能用的TSMC130 PDK?

位流检测器(用于S/PDIF)下载产生码

位流检测器(用于S/PDIF)下载产生码
发表于 04-12 20:42 36次 阅读
位流检测器(用于S/PDIF)下载产生码

CDC单bit脉冲跨时钟域的处理介绍

单bit 脉冲跨时钟域处理 简要概述: 在上一篇讲了总线全握手跨时钟处理,本文讲述单bit脉冲跨时钟....
的头像 甘师傅汽车电路修理 发表于 03-22 09:54 565次 阅读
CDC单bit脉冲跨时钟域的处理介绍

请问Micro:bit如何连接Rotation Sensor模块?

本章将介绍Micro:bit连接Rotation Sensor模块的使用,可用于计算顺时针和逆时针旋转的角度和旋转圈数。 ...
发表于 11-19 06:00 202次 阅读
请问Micro:bit如何连接Rotation Sensor模块?

请问micro:bit光速上手硬件编程的步骤是什么?

micro:bit怎么玩?
发表于 11-13 06:30 101次 阅读
请问micro:bit光速上手硬件编程的步骤是什么?

哪位大神详细介绍bit的引脚?

BBC micro:bit引脚介绍
发表于 11-09 08:14 303次 阅读
哪位大神详细介绍bit的引脚?

请问Micro:bit如何对外界光照强度进行检测?

Micro:bit对外界光照强度的检测
发表于 11-09 07:31 101次 阅读
请问Micro:bit如何对外界光照强度进行检测?

请问Micro:bit的板载有哪些应用?

Micro:bit的板载应用主要包括:图像、文本、数学、游戏。 ...
发表于 11-06 07:55 101次 阅读
请问Micro:bit的板载有哪些应用?

什么是Micro:bit设计的迷你钢琴音乐扩展板

Micro:bit设计的迷你钢琴音乐扩展板是什么
发表于 11-06 07:03 101次 阅读
什么是Micro:bit设计的迷你钢琴音乐扩展板

请问电路专用还是逻辑添加到我的.bit文件中?

我们正在硬件中使用Artix 7(A750T)设备。 作为检查的一部分,我们正在检测SCLK,MOSI,MISO,FCS_B信号。...
发表于 08-10 10:18 101次 阅读
请问电路专用还是逻辑添加到我的.bit文件中?

怎么尝试为QSPI引导设备配置BIT文件?

使用Vivado V2014.4。 我的主板采用Micron N25Q128A QSPI作为配置器件。 BIT文件必须配置为4X。我将以下语句添...
发表于 07-30 10:38 101次 阅读
怎么尝试为QSPI引导设备配置BIT文件?

可以用Micro bit DIY制作智能小风扇

用Micro Bit的DIY小制作—智能小风扇。前面已经给大家介绍了Micro Bit相关的几款编程....
发表于 04-19 14:16 3921次 阅读
可以用Micro bit DIY制作智能小风扇

需要了解Micro bit 及开发工具的原理和介绍

说到Micro:bit或许在很多人眼里看来并不陌生了,这几年在国外比较流行,但是在国内,其热度还是要....
发表于 04-19 14:10 6256次 阅读
需要了解Micro bit 及开发工具的原理和介绍

51单片机的bit数据类型详细资料说明

bit是C51编译器的一种扩充数据类型,利用它可定义一个位标量,但不能定义位指针,也不能定义位数组。....
发表于 04-15 18:24 513次 阅读
51单片机的bit数据类型详细资料说明

牛人制作8-bit计算机

很多用户们在计算机中遇到bit都不知道其中中文含义是什么,那么具体是什么意思呢?别着急,接下来就一起....
的头像 发烧友学院 发表于 02-25 15:25 2531次 阅读
牛人制作8-bit计算机

设置Vivado压缩BIT文件的两种方法

在调试Vivado 过程中,由于生成的BIT文件过大,而我使用的FLASH又是32MBIT的,出现了....
发表于 12-22 14:21 5151次 阅读
设置Vivado压缩BIT文件的两种方法

RM022020台式功率放大器的详细数据手册免费下载

适合使用驱动器/助推器放大器,使更多的功率入射到被测器件(DUT)上。这个放大器是行波管放大器的极好....
发表于 08-16 11:27 470次 阅读
RM022020台式功率放大器的详细数据手册免费下载

bit和int char基本认识及区别

 bit和int char之类的差不多,只不过char=8位, bit=“1位而已”。都是变量,编译....
发表于 08-06 08:00 1765次 阅读
bit和int char基本认识及区别

18个C源码实例合集(4bit_lcd,4路温度报警器)等详细资料免费下载

18个C源码实例合集包括了:(4bit_lcd,4路温度报警器,8x8LED汉字显示,ad_da,c....
发表于 07-23 08:00 517次 阅读
18个C源码实例合集(4bit_lcd,4路温度报警器)等详细资料免费下载

Vivado中综合实现和出bit文件步骤教程

本文详解综合实现和出bit文件。各Block都搭建完成后,选中这个bd右键,Generate Out....
的头像 Hx 发表于 07-05 01:21 28026次 阅读
Vivado中综合实现和出bit文件步骤教程

LM4F232中16 32bit位通用定时器模块的详细中文资料概述

下面我们认识下Stellaris系列的通用定时器。在LM4F系列ARM的内部通常集成有6个16/32....
发表于 05-08 16:59 891次 阅读
LM4F232中16 32bit位通用定时器模块的详细中文资料概述

这是一款经典的遥测信号处理器测试方案

可测试性定义为:产品能及时准确地确定其状态,隔离其内部故障的设计特性,以提高产品可测试性为目的而进行....
的头像 电子设计 发表于 12-13 17:47 5210次 阅读
这是一款经典的遥测信号处理器测试方案

船载测控雷达信道系统的BIT设计

随着测控技术的迅速发展,现代测控雷达的功能越来越多,集成化和数字化程度越来越高,结构也越来越复杂。测....
发表于 11-14 16:33 573次 阅读
船载测控雷达信道系统的BIT设计

4bit_lcd_源代码

以前寫論文收集的一些資料,學習單片機、C語言、Proteus的好資料!!!!
发表于 10-25 14:59 472次 阅读
4bit_lcd_源代码

提高遥测信号处理器测试性的一种方法

随着集成电路设计方法与工艺技术的不断进步,集成电路的可测性已经成为提高产品可靠性和成品率的重要因素。....
发表于 01-19 09:28 1071次 阅读
提高遥测信号处理器测试性的一种方法

战术导弹雷达导引系统BIT设计与分析

针对导弹武器系统设备故障检测及隔离困难的问题,介绍了机内检测(BIT)的概念及其在雷达导引系统中的作....
发表于 04-15 18:37 586次 阅读
战术导弹雷达导引系统BIT设计与分析

Agilent 81150A With Arbitrary

• Any ideal and real-world signals from puls....
发表于 08-12 10:53 323次 阅读
Agilent 81150A With Arbitrary

74ls373 datasheet (8-bit regis

These 8-bit registers feature totem-pole TRI-STATE....
发表于 04-13 08:15 568次 阅读
74ls373 datasheet (8-bit regis