树状数组
来源:互联网 发布:星星宠物 知乎 编辑:程序博客网 时间:2024/06/11 22:45
本文参考:树状数组的文章
一、树状数组特点
经常使用树状数组进行维护和查询的操作,如修改某点的值,求某个区间的和。
- 对于普通数组,修改数组中的值和求和这两个操作在最坏情况下需要O(n)的时间;
对于树状数组,这两个操作的时间均为O(logn)。
图中A为普通数组,C为树状数组。如树状数组第4个元素C4的父节点为C8(4的二进制表示为“0100”,则k=2,4 + 2^2 =8)。
树状数组的存储特点
- 物理空间上以数组形式连续存储;
- 逻辑空间上,对于两数组下标x,y(x < y) ,若有 x + 2^k = y(k等于x的二进制表示中末尾0的个数),则称y为父节点,x为子节点。并且,奇数下标一定为叶子结点。
树状数组的结点含义
- i = 偶数:Ci = Ci所有子节点的值 + Ai;
i = 奇数:Ci = Ai。
如图中可知:C7 = A7C8 = C4 + C6 + C7 + A8 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8 则我们可知,Ci表示一段普通数组A的连续区间和,其中,右区间边界为i,即Ci对应区间的最后一个元素而为Ai;Ci对应的第一个元素是Ci最左下角的叶子结点,而叶子结点的下标,我们可以通过已知的x + 2^k = y关系式求得。 若i的二进制表示为ABCDE1000,则它的左孩子结点为ABCDE0100,按父子关系逆推,有: ABCDE1000 => ABCDE0100 => ABCDE0010 => ABCDE0001 此时,ABCDE0001为叶子结点。
Ci可表示的A数组的区间的元素个数为2^k,故有以下表达式:
Ci=∑j=i−2k+1iA[j]
二、树状数组的求和
对普通数组A的求和表示为
int lowbit(int x){ return k&-k;}/*树状数组求和*/int sum(int x){ int sum = 0; while(x){ sum += C[x]; x -= lowbit(x); } return sum;}
三、树状数组的更新
对树状数组的更新,在树状数组C上进行。因为Ai的改变会影响Ci及其父节点。
/*树状数组的更新*/void add(int x, int num){ while(k < n){ C[x] += num; x += lowbit(x); }}
0 0
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- js实现页面换肤
- codeforces B. Fox And Two Dots (dfs)
- POJ[1002]487-3279
- TCP/IP协议详解——邮差与邮局(2)
- Webpack介绍及入门
- 树状数组
- windows-API劫持(API-HOOK)
- iOS_内购IAP
- 利用TortoiseGit客户端来管理GitHub项目代码
- Power Designer 基础使用
- Android属性allowBackup安全风险浅析
- 一行命令搞定node.js 版本升级
- 设计模式-状态模式(State)
- MapReduce任务运行到running job卡住