樹狀數組定義:html
是一個查詢和修改複雜度都爲log(n)的數據結構。能夠用於處理前綴和的問題,動態維護前綴和的工具數組
區間修改和區間查詢用樹狀數組會顯得很麻煩 相對而言用線段樹會更靈活。數據結構
基本操做:求數列區間和,能夠對數列單點進行操做。ide
前置知識:工具
差分數組spa
lowbit()操做:返回非負整數x 在二進制表示下,第一個1和後面的0表示的數值(十進制的值)。3d
int lowbit(int x) { return x&(-x); } /* -i 表明i的負數 計算機中負數使用對應的正數的補碼來表示
k表示i的二進制中末尾連續0的個數。 例如 : i=6(0110) 此時 k=1 -i=-6=(1001+1)=(1010) i&(-i)=(0010)=2=2^K k=1. C[i]=A[i-2^k+1]+A[i-2^k+2]+......A[i]; C[i]=A[i-lowbit(i)+1]+A[i-lowbit(i)+2]+......A[i]; */
樹狀數組思想:code
區間查詢——》前綴和 ——》樹結構維護(log2n)htm
樹狀數組 t[x] 保存以x爲根的子樹中葉節值的和 。blog
觀察 t[x] 中每一個x的二進制,每一層末尾零相同 ,零的個數即K對應覆蓋的長度,覆蓋長度就是lowbit(x)。
t [x] 的父節點爲 t【x+lowbit[x]】 樹的深度爲 log2n+1
基本操做(單點修改 查詢前綴和)
void update(int i,int val)//單點更新 { while(i<=n){ t[i]+=val; i+=lowbit(i);//由葉子節點向上更新樹狀數組C,從左往右更新 } } int ask(int x)//求區間[1,i]內全部元素的和 即求前綴和 { int ans=0; while(x>0){ ans+=t[x];//從右往左累加求和 x-=lowbit(x); } return ans; }
樹狀數組初始化
memset(a, 0, sizeof a);
memset(c, 0, sizeof c);
cin>>n;
for(int i = 1; i <= n; i++){
cin>>a[i];
updata(i,a[i]); //輸入初值的時候,也至關於更新了值
}
樹狀數組的用法
1.單點修改,單點查詢 update(x,val) ; ask(x) - ask(x-1);
2.單點修改,區間查詢 update(x,val) ; ask(r) - ask(l-1);
3.區間修改,單點查詢 (差分數組 )
用樹狀數組維護差分數組的前綴和,即原數列的每一個元素,因爲區間修改 ,產生的改變量。
區間修改 [l,r]+d update(l,d) update(r+1,-d)
查詢 a[x] ans =a[x]+ask(X)
4. 區間修改,區間查詢
求出原數列a[x]的前綴和 ans=a[r]-a[l] 原數列的前綴和也能夠用差分數組來求