树状数组基础
来源:互联网 发布:linux mysqldump 编辑:程序博客网 时间:2024/06/08 05:21
与其说是写博贴,不如说是做个总结。几个月前接触了树状数组,首先的感觉是好神奇啊!用那么简单而优美的几行代码就实现了那么强大的功能!mogicmagic啊!一直都很崇拜发明树状树组的人。可惜后来因为被抓去刷文化课去了,就一直没有彻底搞懂树状数组。这几天放假,终于把这个优美的玩意搞清楚了,在这里做个总结。好了,废话少说,开始吧。
一、树状数组是什么?能干啥?能吃吗?
首先,不能吃!
树状数组(Binary Indexed Tree(BIT), Fenwick Tree)是一个查询和修改复杂度都为log(n)的数据结构。主要用于查询任意两位之间的所有元素之和,但是每次只能修改一个元素的值;经过简单修改可以在log(n)的复杂度下进行范围修改,但是这时只能查询其中一个元素的值(如果加入多个辅助数组则可以实现区间修改与区间查询)。 百度百科
说人话
平常我们会遇到一些对数组进行维护查询的操作,比如,修改某点的值、求某个区间的和。一般的暴力,修改的复杂度是O(1),查询的复杂度是O(N)。如果在线的对数组进行M次修改或求和,最坏的情况下复杂度是O(M*N),当规模增大后肯定会爆炸!而树状数组干同样的事复杂度却是O(M*lgN)。厉害啊!
二、树状数组如何实现?
我们先来看张图。这张图是已经用烂了的,也不存在雷不雷同了。
c就是我们为a数组构建的树状数组。来看看规律。容易看出,c[8]表示a[1]~a[8]的和,c[4]表示a[1]~a[4]的和,c[2]表示a[1]~a[2]的和......是不是有种二分的感觉?那树状树组到底是怎么做到的呢?
我们从现在开始,所有的数都用二进制来表示。我们先引入一个概念:lowbit。一个数k的lowbit值就是这个数去掉所有高位的1,只留下最低位的1。比如,0110的lowbit就是0010,0100的lowbit就是0100,0011的lowbit就是0001。lowbit(k)是怎么求的呢?非常简单,就是把k与上-k,即lowbit(k) = k & -k。比如k = 1010,那么-k就是把k取反加1(这是计算机中的补码),即0101 + 1 = 0110,那么k & -k就是1。为什么呢?因为取反后,k的每一位都与取反的k不一样,这时再把取反的k加上1,即-k,那么就能保留下最后一位的1。如果还不明白的话,读者可以自己举几个例子试一试。
好,神奇的地方出现了!我们发现,设c[i]父亲节点为c[j], 那么j = i + lowbit(i)!!比如0001 + 0001 = 0010,0011 + 0001 = 0100,0110 + 0010 = 1000!请记住这个神奇而重要的性质!它在下面的算法中非常重要!至于这个性质的数学证明,请读者自行完成。
那么我们容易发现,如果要更新c[0001],那么我们也要更新c[0010]、c[0100]、c[1000],即它的所有祖先。那么可知,如果要更新c[k],那么要接着更新c[k+lowbit(k)]以及其它祖先。还不懂?上代码!
//第k个数增加x O(lgn)void updata(int k, int x) { while(k <= n) { c[k] += x; k += lowbit(k); }}我们已经会更新了,那查询呢?很简单,把上面的更新直接逆过来写。不多说,上代码!
//求1 ~k的和 O(lgn)int query(int k) { int ans = 0; while(k) { ans += c[k]; k -= lowbit(k); } return ans;}那么,求a~b的和,就直接query(b) - query(a-1)就行了。
附上完整代码
#include<iostream> #include<cstdio>using namespace std;#define N 100001int n;int c[N];int lowbit(int k) {return k & -k;}void updata(int k, int num) {while(k <= n) {c[k] += num;k += lowbit(k);}}int query(int k) {int ans = 0;while(k) {ans += c[k];k -= lowbit(k);}return ans;}int main() {cin >> n;for(int i = 1; i <= n; i++) {int a;scanf("%d", &a);updata(i, a); }int m;cin >> m;while(m--) {int op;int x, y;scanf("%d%d%d", &op, &x, &y);if(op == 1)updata(x, y);elseprintf("%d\n", query(y) - query(x-1));}return 0;}
1 0
- 基础树状数组
- 树状数组基础
- 基础树状数组
- 树状数组基础
- 树状数组基础
- HUD_1556_树状数组基础
- Number sequence 树状数组基础
- 树状数组基础及运用
- codevs树状数组基础练习
- HDU-1541 树状数组(基础题)
- HDU 1166 树状数组 基础题
- poj 2352 Stars(树状数组基础)
- 算法基础 - 树状数组(binary indexed tree)
- LA4329 Ping pong(树状数组基础)
- Java基础 - 树状数组Java版
- 算法基础篇(7)------树状数组
- 简单基础树状数组 HDU 1556
- poj 2352 (树状数组基础题)
- 测试Theano使用GPU并行计算,以验证环境搭建是否成功
- NGN - SIP
- 九大行星
- 联系人导入导出分析
- 1008. Elevator 解析
- 树状数组基础
- Unity3D -- 光照常用函数和变量(Shader学习之二)
- (四十二)线程——线程属性
- NumPy 索引,切片和迭代
- 如何从量化的角度观看股票传统的技术指标
- 微赞WZ_V51.2版本20160706UTF8商业版程序同步完整包 带400多功能模
- zoj1657
- 1009. Product of Polynomials 解析
- LeetCode - 152. Maximum Product Subarray - 思路详解 - C++