掌握樹狀陣列 徹底入門

2021-09-10 06:33:04 字數 3576 閱讀 9366

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

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;

最後說一下樹狀陣列的優缺點:①特點:**短小,實現簡單;容易擴充套件到高緯度的資料;

②缺點:只能用於求和,不能求最大/小值;不能動態插入;資料多時,空間壓力大。

掌握樹狀陣列 徹底入門

大佬部落格 先貼一下樹狀陣列的模板 int lowbit int i void update int i,int val 單點更新 int sum int i 求區間 1,i 內所有元素的和 return ret 模板中最常見的三個函式 取陣列下標二進位製非0最低位所表示的值 單點更新 區間查詢。樹...

樹狀陣列徹底入門

int lowbit int t void add int x,int y int getsum int x 這篇筆記 會詳細的講解,使得隊員們對樹狀陣列徹底入門 而不是懵懵懂懂。以上先給出 最常見的,三個函式。單點更新,區間查詢 網上的解釋以及分析有很多,這裡是我的一點總結和體會歸納一下,並且在週...

樹狀陣列1 樹狀陣列入門

仔細看一下,發現tree的每乙個節點的高度並不是隨意的,而是由它轉成二進位制之後末尾連續零的數量決定的,連續零的數量加1,就是高度,例如 3 11 零的數量為0,加1等於1,所以它的高度就是1 6 110 零的數量為1,加1等於2,所以它的高度就是2 8 1000 零的數量為3,加1等於4,所以它的...