超详细树状数组讲解(原理+代码实现+拓展)

写在前面

话说挑个阴间时间发就没人看了罢(

这篇文章真的废了我很多心血,接下来几个月上学,可能没有很多时间写博客,所以难免会出现一些错误和讲得不够详细的地方,欢迎大家评论指出!

1 为什么要用树状数组

1.1 树状数组的用处

在做题的时候,经常会遇到“单点修改+区间查询”“区间修改+单点查询”“求逆序对个数”之类的问题。

如果只用一般的思路去写,很容易写出  O(nq)  的做法——

对于每个询问,遍历询问区间进行修改/查询。

但是当数据量加大的时候,就只能用树状数组优越的小常数以及  \displaystyle O(q\,\log_2n)  的时间复杂度进行优化。

1.2 树状数组?线段树?

另一种数据结构“线段树”与树状数组的时间复杂度大体相似,但我不会线段树

线段树的常数比树状数组略大一些,而且它的代码量更大;

不过它能解决的问题比树状数组多一点,但是树状数组也可以解决大部分线段树问题才怪

2 树状数组原理

2.1 思想

树状数组本质其实就是在维护一个前缀和/差分。

在“单点修改+区间查询”和求逆序对的时候用的就是前缀和的思想,“区间修改+单点查询”也要用到差分思想,所以不会前缀和和差分的点这里

2.2 树?数组?

为什么把“数组”和“树”两个相反的词放在一起呢?

其实树状数组从实现上看是一个数组,它的定义是:

1) int lowbit(int x) 返回 x 转为二进制后最后一个 1 的位置所代表的数值

e.g.  (34)_{10} = (100010)_2  所以返回  (10)_2 = (2)_{10} 

2) 定义 tree 数组为 a 数组的树状数组 tree[i] = a[i-lowbit(i)+1] + a[i-lowbit(i)+2] + ... + a[i]

\displaystyle tree_i=\sum_{j\in (i-lowbit(i),\,i]}a_j

为什么说这是个树呢?请看VCR:

图中t[i]就是前面的 tree[i] , tree[i] 对应绿

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值