树状数组

落笔记下自己的感悟,本文章主要针对与lowbit函数的讲解,单点修改、单点询问与区间询问(用树状数组解决);

当遇到区间修改时,树状数组也能搞定,但是毕竟复杂,没有线段树更实在(线段树的延迟更新)。


lowbit函数


定义:在二进制状态下,最后一位1与其后面的零所构成的数值。

   例如:    (12)10进制 ------进制转换------  (11002进制

上例,红色部分(100)即是末尾1与其后面的零构成的数值。其值转成十进制为4;

所以  lowbit(12) =  4;

如何用代码实现lowbit函数?

    不难发现,实现方法:     lowbit(n)=n&(~n+1)

    然后又发现   (~n+1) 不就是取反加1嘛,不就是-n的补码?

    然后计算机存储的是补码,所以总结:  lowbit(n)=  (n)&(-n)


树状数组的实现原理


给出下图,已经建立好了树状数组。

树上结点数值的红色部分即lowbit函数值,也是该结点存下的区间长度值。

例1:

树结点4,   lowbit(4)=(100)= 4,  区间长度为4,即存下4个数(分别是数组结点1,2,3,4)

例2:

树结点6,lowbit(6)=(10)2   =   2,存长度为2的数值,分别是array【5】、array【6】


规律


1.建立的树状数组上,每一层的lowbit函数值相等。

2.lowbit函数值记录的是      区间长度。

3.树上编号为x的节点, 他的父节点编号为x+lowbit(x)

4.整棵树的深度为:  (log2n )+ 1

5.找下一个结点    x-=lowbit(x)


代码


当要单点更新时,先更新底层,然后依次更新其父节点,一直到根结点。

用代码实现则运用上述规律3。

 1 int lowbit(int n){
 2     return n&(-n);
 3 }
 4 
 5 
 6 //在叶节点x  增加 数值k 
 7 void add(int x,int k){
 8     for (;x<=n;x+=lowbit(x)){
 9         root[x]+=k;
10     }
11 } 

  

区间查询运用规律5

 1 int lowbit(int n){
 2     return n&(-n);
 3 }
 4 
 5 // 区间查询 
 6 
 7 int ask(int x){
 8     int ans=0;
 9     for (;x;x-=lowbit(x))
10         ans+=root[x];
11     return ans;
12 } 

例如上图查询区间【1,7】的和  == root【7】+root【6】+root【4】

当遇到查询【l,r】区间和时,我们应该知道树状数组大多是用来维护前缀和的,那么只要查询两次区间和  ,然后【1,r】减去【1,l-1】就是答案。

原文地址:https://www.cnblogs.com/q1204675546/p/14038858.html