数据结构之树状数组

NFC门禁卡复制全解析:从M1卡到UID卡的攻防实践 本文深入解析了NFC门禁卡的安全机制与攻防实践。从M1卡基于Crypto1算法的原理漏洞讲起,详细阐述了利用Proxmark3等工具进行侦听、破解密钥及使用UID卡进行复制的完整攻击链条。同时,为防御方提供了从升级CPU卡、启用全扇区认证到部署多因子验证的系统性防护策略,旨在帮助管理员构建更稳固的物理安全防线。 阅读详情

1、概述

树状数组(binary indexed tree),是一种设计新颖的数组结构,它能够高效地获取数组中连续n个数的和。概括说,树状数组通常用于解决以下问题:数组{a}中的元素可能不断地被修改,怎样才能快速地获取连续几个数的和?

2、树状数组基本操作

传统数组(共n个元素)的元素修改和连续元素求和的复杂度分别为O(1)和O(n)。树状数组通过将线性结构转换成伪树状结构(线性结构只能逐个扫描元素,而树状结构可以实现跳跃式扫描),使得修改和求和复杂度均为O(lgn),大大提高了整体效率。

给定序列(数列)A,我们设一个数组C满足

C[i] = A[i–2^k+ 1] + … + A[i]------【C[i] = a[i-lowbit(i)+1] + …+ a[i]i-lowbit(i)+1 是什么?就是i把最右边的1去掉,然后再加1】

其中,k为i在二进制下末尾0的个数,i从1开始算!

则我们称C为树状数组。

下面的问题是,给定i,如何求2^k?

答案很简单:2k=i&(i^(i-1)) ,也就是i&(-i)

下面进行解释:

---- 这里有错, 应该为(2)10
这里用到低位技术:
  低位技术即Lowbit技术。相信熟悉树状数组(BIT)的朋友应该并不陌生。
  我们对于一个非0数x,现在提取出其最低位的1。这里我提三种不同的写法。
  Lowbit(x)=x&(x^(x-1))
  Lowbit(x)=x&~(x-1)
  Lowbit(x)=x&-x
  注意:这里我们求出的是x中最后一个1表示的数,而非其位置。
  可以发现,这三种低位函数的写法可谓大同小异——均涉及到了x&和x-1(其实 –x 可以认为是和 ~(x-1) 等价的,这里利用了负数的存储原理)。
  x-1的性质在于:其将一个数最后一个1变成了0,并把原来这个1之后0的位置均变成了1。低位技术正是利用了这个性质。

数组C的具体含义如下图所示:


当我们修改A[i]的值时,可以从C[i]往根节点一路上溯,调整这条路上的所有C[]即可,这个操作的复杂度在最坏情况下就是树的高度即O(logn)。另外,对于求数列的前n项和,只需找到n以前的所有最大子树,把其根节点的C加起来即可。不难发现,这些子树的数目是n在二进制时1的个数,或者说是把n展开成2的幂方和时的项数,因此,求和操作的复杂度也是O(logn)。(如求前4项的和,(4)10==(0100)2,所以找出一个就可以,它是c[4];其它也一样).

树状数组能快速求任意区间的和:A[i] + A[i+1] + … + A[j],设sum(k) = A[1]+A[2]+…+A[k],则A[i] + A[i+1] + … + A[j] = sum( j )-sum( i-1 )。

下面给出树状数组的C语言实现:

//*******************求低位*******************//
int lowbit(int t)//lowbit(x) 实际上就是x的二进制表示形式留下最右边的1,其他位都变成0   
{
    return t & ( -t );   
}   

//*******************求前n项和*******************//
int sum(int x)   
{          
    int tot = 0;          
    while(x > 0)        
    {                
        tot += c[x];                
        x -= lowbit(x);//x - lowbit( x )是什么样子?就是x的二进制最右边的1变为0,例如x=7,则sum=c[7]+c[6]+c[4],具体可以见上图并且写出7的二进制0111,可以看出接下来下标为6,4    
    }     
    return tot;  
}   

