5.3 树状数组

哎 树状数组是个什么东西嘞?

它的英文名叫做 Binary indexed tree 翻译成中文怎么是 二进制索引树?

没错。。它确实有个小名叫二元索引树。就是一棵被人类利用的小树罢了。。

 

那它是用来干什么的呢?

维基百科和百度百科都这样说:其初衷是解决数据压缩里的累积频率(Cumulative Frequency)的计算问题,现多用于高效计算数列的前缀和, 区间和。它可以以O(\log n)的时间得到任意前缀和\sum_{i=1}^{j}A[i], 1\leqslant j\leqslant N,并同时支持在O(\log n)时间内支持动态单点值的修改。空间复杂度O(n)

提取和总结一下有用的信息:高效  计算区间和/前缀和  修改区间值  

(但是我看视频的时候有说到其实它应用挺多的。。但 至少现在为止对我来说有用的只有这些。小的方面看的话也就是你做算法题的时候数据太大超时。。用一下这个。大的看一下就是处理大数据上啊巴拉巴拉之类的地方可以用到。。

 

那树状数组的原理又是什么呢?

嗯。。看完讲解的视频。没看懂。。感觉跟以前的数学归纳法差不多。。显而易见。。由规律可得。。可以自行去b站搜索关键词:树状数组。

 

接下来上图(乱涂乱画= =

它虽然长得跟树不一样 但其实本质是一样的  如图可见 16存储的是[1, 16]的值 15存储的是[15]的值 14存储的是[13, 14]的值 12存储的是[9, 12]的值

那到底怎么知道一个节点存储的长度/存储的哪些数字呢

 

接下来引入一个知识 lowbit => 

原理:我大概也知道是什么补码啊乱七八糟的与运算啊什么的  可我确实不明白它为什么要这么做

作用:取一个数转化为二进制后最右边的1与它右边的0所组成的数

举个栗子:6 => 110 | lowbit(6) = 10 = 2

不如再举一个 9 => 1001 | lowbit(9) = 1 = 1

显而易见(笑死 上下文照应)的是 每个节点存储的区间长度就是它的lowbit得到的值 比如上面的6 lowbit计算出来的值是2 也就是它存储的区间长度是2 也就是 5 6 的值的和

 

好了其实最重要的还是我们怎么利用这个树状数组

首先。计算前缀和

直接上结论(就是不懂原理我本人):就是在二进制下每一个1的位置减1。

比如6 => 110  = 110 + 100 = 6 + 4(要求到第6个的前缀和就是求6节点和4节点的值)(6节点存储的是 6 + 5 4节点存储的是 4 + 3 + 2 + 1)

       7 = > 111 = 111 + 110 + 100 = 6 + 4 + 1

 

然后。修改区间和

继续上结论:在二进制下的每一个1 加 1

比如 修改了6的值以后 要修改的区间(以上图为例,最大是16)6 => 110 修改 它本身+(先最右边的1加1)1000(8)+ 继续加1 10000(16)

 

蓝后。上代码。

我们怎么做查询呢?

得先搞个lowbit函数

int lowbit(int x)
{
    return x & (-x);
}

接下来开始做查询(但是这里的查询的起始值都是数组的开头)

// 查询数组开头到x的区间和 其中c是树状数组
int query(int x) 
{
    int res = 0;
    while(x > 0)
    {
        res += c[x];
        x -= lowbit(x);
    }
    return res;
}

然后是更新数据

void updata(int i, int k)//在第i个位置加上k
{
    while(i <= n)        //n表示数组的末位
    {
        c[i] += k;
        i += lowbit(i);
    }
}
 

 

哎突然停止了。。因为吃个午饭睡个午觉以后突然进入老年人的脑子了= =

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值