透析 树状数组
来源:互联网 发布:王宝强 日本 知乎 编辑:程序博客网 时间:2024/04/30 08:29
简单地研究了一下这个数据结构,在这做个总结摘要。
树状数组是一个查询和修改复杂度都为log(n)的数据结构,假设数组a[1...n],那么查询a[1] + …… + a[i] 的时间是log级别的,而且是一个在线的数据结构,支持随时修改某个元素的值,复杂度也为log级别。
来观察一下这个图:
令这棵树的结点编号为C1,C2……Cn。令每个结点的值为这棵树的值的总和,那么容易发现:
C1 = A1
C2 = A1 + A2
C3 = A3
C4 = A1 + A2 + A3 + A4
C5 = A5
C6 = A5 + A6
C7 = A7
C8 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8
……
C16 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8 + A9 + A10 + A11 + A12 + A13 + A14 + A15 + A16
这里有一个有趣的性质,下午推了一下发现:
设节点编号为x,那么这个节点管辖的区间为2^k(其中k为x二进制末尾0的个数)个元素。因为这个区间最后一个元素必然为Ax,所以很明显:
Cn = A(n – 2^k + 1) +…… + An
算这个2^k有一个快捷的办法,定义一个函数如下即可:
int lowbit(int x){return x & (x ^ (x – 1));}
查询
当想要查询一个SUM(n)时,可以依据如下算法即可:
由Cn = A(n – 2^k + 1) +…… + An;
Sum(n) = A1+A2+A3+…+An = Cn+C[n-lowbit(n)]+C[(n-lowbit(n))-lowbit(n-lowbit(n))]+…;
step1: 令sum = 0,转第二步;
step2: 假如n <= 0,算法结束,返回sum值,否则sum = sum + Cn,转第三步;
step3: 令n = n – lowbit(n),转第二步。
可以看出,这个算法就是将这一个个区间的和全部加起来,为什么是效率是log(n)的呢?以下给出证明:
n = n – lowbit(n)这一步实际上等价于将n的二进制的最后一个1减去。而n的二进制里最多有log(n)个1,所以查询效率是log(n)的。
修改
那么修改呢,修改一个节点,必须修改其所有祖先,最坏情况下为修改第一个元素,最多有log(n)的祖先。所以修改算法如下(给某个结点i加上x):
step1:当i > n时,算法结束,否则转第二步;
step2: Ci = Ci + x, i = i + lowbit(i)转第一步。
i = i +lowbit(i)这个过程实际上也只是一个把末尾1补为0的过程。
//修改过程必须满足减法规则!
所以整个程序如下:
int lowbit(int t){ return t & (t^(t-1)); }void modify(int pos,int num){ while (pos<=n) { in[pos]+=num; pos+=lowbit(pos); }}int query(int end){ int sum=0; while (end>0) { sum+=in[end]; end-=lowbit(end); } return sum;}memset(in,0,sizeof(in)); //初始化for (i=1;i<=n;i++) modify(i,a[i]);
以下拿这次上海预选赛的一道题做为一个例子好了。
题意:求一个序列逆序数的奇偶性。
如果初看此题,大概要乐死了,不是很轻松?看看限制条件吧:n <= 1000,000,数为1...n
内存限制:5MB
嗯……这下好了,随便怎么做都超内存。
数状数组怎么解决呢?
首先来看一下一个数的逆序数怎么求?一个数的逆序数为排在其前面又比其大的数的个数总和。
那么可以这么做:每查到一个数时,总能知道现在已经插入了多少个数,利用树状数组,可以很轻松地知道比它小的数有多少个,那么这个数的逆序数不是手到擒来?
此题只求奇偶性,所以开一个布尔数组是最省空间的,读完所有数之后,答案也就出来了。
- 透析 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- C#开发:openfiledialog的使用
- tableau desktop(四) 导出和发布
- Dos命令查看端口占用及关闭进程
- 教你写Android网络框架之基本架构
- 2.Android Studio创建安卓项目及项目结构
- 透析 树状数组
- 重载、重写---C#
- MySql5.6 Window超详细安装教程
- 44.扑克牌的顺子
- ibsvm实现简单线性分类
- Leetcode|ZigZag Conversion
- shell 入门教程
- 《程序员的自我修养》读书笔记7
- 我认识的PE文件之相对虚拟地址 + 文件偏移地址