详细易懂 树状数组

树状数组是解决动态前缀和问题的数据结构

比如会给你N个数据,a1,a2,a3...an;

询问a1+a2+a3+...+m

修改ai(1<=i<=n)

暴力:复杂度为O(n^2)

我们来看这个树状数组图

根据图可看出   d[6]=a5+a6  6的二进制是110,所以它末尾0的个数是1,所以它需要存储2^1, 也就是两个元素

同理  d[8]=a1+a2+...+a8, 8的二进制是1000,末尾0的个数为3,所以它需要存储2^3,也就是8个元素

如果说要询问14到1的和,则直接找d[14]+d[12]+d[8]前缀后相加,它不需要将14个和相加起来,这样就可保证查询复杂度是O(logn)

那么它具体是什么原理呢,我们要询问13这个位置的前缀和,1101=13,树状数组的原理其实是个二进制拆分,

它将1101拆成三部分

1101 对应的是d[13] 2^0

1100 d[12] 2^2

1000 d[8]  2^3

每次抹掉最后一个1.因此如果我们要得到13的前缀和,则需要这三个的前缀和,十分巧妙。

所以修改数据时需要将包含这个区间的值也修改。

二进制数末尾的1在哪里,这个问题如何实现呢

lowbit(int x){

return x&(-x)

}

它的实现是由补码表示法,感兴趣的可以去查阅资料,在这里不多赘述了。

伪代码

int d[100005]

int lowbit(int x)

{

return x&(-x);

}

//查询操作如下

int query(int x)//查询x位置的前缀和

{int res=0;

while(x)

{res+=d[x];

x-=lowbit(x);

}

return res;

}

//修改  就是查询操作倒过来

void add(int x,int v)//对d[x]加上V

{

while(x<=n)

d[x]+=v;

x+=lowbit(x);

}

}

树状数组还可以解决区间加/单点查询问题

区间和 ?  【5,8】=sum(8)-sum(4)

 

如何对区间【3,6】的每个数加上5,在3这个位置+5,7的位置上-5;意思是假如1-7的初始值都为0;3加上5,6+1=7的位置上则减5,这样查询1-2时为0,3-6时为5,而查询7这个区间为0,消除了之前+5的影响。

 

 

 

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值