基础树状数组
如果給定一個數組,要你求里面所有數的和,一般都會想到累加。但是當那個數組很大的時候,累加就顯得太耗時了,時間復雜度為O(n),并且采用累加 的方法還有一個局限,那就是,當修改掉數組中的元素后,仍然要你求數組中某段元素的和,就顯得麻煩了。樹狀數組是一個查詢和修改復雜度都為log(n)的數據結構。主要用于查詢任意兩位之間的所有元素之和,但是每次只能修改一個元素的值;經過簡單修改可以在log(n)的復雜度下進行范圍修改,但是這時只能查詢其中一個元素的值。
基本概念:
假設數組a[1..n],那么查詢a[1]+...+a[n]的時間是log級別的,而且是一個在線的數據結構,支持隨時修改某個元素的值,復雜度也為log級別。
如圖所示,c[1]=A[1],c[2]=A[1]+A[2],c[3]=A[3],c[4]=c[2]+c[3]+A[4]=A[1]+A[2]+A[3]+A[4]……;
c[n]=A[n – 2^k + 1]+..…+A[n];k為n的二進制從右往左數0連續的個數。
計算2^k用下面的方法:
int lowbit(int x) {return x&(x^(x-1)); } 利用機器補碼特性,也可以寫成:
int lowbit(int x) {return x&(-x); } x&(-x)是個神奇的方法。
x+=x&(-x)可以找到他的上一個節點,例如x=4,得到8;
x-=x&(-x)就是可以得到x所管轄的下個節點,例如x=7,然后得6,一直循環到x為0,就可以得到7所管轄的區域為1,2,3,4,5,6,7;
void add(int i,int x) {while(i<=n){c[i]=c[i]+x;i+=loebit(i);} }
上面函數是修改的,因為樹狀數組是有管轄區域的,所以只要改一個點,那么它所管轄的店都要修改;
int Sum(int n) {sum=0;while(n>0){sum+=c[n];n-=loebit(n);} }
上面是求和函數;
例如:求1到7的和,代入Sum函數,循環一次走到6,再循環一次走到4,然后就循環結束了;
這是樹狀 數組的基本應用;
大神講解:
http://blog.csdn.net/int64ago/article/details/7429868
http://www.cnblogs.com/zhangshu/archive/2011/08/16/2141396.html
http://blog.csdn.net/shahdza/article/details/6314818
總結
- 上一篇: 小希的迷宫
- 下一篇: Color the ball