樹狀陣列趣解

2021-08-04 23:41:09 字數 2136 閱讀 7448

4操作原理

5小結

感謝各位能在白忙之中抽空來看鄙人的文章,cgg在這有禮了!

先給張圖。

下面的a是原陣列,而c則是a對應的樹狀陣列。所以你應該會恍然大悟(也許誇張了些),樹狀陣列是陣列的另一種表現形式,而這種表現形式會大大提高其各種操作的效率,在競賽中,也時常會考察,那麼下面,就讓我們一起去解開他神秘的面紗吧!

有的人看到後會有點發懵,a和c的對應關係是怎樣的呢?我們先寫前幾項看一下。

2^k=i&(i^(i-1))

2^k=i&(-i)

這裡給出了兩個公式,都能計算出來2^k,這樣我們也就能進行必要的操作了。

那麼為什麼是這兩個公式呢?下面我們就說一下原理。

先舉例,如10100

1、運用公式一

i-1=10011

x=i^(i-1)=00111

i&x=00100=4=2^2

k=2

沒有任何問題,那麼為什麼呢?

首先,減一,會導致末尾的0全部變成1,且原來最後乙個1變成0,自己想想豎式計算,0減1的時候需要向高位借一位。

接下來異或,原數最後乙個1左邊位沒變化,所以異或肯定是0,而原數最後乙個1,減1後變成0,所以該位異或後肯定為1,而原數末尾的0,減1後變成1,所以以後結果也為1,綜合一下,就是自最後乙個1以後全為1,而其他位為0.

最後一步,按位與,x中0的為肯定都為0,而1的位,只有原數i最後乙個1為1,其他結果均為0,又因為,這個1是從左往右數第(k+1)位,所以是2^k。

應該聽懂了吧!

2、公式二

這裡簡單解釋一下,首先你得弄清補碼是啥,因為負數的二進位制就是通過補碼實現的。乙個負數的二進位制就是它絕對值的二進位制表示取反再加一。那麼我們看看-i的二進位制應該是怎樣的,首先取反,原來最後乙個1變成0,而末尾0變成1,其他位也取反,接下來在加1,會怎樣?末尾1又變成0,而i中最後乙個1變成0後又因為進製變成1,前面為僅僅為原數相反不變。總結一下就是,最後乙個1及其右邊的數不變,而其他位取反。

那麼接下來按位與,由於取反的其他位與原來位相反,結果肯定為0,而末尾0,結果肯定為0,只有最後乙個1,一直沒變,所以結果依然為1,這就回到了公式一中最後的結果。

有了公式,**就很簡單了,這裡給出方便大家學習。

公式一

int lowbit(int x)
公式二

int lowbit(int x)
操作主要有3種:插入操作,求前k個數之和,求區間[l,r]的和。

插入操作

void insert(int x,int p)

}

求前k個數之和
int

sum(int k)

return ans;

}

求區間[l,r]的和
int ask(int l,int r)
這裡我們有幾個約定:c是樹狀陣列,n是c的大小。

插入操作

插入操作只是我們給的**的一種特殊情況,即原數等於0的時候。

我們所要做的,不僅是將原陣列的對應值改掉,我們還要將樹狀陣列中包含這個值的結點的值改變。

值得解釋的,也就是下面這句話:

x+=lowbit(x);
還記得我前面賣的關子嗎?左右下標的關係。這裡就用到了。

lowbit(x)的結果就是乙個除了x二進位制最後乙個1的位置是1,其他均為0,所以x+lowbit(x)結果就是末尾多了0,這也就符合我們前面的那個規律了。

求前k個數之和

這個就更好解釋了,因為每個數負責的是a[i-2^k+1]到a[i]的和,所以加上c[x]後,很自然的讓x-2^k(即x-lowbit(x)),得到c[i-2^k],而這正是c[x]負責的範圍的左邊。

求區間[l,r]的和

這個我覺得可以不用講了,

sum(l-1)=a[1]+……+a[l-1]

sum(r)=a[1]+……+a[r]

所以下式減上式就得到

a[l]+a[l+1]+……+a[r]

zoj 樹狀陣列經典 未解

問題 n個點,對於每個點i,都有一條連向i 1的有向邊,另外有m條其他的有向邊,有q個詢問 u,v 求u到v的最短路 將m條有向邊和q個詢問對所表示的點對一起排序,u,v u大的排前,u一樣的v小的排前,u和v一樣大的先處理插入的再處理詢問的 邊插入邊詢問 樹狀陣列裡存的是右端點在v之後的詢問的結果...

hdu 1166 樹狀陣列解

樹狀陣列解決 關於樹狀陣列參考大佬的部落格 然後就很好理解這題了,附上 hdu 1166 單點修改,區間查詢 include include include define max 50010 using namespace std inttree max intarr max intn int lo...

趣解《5秒法則》

舉例 用本書知識使我比別人更高效完成工作或學習任務 開始 5 把鬧鐘放在不容易夠著的地方。因為,關鬧鐘比平時更費勁,會建立痛苦的聯想,而早起可讓您更快完成任務,是快樂的聯想。把鬧鐘放在身旁,還是放在費勁找它的地方,您是否更願意,在費勁關它的時候選擇起床來避免這種痛苦?4 前天晚上寫下1 3個 必做事...