樹狀陣列入門

2022-07-06 01:48:09 字數 3250 閱讀 4754

最近初學樹狀陣列,原理還不是太理解,等自己什麼時候完全理解了再自己總結一番。

先貼一下樹狀陣列的模板**:

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,最後輸出整個陣列每個元素的值。更新區間...