标签:
树状数组(Binary Indexed Tree(BIT), Fenwick Tree)是一个查询和修改复杂度都为log(n)的数据结构。主要用于查询任意两位之间的所有元素之和,但是每次只能修改一个元素的值;经过简单修改可 以在log(n)的复杂度下进行范围修改,但是这时只能查询其中一个元素的值,且其常数之小是线段树无法做到的。
如图,其中a数组保存了初始读入的n个值,c数组即为我们构建的树状数组。
那么容易发现:
function lowbit(x:longint):longint; begin exit(x and (-x)); end;
为什么要用这样一个函数呢?事实上经过测试我们发现,对于1-n内某数x,lowbit(x)表示其“管辖”着从它向后共2^lowbit(x)个数的和,而通过这种方法我们可以在不超过logn的时间内求出所有的lowbit加和,得到的就是该长度下的前缀和。
不难证明,对于1-n内的两个数i,j,满足i<=j,sum(i,j)=sum(1,j)-sum(1,i-1);
故对于任意区间,我们都可以用这种方法求解该区间内所有值的和,代码贴上
function sum(l,r:longint):longint; var s1,s2:longint; ans1,ans2:longint; begin s1:=l-1; s2:=r; ans1:=0; ans2:=0; while s1>0 do begin inc(ans1,bit[s1]); dec(s1,lowbit(s1)); end; while s2>0 do begin inc(ans2,bit[s2]); dec(s2,lowbit(s2)); end; exit(ans2-ans1); end;
理解代码后建议自己打一遍,代码细节很多比较容易错
那么对于这样一棵树,它是怎么被构造出来的呢?
procedure in_in(pos,x:longint); begin while pos<=n do begin inc(bit[pos],x); inc(pos,lowbit(pos)); end; end;
当然,对于这样一个神奇的数据结构我们必须了解它的局限性,即——无法进行区间修改(神犇别跟我说什么可以的话,一旦区间修改就只能单点查询一般用不到好的不送= =)
而单点修改也并非仅修改原来的a数组,而是同时修改你所用的“带有区间性质”的数组
单点修改分两种:
1)将一个点的值增加或减少某个值
方法:将其值修改后,用lowbit求出其父节点及之上的节点
直接贴代码,如果lowbit理解深入一定能看懂
procedure change2(x,y:longint); begin while x<=n do begin inc(bit[x],y); inc(x,lowbit(x)); end; end;
2)讲一个点的值改成另一个值
方法:很简单,求出修改后值和修改前值的差即可,再一次变成方法一修改233
代码贴一个
procedure change1(x,y:longint); var ans1,ans2:longint; s1,s2:longint; begin s1:=y-a[x]; s2:=x; while s2<=n do begin inc(bit[s2],s1); inc(s2,lowbit(s2)); end; end;
就是这样,以上所有的代码都可以直接使用,加上变量和主程序就是一个完整的代码。
以上就是本人对于树状数组的一点小心得,如果有问题加我qq:1064864324,记得加备注。
喜欢就收藏一下,记得关注订阅哦亲(卖萌中~~)
标签:
原文地址:http://www.cnblogs.com/victorslave/p/4803277.html