//*******************更新*******************//   
void update(int pos, int num)   
{         
    while(pos <= n)  //pos + lowbit(pos) 必须小于等于a 的元素个数n       
    {                
        c[pos] += num;                
        pos += lowbit(pos);         
    }   
}      


3、扩展——二维树状数组

一维树状数组很容易扩展到二维,二维树状数组如下所示:

C[x][y] = sum(A[i][j])

其中,x-lowbit[x]+1 <= i<=x且y-lowbit[y]+1 <= j <=y

4、应用

(1)    一维树状数组:

参见:http://hi.baidu.com/lilu03555/blog/item/4118f04429739580b3b7dc74.html

(2)    二维树状数组:

一个由数字构成的大矩阵,能进行两种操作

1) 对矩阵里的某个数加上一个整数(可正可负)

2) 查询某个子矩阵里所有数字的和

要求对每次查询,输出结果

(3)求第k小元素

#define N (1<<20)  
int c[N];  
//复杂度log(n)  
int find_k(int k){  
    int ans = 0,cnt = 0;  
    for(int i=log(double(N-1))/log(2.0);i>=0;i--){//把树状数组的求和反向模拟作二分逼近  
        ans += (1<<i);  
        if(ans>=N || cnt+c[ans]>=k)ans -= (1<<i);  
        else cnt += c[ans];  
    }  
    return ans+1;  
}  


5、总结

树状数组最初是在设计压缩算法时发现的(见参考资料1),现在也会经常用语维护子序列和。它与线段树(具体见:数据结构之线段树)比较在思想上类似,比线段树节省空间且编程复杂度低,但使用范围比线段树小(如查询每个区间最小值问题)。

所以,树状数组适合单个元素经常修改而且还反复要求部分的区间的和的情况。上述问题虽然也可以用线段树解决,但是用树状数组来做,编程效率和程序运行效率都更高。如果每次要修改的不是单个元素,而是一个区间,那就不能用树状数组了(效率过低)。

6、参考资料

(1)    Binary Indexed Trees:

http://www.topcoder.com/tc?module=Static&d1=tutorials&d2=binaryIndexedTrees

(2)    吴豪文章《树状数组》:

http://www.java3z.com/cwbwebhome/article/article19/zip/treearray.zip

(3)    郭炜文章《线段树和树状数组》:强烈建议看一下!!!

http://poj.org/summerschool/1_interval_tree.pdf



















UReport2 报表设计器 在线表格 UReport2官网 一、UReport2报表设计器 UReport2是一个开源的可视化报表设计器,功能强大,操作简单,可以实现复杂的报表统计,有各种各样的导出和打印功能,支持导入Excel表格! 1、报表设计器 2、设计一个简单的用户列表展示 二、可编辑表格 扩展了layui的表格,支持多元化数据编辑(单选,多些、日期、下拉联动),开发简单、高效、便捷。有了它就可以轻松开发类似进销存系统的表格录入功能了,用户拿来即用! 三、主从表录...... 阅读详情

相关推荐

nRF24L01模块性能调优笔记:基于STC8H的SPI通信,如何突破700包/秒的传输瓶颈?

本文详细介绍了如何通过SPI通信优化、nRF24L01寄存器配置和STC8H系统级调优,突破700包/秒的传输瓶颈。从硬件设计到软件实现,提供了一套完整的性能调优方案,特别适合需要高性能无线通信的嵌入式开发者。

weixin_42525211的博客 181

高级数据结构——树状数组原理和实现

通过了解有关树状数组的原理来解决按数字情况排序的题目,然后得到有关树状数组的组成和用法。

薛定谔的猫的博客 459

Renesas:定时器输入捕获

一、PWM输入捕获 1、Smart Configurator配置 注意:在使用前,需要使能对应的定时器!否侧无法正常进行输入捕获! 2、脉冲宽度的获取 如何区分高低电平的脉冲宽度:最常用的方法就是在触发中断后,判断IO口的高低电平,来确认是上升沿触发的中断还是下降沿触发的中断。 若无法进入中断,可查看:Renesas:配置中断的常规流程 (1)中断方式(Smart Configurator生成的代码) #pragma interrupt r_Config_TAUB0_0_i...

不吃鱼的猫的博客 2483

关于lowbit函数

