透析 树状数组



 

 

简单地研究了一下这个数据结构,在这做个总结摘要。

 

树状数组是一个查询和修改复杂度都为log(n)的数据结构,假设数组a[1...n],那么查询a[1] + …… + a[i] 的时间是log级别的,而且是一个在线的数据结构,支持随时修改某个元素的值,复杂度也为log级别。

 

来观察一下这个图:

 

令这棵树的结点编号为C1C2……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(其中kx二进制末尾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

嗯……这下好了,随便怎么做都超内存。

数状数组怎么解决呢?

首先来看一下一个数的逆序数怎么求?一个数的逆序数为排在其前面又比其大的数的个数总和。

那么可以这么做:每查到一个数时,总能知道现在已经插入了多少个数,利用树状数组,可以很轻松地知道比它小的数有多少个,那么这个数的逆序数不是手到擒来?

此题只求奇偶性,所以开一个布尔数组是最省空间的,读完所有数之后,答案也就出来了。

 

 

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值