樹狀陣列【學習B站視訊筆記】
樹狀陣列
1、樹狀陣列是什麼
樹狀陣列是一個查詢和修改複雜度都為log(n)的資料結構。主要用於查詢任意兩位之間的所有元素之和。但是每次只能修改一個元素的值。
2、樹狀陣列幹什麼用的
最簡單的樹狀陣列就是用來解決動態字首和問題的資料結構。這個陣列是動態的,也就是說這些值在某些時候會發生變化。
3、樹狀陣列具體圖解
令這棵樹的結點編號為C1,C2...Cn。令每個結點的值為這棵樹的值的總和,那麼容易發現:
C1 = A1
C2 = A1 + A2
C3 = A3
C4 = A1 + A2 + A3 + A4
C5 = A5
C6 = A5 + A6
C7 = A7
C8 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8
...
C16 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8 + A9 + A10 + A11 + A12 + A13 + A14 + A15 + A16
這裡有一個有趣的性質:
設節點編號為x,那麼這個節點管轄的區間為2^k(其中k為x二進位制末尾0的個數)個元素。因為這個區間最後一個元素必然為Ax,
所以很明顯:Cn = A(n – 2^k + 1) + ... + An
舉例:
13=1101=A[13];
往前找:12=1100=A[9]+A[10]+A[11]+A[12];
繼續往前找 8=1000=A[1]+..A[8];
可以看出是逐漸消1致0得出的結果。
可以用Lowbit:x&(-x)實現。
同時從這裡的樹也可以分析出來:對一個值的改變能夠影響的總體是沿著樹往上走的,
每一次都向非0位過後的第一個最小的0變為1上升:10001100=>10011100.
目前不知道具體這個上升這麼操作的原因是什麼。//PS:有大神知道能否告訴我一下 靴靴。
HDU 1166
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<set> using namespace std; int sum[200050]; int n; int lowbit(int x) { return x&(-x); } //返回最小的值 void update(int pos,int val)//單點修改 { while(pos<=n) { sum[pos]+=val; pos+=lowbit(pos); } }//維護的是字首和 int query(int pos) { if(pos==0)return 0; int s=0; while(pos) { s+=sum[pos]; pos-=lowbit(pos); } return s; }//就算是前面的更新,也只是把需要用到的更新了,求區間和的時候需要按1的位置加起來。 int main() { string s; int T; cin>>T; int i,j; int cnt=0,pre; while(T--) { cin>>n; printf("Case %d:\n",++cnt); memset(sum,0,sizeof(sum)); for(int k=1;k<=n;k++) { scanf("%d",&pre); update(k,pre); } cin>>s; while(s[0]!='E') { if(s[0]=='A') { cin>>i>>j; update(i,j); } if(s[0]=='S') { cin>>i>>j; update(i,-j); } if(s[0]=='Q') { cin>>i>>j; cout<<query(j)-query(i-1)<<endl; } cin>>s; } } }