初学树状数组(BIT)

初学树状数组(BIT)

菜鸟来学习树状数组了(耶)
还是从一个经典的问题引入吧

问题

对于一个长度为n的数列,有如下两种操作:
1.将元素ak加上x
2.查询任意一段区间的和。
(当然,两种操作都要进行多次)
在上面的问题中,其实只要能求到a1+a2+…的值,就可以解决问题了

为什么要有树状数组

(以下纯粹为个人意会,如有误,轻喷)


对于任意一个数字,我们都可以将其表示为2的幂次的和的形式,而且这种表示唯一。原因:任意一个十进制数都可以表示为唯一 一个二进制数。
比如,我们想求出a1+a2+…+a16
又想求出a1+a2+…+a19
常规的,我们一个一个加过去,时间复杂度为O(n),如果要做很多次这种操作,时间话费就很大
但是,我们知道,16=2^4 ,19=2^4 +2^1 +2^0
那么,假设我们知道a1+a2+…+a16、a17+a18、a19的值,并且存下来,那么,求和是不是会快很多?(logn级别的)
那你也许会问:为什么不是保存a1,a2+a3,a4+a5+…+a19呢?
因为这样没法统一啊。比如说这样你就没法求a1+a2+…+a16。
于是,lowbit和树状数组就诞生了。

lowbit函数

#define lowbit(x) ((x)&-(x))
(x是正整数)

这个函数实际上是寻找x的二进制表示中最低位的1出现的位置。(补码)

x1 2 3 4 5 6 7 8 9
x的二进制1 10 11 100 101 110 111 1000 1001
lowbit(x)1 2 1 4 1 2 1 8 1
tree[1]的值a1
tree[2]的值a1+a2
tree[3]的值a3
tree[4]的值a1+a2+a3+a4
tree[5]的值a5
tree[6]的值a5+a6
tree[7]的值a7
tree[8]的值a1+a2+…+a8

这样安排tree数组是和lowbit相对应的(看tree中项的个数)。不得不说安排很巧妙。当然这只是编程技巧罢了。

void add(int x,int d)
{
    while(x<=n)///n是数组中元素个数
    {
        tree[x]+=d;
        x+=lowbit(x);
    }
}
int sum(int x)
{
    int ans=0;
    while(x>0)
    {
        ans+=tree[x];
        x-=lowbit(x);
    }
    return ans;
}

add

add函数用在初始化tree数组和更新tree中元素。最后代码其实是不用一个叫a[]的数组来存元素的,直接用tree存就好了。
比如说读入第三个数字为4(或者把第三个数字加四).调用add(3,4)
那么,tree[3]肯定被更新为4了(tree[3]+=4)
通过x+=lowbit(x),可以把所有含有a3项的tree数组内容都更新了(实在是妙啊)

sum

sum的思路就是十进制数表示成2的幂次的思路。具体不再详细说明

大抵难点如上。(剩下的就是刷题了。。。)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值