lowbit(x)是x的二进制表达式中最低位的1所对应的值。 比如,6的二进制是110,所以lowbit(6)=2。 最近回头看树状数组,发现关于lowbit()函数,目前有两种算法。 第一种是比较常见的,也是我一直在用的: int lowbit(int x) { return x&(-x); }最近发现了另一种算法,如下所示: int lowbit(int

醉醉的博客 4万+

Ubuntu 20.04 + CARLA 0.9.13 长时运行崩溃?手把手教你定位和缓解Segmentation fault

本文详细解析了Ubuntu 20.04环境下CARLA 0.9.13仿真平台长时运行崩溃问题,提供了从内存监控到核心转储分析的系统级诊断方法,并分享内存泄漏缓解、稳定性优化配置等实用解决方案,帮助开发者构建更稳定的自动驾驶仿真环境。

weixin_28362173的博客 254

calibre:将calibre 的layer number 转换为实际的laymer 名称(7)

可以使用与版图数据库配套的(Standard Verification Rule Format,标准验证规则格式),在 Calibre DESIGNrev 中加载图层名称。

u013620135的博客 984

树状数组简单梳理(上)

树状数组简单梳理(上) 背景 平时做题时我们经常会碰到一类问题: 有一个数组,多次往这个数组上某个点的值增加k,再多次求数组上某个区间所有数组之和。 有一个数组,多次往这个数组某个区间上的值增加k,再多次求某个点的值。   以第一个问题为例,用正常的思路想就有如下操作 //多次往某个点增加k while(t1--)    a[x]+=k; //多次求某个区间所有数字之和 whil...

c0ldHEart的博客 441

详解大端模式和小端模式

详解大端模式和小端模式 一、大端模式和小端模式的起源         关于大端小端名词的由来,有一个有趣的故事,来自于Jonathan Swift的《格利佛游记》:Lilliput和Blefuscu这两个强国在过去的36个月中一直在苦战。战争的原因:大家都知道,吃鸡蛋的时候,原始的方法是打破鸡蛋较大的一端,可以那时的皇帝的祖父由于小时侯吃鸡蛋,按这种方法把手指弄破了,因此他的父亲,就下令,命令

ce123的技术博客 19万+

求二进制数中高位或低位第一次出现1所在的位置

题目: 怎么求二进制数中,第一次出现1

JimmyCai0101的专栏 9696

【知识分享】车载以太网PCB布局设计指南

本文将深入探讨在设计车载以太网设备的印刷电路板(PCB)时需要着重考虑的若干关键主题。这些主题广泛涵盖了数据布线设计,以确保其符合信号完整性(SI)和电磁兼容性(EMC)标准;外部元器件的合理摆放;以及采取有效的抗电磁干扰(EMI)布局策略等方面。通过全面且细致地处理这些关键环节,能够显著提升车载以太网设备的性能与可靠性。

一只豌豆象的博客 1352

使用Transformer实现自动调制识别(RML2016a)

image_size = 128 # resize重置输入大小patch_size = 2 # 从输入图片(信号看作图片)中将被提取的块大小# 分成 num_patches 个块num_patches = (image_size // patch_size) #(72/6)**2 横着裁剪),],return x)(x1, x1)# MLP.# Add MLP.x=x_train,y=y_train,filepath,round。

QAQIknow的博客 6276

树状数组的原理及实现

树状数组 ,顾名思义就是像树一样的数组,当然这里说的是存储方式像树,就像哈希散列表根据哈希函数来储存。 具体怎么存呢。定义每一列的顶端结点C[]数组 图中C[i]代表 子树的叶子结点的权值之和 //这里以维护区间和为例。 C[1]=A[1]; C[2]=A[1]+A[2]; C[3]=A[3]; C[4]=A[1]+A[2]+A[3]+A[4]; C[5]=A[5]; C[6...

小小前端攻城狮的博客 2773

【AN7581】AN7581 SDK编译环境搭建操作说明

安装编译需要的工具包。

wgl307293845的博客 338

数据结构-树状数组

树状数组是一种高效的数据结构,常用来解决区间和问题。本文将对这种数据结构进行介绍,并且给出golang语言的实现。最后以LeetCode 307来介绍如何使用树状数组解决问题。

zhuohuashiyi 1206

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

数据结构————树状数组

树状数组详解

2401_82659959的博客 694

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

树状数组 【数据结构】

本文介绍了树状数组(Fenwick Tree)的基本原理和应用。树状数组是一种高效处理单点修改和区间查询的数据结构,相比线段树具有代码简单、空间复杂度低的优势。核心原理是利用lowbit运算构建树状结构,通过x±lowbit(x)操作实现快速查询和修改。典型应用包括区间求和和求解逆序对问题,其中逆序对问题可通过离散化处理大数情况。文章提供了单点修改区间查询和求解逆序对的具体代码实现,并指出树状数组在复杂操作时可能不如线段树适用。

Juan_2012的博客 1118

【数据结构】—— 树状数组

【数据结构】—— 树状数组

forever_bryant的博客 508

数据结构--树状数组

树状数组或二叉索引树,顾名思义是一个有着树形结构的数组,主要用于高效地处理区间上的查询与搜索问题。需要提及的是树状数组能够解决的问题,使用线段树都能够解决,而线段树能够解决的问题,使用树状数组有可能不能解决,但树状数组优点在于的实现更加简单。

chui_san的博客 718

【数据结构】树状数组

假设一个数可以x可以被二进制分解成x2i1​2i2​...2im​,不妨设i1​i2​...im​,进一步地,区间1x可以分成Ologx2i1​12i1​2i2​2i1​12i1​2i2​...2im​2i1​2i2​...2im−1​12i1​2i2​...2im​这些小区间的共同特点是:若区间结尾为R,则区间长度为low。

Doctor_Anonymous的博客 1309

【数据结构之树状数组】

1、概述 树状数组(binary indexed tree),是一种设计新颖的数组结构,它能够高效地获取数组中连续n个数的和。概括说,树状数组通常用于解决以下问题:数组{a}中的元素可能不断地被修改,怎样才能快速地获取连续几个数的和? 2、树状数组基本操作 传统数组(共n个元素)的元素修改和连续元素求和的复杂度分别为O(1)和O(n)。树状数组通过将线性结构转换成伪树状结

学习之路 561

【算法】树状数组数据结构

树状数组详解与算例分析

一些笔记 1316

数据结构: 树状数组

AlgorithmDataStructureProgramming接下来,我们就来介绍一些经典重要的数据结构。首先是树状数组。实际上,数据结构就相当于一种算法,是在某种结构上实现某算法。树状数组是一个查询和修改复杂度都为Olog2​n的数据结构,运用树状数组可以实现很多算法问题,比如单点修改,区间求和,求逆序对等等。比如区间求和,若n为数列长度,m为查询次数,那么查询总和的最坏时间复杂度为Onm,假设n和m

Leo201111的博客 1257

数据结构——树状数组

区间信息的维护与查询专题———树状数组1.问题来源动态连续和查询问题。给定一个n个元素的数组A1,A2,...,An,你的任务是设计一个数据结构,支持以下两种操作。★ Add(x,d)操作:让Ax增加d.★ Query(L,R):计算AL+AL+1+...+AR.对普通数组进行一次修改或特定区间求和,时间复杂度为O(N),N为修改或求和需要扫描的数组区间大小。但有一种称为树状数组(又称二叉索引树)...

popcjz的博客 1390

进阶数据结构 树状数组

树状数组是一种高效的数据结构,基于二进制分解思想,通过lowbit运算实现O(logN)的区间查询和单点修改。相比线段树,它代码更简洁、常数更小,适合处理单点修改需求高的场景。树状数组利用正整数二进制分解的唯一性,将区间划分为多个小区间进行维护,要求维护的信息具有结合律和可差分性。基本操作包括区间查询和单点修改,通过权值树状数组等变形可解决逆序对等问题。其核心在于利用lowbit划分区间,构建树形结构,使深度保持在O(logN)级别。

2501_92685363的博客 546
上一篇: 数据结构汇总
下一篇: hdu 2492【树状数组】
leolin_
博客等级 码龄16年 96粉丝 411原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值