連續和查詢問題。給定乙個n個元素的陣列a[1],a[2],....a[n],我們的任務是設計乙個陣列結構,支援乙個查詢操作query(l,r)=a[l]+a[l+1]+a[l+2]+....+a[r]。如何做呢?如果每次用迴圈來計算,單詞查詢需要o(n)的時間,效率太低。如果借助字首和思想,可以花o(n)時間事先計算好s[i]=a[1]+a[2]+a[3]+....+a[i]。那麼query(l,r)=s[r]-s[l-1]。下面我們要是想再支援乙個操作,即add(x,d) 讓a[x]增加d。那麼如果依照剛才的思路,每次執行add操作需要修改一批s[i],還是會很慢。有一種二叉索引樹(binary indexed tree,bit)的資料結構可以很好地解決這個問題。為此我們先介紹lowbit。
對於乙個正整數x,我們定義lowbit(x)為x的二進位制表示式中最右邊的1所對應的值。比如,38288的二進位制是1001010110010000,所以lowbit(38288)=16(10000)。在程式實現中,lowbit(x)=x&-x。
如圖所示,是乙個典型的bit,由15個結點組成。灰色結點是bit中的結點(白色長條的含義稍後敘述),每一層結點的lowbit相同,而且lowbit越大,越靠近根。圖中的虛線是bit中的邊。注意編號為0的點是虛擬結點,他並不是樹的一部分,但是他的存在可以讓演算法理解起來更容易一些。
對於結點i,如果它是左子結點,那麼父結點的編號是i+lowbit(i)。如果它是右子結點,那麼父結點的編號是i-lowbit(i)。搞清楚樹的結構之後,構造乙個輔助陣列c,其中c[i]=a[i-lowbit(i)+1]+a[i-lowbit(i)+2]+....+a[i]。換句話說,c的每個元素都是a陣列中的一段連續和。到底是那一段呢?在bit中,每個灰色結點i都屬於乙個以它自身結尾的水平長條(對於lowbit=1的那些點,長條就是他本身),這個長條中數之和就是c[i]。
有了c陣列之後,如何計算字首和s[i]呢?順著結點i往左走,邊走邊往上爬。把沿途經過的c[i]累加起來就可以了。如下圖:
而如果修改了乙個a[i],需要更新c陣列的哪些元素呢?從a[i]開始往右走,邊走邊往上爬,沿途修改所有結點對應的c[i]即可。如下圖:
兩個操作的**實現為:
int sum(int x)
return ret;
}void add (int x, int d)
}
不難證明,兩個操作的時間複雜度均為o(logn)。預處理方法是先把a和c陣列清空,然後執行n此add操作,總時間複雜度為o(n*logn)。
乙個二叉索引樹的例題
一條大街上住著n個兵乓球愛好者,經常組織比賽,切磋技術。每個人都有乙個不同的技能值a[i]。每場比賽需要三個人,兩名選手,一名裁判。他們有乙個奇怪的規定。即裁判必須能住在兩名選手中間,並且技能值也要在兩名選手之間。問一共能組織多少種比賽。
分析:考慮第i個人當裁判的情形。假設a[1]到a[i-1]中有c[i]個比a[i]小,那麼就有(i-1)-c[i]個比a[i]大;同理,假設a[i+1]到a[n]中又d[i]個比a[i]小,那麼就有(n-i)-d[i]個比a[i]大。根據乘法原理和加法原理,i當裁判的時候有c[i]*(n-i-d[i])+(i-c[i]-1)*d[i]中比賽。這樣問題就轉化為求c[i]和d[i]。
c[i]可以這樣計算:從左到右掃瞄所有的a[i],另x[j]表示目前為止已經考慮過的所有a[i]中,是否存在乙個a[i]=j(x[j]=0表示不存在,等於1表示存在),則c[i]就是x[1]+x[2]+...+x[a[i]-1]。初始時所有的x[i]=0,在計算c[i]時,需要先設x[a[i]] = 1,然後求字首和。換句話說我們需要動態的修改單個元素的值並求字首和,這正是bit的標準用法。這樣可以在o(n*logr) (r是a[i]的上限)時間複雜度內計算出所有的c[i],計算d[i]方法一樣。然後再o(n)時間裡累加出最後的答案。
二叉索引樹(樹狀陣列)
二叉索引樹 binary indexed tree,bit 動態連續和查詢問題,給定乙個n個元素的陣列a1,a 2,an。支援以下兩種操作 1.add x,d 操作 讓a x增加d。2.query l,r 計算al a l 1 ar。在學習二叉索引樹之前,需要先介紹lowbit.對於正整數x,我們定...
樹狀陣列(二叉索引樹)
樹狀陣列的原理介紹可見劉汝佳 演算法競賽入門經典 訓練指南 194頁,講的非常好 簡單自己對樹狀陣列的基本理解 我們原先不是把陣列看成一排嗎,但現在不是了,我們用乙個類似二叉樹的結構來儲存資料,存到c當中去,好好研究劉汝佳所畫的圖。下面說明基本應用 對於乙個n元素的陣列a n 可執行如下操作 add...
二叉索引樹(樹狀陣列)
二叉索引樹 binary indexed tree 又叫樹狀陣列,主要是用於解決動態連續和查詢問題。給定乙個n個元素的陣列a1,a2,an,你的任務是設計乙個資料結構,支援以下兩種操作。對於正整數x,我們 定義lowbit x 為想的二進位制表示式中最右邊所對應的值。比如由38288的二進位制是10...