看懂樹狀陣列

2021-07-26 19:38:46 字數 1654 閱讀 9778

恩,今天一下午都花在搞樹狀陣列上面去了吧。現在才認清楚樹狀陣列的一些東西。

我們先看樹狀陣列的結構 如圖

他的規律就是c[x]永遠有一條線連到a[x],c[x]之前絕對沒有連到a[x]的線

c[2^n]=a[1]到a[2^n]的和

c[2k+1]=a[2k+1]

c[2^n-2k]=c[2^(n-1)]+a[2^(n-1)+1]到a[2^n-2k]的和(2^n-2k>2^(n-1))

現在介紹三個函式

第乙個函式:

int lowbit(int x)  

x+=lowbit(x)得到的就是包括c[x]的最近乙個節點的下標

可以看到,如果我要維護陣列c那麼,如果我的a[5]改變了x的話我就要把所有包含a[5]的陣列c中元素改變x

這樣就引出了我們的第二個函式

維護函式

void update(int x,int num)  

}

這裡的x為我改變的a陣列中元素的下標,num為要改變的值,n為陣列上限

可以看到a[1]到a[7]的和為c[7]+c[6]+c[4]

7-lowbit(7)=6

6-lowbit(6)=4

現在我們可以看到x-lowbit(x)的作用了吧

那麼我們引出最後乙個函式,求和函式

int getsum(int x)  

return s;

}

這個函式返回的就是a[x]到a[0]的和

有了這三個函式我們就可以解決更新每個點的值,最後求一段區間的值的和 的問題了

然而oj上還有另一種問題

:更新一段區間上的值最後求乙個點的值

這時候就要反著來了

對於區間[a,b],每個元素的值改變x

那麼我們的維護**是這樣的

void update(int x,int num)  

}

update(b,1);

update(a-1,-1);

舉個例子,對於區間[2,7]來說

我們把c[7],c[6],c[4]全部+1

c[1]全部-1

為什麼要這樣維護呢

接下來我們看求和**就知道了

int getsum(int x)  

return s;

}

求和**是把所有包括a[x]的c中的元素全部加起來

比如 x=3的話s就等於c[3]+c[4]+c[8]

現在我們對比前面的看一下

首先我們發現,對區間[a,b]進行維護的話我們對下標》b的c中的元素是沒有動的所以求和時下標在b之後的元素是完全不受影響的

求和的時候如果我要求的元素在a之前那麼我加到最後加的和減的是可以相互抵消的

如果下標在a,b之間的話,此求和時是不受下標在a前面的c中的元素影響的但要加上且僅加上乙個下標在【a,b】之間的元素。

這樣就完成了計算

對於lowbit函式,這裡結合了位運算和二進位制的知識,非常巧妙

如果想深究的話看連線

樹狀陣列1 樹狀陣列入門

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

樹狀陣列 瞎bb 樹狀陣列

樹狀陣列是乙個利用一維陣列和位運算組成的求解區間問題的高效資料結構,其構造如圖所示 首先,我們要用它解決單點修改 區間查詢的操作。根據這張圖我們建立乙個陣列bit,下標就是圖中顯示的十進位制數。bit i 就表示了圖中所示的一段區間的和,例如bit 6 sum 5,6 bit 4 sum 1,4 下...

樹狀陣列 求逆序對個數(初學者都能看懂)

在網上翻看了一些部落格,感覺大體對於樹狀陣列求逆序對的講解不夠詳細,那些部落格,更多像是給已經學會逆序對的人複習用的。而初學者,可能要冥思苦想。接下來,我便從乙個初學者的角度,來一步步的,講解一下由樹狀陣列求逆序對。需要的前置知識只有,會線段陣列的基本應用。單點更新,區間查詢,求lowbit。先貼樹...