树状数组

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


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

从图中可以看出: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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值