樹狀數組是一個優美小巧的資料結構,在很多時候可以代替線段樹。樹狀數組的本質就是一種通過二進位位來維護一個序列前i和的資料結構。(詳見論文或http://old.blog.edu.cn/user3/Newpoo/archives/2007/1712628.shtml)
樹狀數組按照維數分為1維和2維,按照類型分可以分為插點問段和插段問點,這兩個互逆,只是改變for迴圈的方向就可以了。一般以插點問段較為常見,對於查點操作,只需查詢前n項和及前n-1項和,便可得到第n項的值
插段問點轉化為插點問段:
設A[1,N]為我們要處理的數組。另外設定一個數組B[1,N],使得B[1] + B[2] + .. B[i] = A[i], 其中1 <= i <= N.
即B[i] = A[i] - A[i-1]
當要查詢A[i]的時候,我們只需在數組B上使用一般的樹狀數組操作查詢區間[1,i]即可
當我們要給區間A[a~b]加上delta時,只需要在數組B上對B[a]進行一般樹狀數組的更新delta的操作,同時對數組B上對B[b+1]進行 - delta操作。
final int lowbit(int k){return k&(-k);}//可查詢0,不可更新0,閉區間int ss[]=new int[100010],N;final void inc(int k,int m){while(k<=N){ss[k]+=m; k+=lowbit(k); }}final int get(int k){int sum=0;while(k>0){sum+=ss[k];k-=lowbit(k);}return sum;}
樹狀數組用做統計很好用,假如y = f(x),事先應該考慮好是把y作為下標,還是x作為下標。
--------------------------------------------------------------------------------------------------------------------------------------------
poj 2352 STARS
題意:給定一組點,問二維空間中各個點的等級是多少,點的等級定義如下:其左下方點的個數。
解法:由於點時按縱座標從小到大給出的,因此只需要知道前面輸入的點在當前點左側的點有多少個,這個點的等級就是幾。一維樹狀數組插點問段即可實現。
poj 3067 Japan
題意:日本東海岸有n個城市,西海岸有m個城市,現在要修建k條高鐵串連東海岸的城市s和西海岸的城市t。問這k條高鐵總共有多少個交點。
解法:首先對k條公路按照起點從小到大排序,對於第i條公路,如果前i-1條公路有x條的終點大於t,則第i條公路與前面的x條公路有交點,用樹狀數組查詢前t項和,並用i減之即可達到結果。
poj 3321 Apple Tree
題意:一棵具有n個節點的樹,一開始,每個節點上都有一個蘋果。現在給出m組動態操作:(C,i)是摘掉第i個節點上面的蘋果(若蘋果不存在,則為加上一個蘋果),(Q,i)是查詢以第i個節點為根的子樹有幾個蘋果(包括第i個節點)。
解法:關鍵在於樹形結構和線性結構的轉換,用線性結構中的前i項和代表樹形結構中的以i為節點的子樹。使用後序遍曆為所有節點編號,這樣就保證了跟節點的 編號比所有子節點都大,同時記錄沒課子樹最左邊的節點號,這樣子樹的蘋果數就等於get(no)-get(min[no]-1);
poj 1195 Mobile Phone
題意:二維樹狀數組,更新點,查詢區間和;
poj 2155 Matrix
題意:給定一個n*n的0-1矩陣,執行一些如下的兩種操作:C a,b,c,d :將矩陣中(x1,y1)到(x2,y2)的格子中的0-1進行“非”操作;Q a b :詢問當前(a,b)位置的元素的值。
解法:使用二維樹狀數組,對於每一條更新,更新(x2,y2);(x1-1,y1-1);(x1-1,y2);(x2,y1-1);更新時對每個節點的值進行取反操作。
POJ 2182 Lost Cows
題意:有N頭牛,每頭牛有唯一的編號(1-N),先給出眉頭牛前面有多少頭牛的編號小於自己的編號,要求求出所以牛的編號。
解法:對於最後一頭牛,前面有x頭小於它的,它的編號就是x+1,每頭牛已知了後面牛的編號及前面小於它編號的牛的數量,因此從後往前查詢每頭牛,二分尋找確定該頭牛的編號(及滿足sum[k]+x<k的最小的k),並更新第k個節點的sum值。
POJ 2828 Buy Tickets
題意:賣票插隊問題,有 N 個插隊行為,告知每次要插到第 i 個位置上,問最後它們的順序是什麼。
解法:與上題類同,思維很巧妙,倒過來做的話就能確定此人所在的位置。
POJ 1990 MooFest
題意:有n頭牛,排列成一條直線(不會在同一個點),給出每頭牛在直線上的座標x。另外,每頭牛還有一個自己的聲調v,如果兩頭牛(i和j)之間想要溝通的話,它們必須用同個音調max(v[i],v[j]),溝通起來消耗的能量為:max(v[i],v[j])
* 它們之間的距離。問要使所有的牛之間都能溝通(兩兩之間),總共需要消耗多少能量。
解法:按v從小到大排序,則對於每一隻牛a,所有(a,b)的消耗等於v[a]*距離和,計算某點到各點的距離和時,在左側的點和在右側的點要分開考慮,因此使用兩個樹狀數組分別統計小於當前x的牛的個數ln和距離和ls,且已知當前所有牛的個數及距離和,
ans += ((cc[i].x * ln - ls) + (sum - ls - cc[i].x * (i - ln)))* cc[i].v;
然後分別更新個數及距離的樹狀數組。
HDU 2492 Ping Pong
題意:有n名水平不相同的乒乓球運動員,要進行若干場熱身賽,每場熱身賽需要一名隊員做裁判,並要求裁判的水平要介於兩名運動員之間,且裁判要住在兩名比賽隊員之間(第i名運動員的住址編號為i),為最多可舉辦多少場不完全相同的比賽。
解法:對於每一名運動員,他作為裁判能舉辦的比賽去卻與他左邊水平低於他的人數和右邊水平高於他的人數,及左邊高於他右側低於他的人數,因此可以用兩個樹狀數組分別維護所有運動員水平小於x的人數及當前水平小於x的人數,有次可知兩側大於x和小於x的人數,遍曆每個裁判,累加得到結果。
poj 2481 Cows
題意:FJ有n頭牛(編號為1~n),每一頭牛都有一個測驗值[S, E],如果對於牛i和牛j來說,它們的測驗值滿足下面的條件則證明牛i比牛j強壯:Si <= Sj and Ej <= Ei and Ei - Si > Ej - Sj。現在已知每一頭牛的測驗值,要求輸出每頭牛有幾頭牛比其強壯。
解法:與Stars一題類似,對於這種有兩個關鍵字並且具備單調性的問題,使用樹狀數組最佳化的一般方法是固定一個關鍵字(或者區間的端點),然後查詢另一個關鍵字前n項和的性質確定當前對象的答案。
此題先按s由小到大排序,如果s相同根據t由大到小排序(使得前面的影響後面的)使用樹狀數組查詢當前大於e-1的個數,還要注意特殊處理一下完全相同的區間。