树状数组

来源:互联网 发布:淘宝上好看的女装 编辑:程序博客网 时间:2024/06/17 17:55

平常我们经常会遇到一些对数组进行维护查询的操作,比较常见的如:修改某点的值,求某个区间的和。当数据规模不大的时候可以使用朴素方法,但当规模增大后是划不来的。而这两个操作正是树状数组的强项。


树状数组的结构如图所示:

从图中可以看出:c[1] = a[1]

c[2] = a[1] + a[2]

c[3] = a[3]

c[4] = a[1] + a[2] + a[3] + a[4] 等等


树状数组这样的结构,其元素之间的下标就存在一定的对应关系:

int lowbit(int x){    return x&(-x);}
通过lowbit来求出某个结点管辖范围,如果x+=x&(-x),就得到该节点的父节点的下标值,如x=4时,就得到8;而x-=x&(-x),就是得到该节点的管辖区间的下个区间的管辖点,如x=7,代入后6,不断循环到0.


修改某点值的函数:

void update(int x,int num){    while(x<=N)     {         d[x]+=num;         x+=lowbit(x);     }}
对于一般的数组只需要修改点的值即可,然而树状数组存储的其左右子节点的和,所以需要修改所有该点被管辖的区间。比如a[2]减1,所有2被管辖的点4,8,16都应该减1


区间求和函数:

int getSum(int x){    int s=0;    while(x>0)     {         s+=d[x];         x-=lowbit(x);     }    return s;}


两种情况:
一。每次修改的是一个点,所求的是关于某段区间:向上修改,向下求和

二。每次修改的是一个区间,所求的值关于某个点的:要向下修改,将它后面的区间都加一遍,再向后修改,把不必要的修改区间再减去,用他的父节点记录每个点的染色次数。

void update(int x,int num){    while(x>0)     {         d[x]+=num;         x-=lowbit(x);     }}
int getSum(int x){    int s=0;    while(x<=N)     {         s+=d[x];         x+=lowbit(x);     }    return s;}



练习题:POJ 2352  POJ 2155  POJ 2299 POJ3067  POJ 2352 POJ 3321 POJ2309 POJ1990


http://www.cnblogs.com/Penn000/articles/5758324.html

https://www.topcoder.com/community/data-science/data-science-tutorials/binary-indexed-trees/#prob



0 0
原创粉丝点击