最近初學樹狀陣列,原理還不是太理解,等自己什麼時候完全理解了再自己總結一番。
先貼一下樹狀陣列的模板**:
int lowbit(int i)
void update(int i,int val)//單點更新
}int sum(int i)//求區間[1,i]內所有元素的和
return ret;
}
模板中最常見的三個函式:①取陣列下標二進位製非0最低位所表示的值;②單點更新;③區間查詢。樹狀陣列,顧名思義是樹狀的陣列,我們首先引入二叉樹,葉子節點代表a[1]~a[8]。
現在變形一下:
現在定義每一列的頂端節點c陣列(其實c陣列就是樹狀陣列),如圖:
c[i]代表子樹的葉子節點的權值之和,如圖可以知道:
c[1]=a[1];
c[2]=a[1]+a[2];
c[3]=a[3];
c[4]=a[1]+a[2]+a[3]+a[4];
c[5]=a[5];
c[6]=a[5]+a[6];
c[7]=a[7];
c[8]=a[1]+a[2]+a[3]+a[4]+a[5]+a[6]+a[7]+a[8];
將c陣列的下標i轉化成二進位制:
1=(001) c[1]=a[1];
2=(010) c[2]=a[1]+a[2];
3=(011) c[3]=a[3];
4=(100) c[4]=a[1]+a[2]+a[3]+a[4];
5=(101) c[5]=a[5];
6=(110) c[6]=a[5]+a[6];
7=(111) c[7]=a[7];
8=(1000) c[8]=a[1]+a[2]+a[3]+a[4]+a[5]+a[6]+a[7]+a[8];
對照式子可以發現:c[i]=a[i-2^k+1]+a[i-2^k+2]+......+a[i];(k為i的二進位制中從最低位到最高位連續零的個數)
例如:當i=8時,k=3,可以自行代入驗證。現在引入lowbit(x):其實就是取出x的二進位制的最低位1,換言之,lowbit(x)= 2^k,k的含義與上面相同。
int lowbit(int i)
/*-i 代表i的負數 計算機中負數使用對應的正數的補碼來表示
例如 : i=6(0110) 此時 k=1
-i=-6=(1001+1)=(1010)
i&(-i)=(0010)=2=2^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];
*/
接下來是區間查詢(求和):利用c[i]陣列,求a陣列中前i項和:舉兩個栗子:
①i=7,前7項和:sum[7]=a[1]+a[2]+a[3]+a[4]+a[5]+a[6]+a[7];
而c[4]=a[1]+a[2]+a[3]+a[4];c[6]=a[5]+a[6];c[7]=a[7];可以得到:sum[7]=c[4]+c[6]+c[7]。
陣列下標寫成二進位制:sum[(111)]=c[(100)]+c[(110)]+c[(111)];
②i=5,前5項和:sum[5]=a[1]+a[2]+a[3]+a[4]+a[5];
而c[4]=a[1]+a[2]+a[3]+a[4];c[5]=a[5];可以得到:sum[5]=c[4]+c[5];
陣列下標寫成二進位制:sum[(101)]=c[(100)]+c[(101)];
細細觀察二進位制,樹狀陣列追其根本就是二進位制的應用,結合**演示一下**過程:
int sum(int i)//求區間[1,i]所有元素的和
return ret;
}
對於i=7進行演示:
7(111) ans+=c[7]
lowbit(7)=001 7-lowbit(7)=6(110) ans+=c[6]
lowbit(6)=010 6-lowbit(6)=4(100) ans+=c[4]
lowbit(4)=100 4-lowbit(4)=0(000) break;
對於i=5進行演示:
5(101) ans+=c[5]
lowbit(5)=001 5-lowbit(5)=4(100) ans+=c[4]
lowbit(4)=100 4-lowbit(4)=0(000) break;
最後是單點更新:當我們修改a陣列中某個值時,應當如何更新c陣列呢?回想一下,區間查詢的過程,再看一下上文中列出的過程。這裡宣告一下:單點更新實際上是不修改a陣列的,而是修改樹狀陣列c,向上更新區間長度為lowbit(i)所代表的節點的值。
void update(int i,int val)//更新單節點的值
} //可以發現 更新過程是查詢過程的逆過程
//由葉子結點向上更新c陣列
如圖:當在a[1]加上值val,即更新a[1]時,需要向上更新c[1],c[2],c[4],c[8],這個時候只需將這4個節點每個節點的值加上val即可。這裡為了方便大家理解,人為新增了個a陣列表示每個葉子節點的值,事實上a陣列並不用修改,實際運用中也可不設定a陣列,單點更新只需修改樹狀陣列c即可。下標寫成二進位制:c[(001)],c[(010)],c[(100)],c[(1000)];
lowbit(1)=001 1+lowbit(1)=2(010) c[2]+=val;
lowbit(2)=010 2+lowbit(2)=4(100) c[4]+=val;
lowbit(4)=100 4+lowbit(4)=8(1000) c[8]+=val;
最後說一下樹狀陣列的優缺點:①特點:**短小,實現簡單;容易擴充套件到高緯度的資料;
②缺點:只能用於求和,不能求最大/小值;不能動態插入;資料多時,空間壓力大。
霜雪千年
樹狀陣列1 樹狀陣列入門
仔細看一下,發現tree的每乙個節點的高度並不是隨意的,而是由它轉成二進位制之後末尾連續零的數量決定的,連續零的數量加1,就是高度,例如 3 11 零的數量為0,加1等於1,所以它的高度就是1 6 110 零的數量為1,加1等於2,所以它的高度就是2 8 1000 零的數量為3,加1等於4,所以它的...
樹狀陣列 入門
樹狀陣列,乙個用來區間求和修改都為log n 的演算法。在網上資料很多,看起來也不是很難,學習一下!基本上學習樹狀陣列都會看到下面這個圖,這也是最基本的乙個圖,看懂這個以後,對樹狀陣列也就會有 一定的了解了。令這棵樹的結點編號為c1,c2.cn。令每個結點的值為這棵子樹的值的總和,那麼容易發現 c1...
樹狀陣列入門
用office做了一張pdf 這是一維的情形,如果是二維,可以把每一行的一維樹狀陣列看成乙個節點,然後再把二維樹狀陣列看成一維樹狀陣列。好文章 兩道入門題 對於第一題hdu1556 題意 初始陣列元素值都為0,給定區間 x,y 將區間 x,y 每個元素的值 1,最後輸出整個陣列每個元素的值。更新區間...