Fenwick Tree 又稱 Binary Indexed Tree(樹狀數組),以下簡稱 BIT,是一個方便解決區間與前綴和問題的資料結構。本篇筆記會介紹其原理,也會說明此資料結構在題目上如何應用
給一個經典的問題: 「給定一個長度為 的數列 (),即 比詢問,每筆詢問給定 ,求區間 的總和」這個問題非常基本,定義一個前綴和陣列 ,並預處理之,再使用差分 ,即可算出
然而,當題目給的數列「可以在詢問過程中對任一個 加值 」,那麼前綴和陣列 ~ 都加值 。在最差情況下,若都是對 加值,那麼每次加值時間複雜度為 ,而這種複雜度非常糟糕。因此我們需要一個好的資料結構來維護前綴和,使每次修改都可以在很小的時間內完成
這段不知道也沒關係
給定一個長度為 的數列 ,我們可以建構長度為 的陣列 ,代表 ,其中 。考慮將 以二進位的 index 拆分,並以 表示。拆分方法是用二進位表示法以 index 最右邊的 逐一刪去,並將每次刪去後的結果對應到的 加總,直到 停止。舉例像是
要完成此拆分,需要先建構陣列 ,如下表。其中 contents 是指 的區間加總
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|---|
contents | 0 | 1 | 1~2 | 3 | 1~4 | 5 | 5~6 | 7 | 1~8 |
index | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
---|---|---|---|---|---|---|---|---|
contents | 9 | 9~10 | 11 | 9~12 | 13 | 13~14 | 15 | 1~16 |
我們可以定義一個函數 代表 在二進位表示中最右邊的 (即 least significant bit)。可以利用補數的特性來定義
如此一來,當我們想要詢問第 項的前綴和時,就可以使用上述的演算法來完成查詢
在更新數值 時,會發現 都會受影響。如上述所建構的 ,假設我們要使 加值 ,我們可以觀察到會受影響的 陣列數值有 、 與 ,這剛好會是 不斷加上 的結果 (、)。因此我們可以得到以下算法
以下面樹狀圖表示會更直覺一點。由於這是以二進制編號來做更新的資料結構,因此提出此想法的原作者將其命名為 Binary Indexed Tree
圖源: 海大競程 - 2025 離散化+BIT
若想要將整個 陣列塞入 BIT,可以將陣列 先初始化為 ,再呼叫 函數去更新數值
要注意 跟 1-based,而 是 0-based
查詢與更新均與樹高有關
變數名稱同上述所示,我們可以用 struct
包起來避免變數互相影響
注意有些變數在數字很大的時候可以用 long long
宣告
給定一個長度為 的數列 (),及 比詢問,每筆詢問給定 ,求區間 的總和
查詢區間可以使用差分的技巧完成
剩下套模板即可
給定一個長度為 的數列 。對於 而言,若 且 ,則稱 為一組逆序數對。求數列 中有多少組逆序數對
舉例假設一長度為 的數列 ,則 有 組逆序數對,分別為:
, for all
觀察一 : 最直觀的方式就是用 去掃描整個陣列。若開兩個 for 迴圈由右往所掃,可以發現有些數字會重複被掃描到。i.g. 在找到 這組之後又會找到 ,發現 被重新掃過。可以考慮將每個出現的數字出現次數記錄到一個陣列 之中
觀察二 : 若建立了用於計數的 ,可以發現當我們掃描到新的數字 時,算出此時的前綴和 ,就可以知道「比 還小的數字數量」。由於是由右往左掃描, 位於其他數字左邊,符合 ,又因前綴和只會加到比 小的數字的數量,所以也符合 。因此每次將「比 還小的數字數量」加總,就可以得到逆序數對數量
觀察三 : 前綴和的資料結構可以用 BIT 來實作,有效減少 單一數值修改的時間複雜度
此演算法的時間複雜度為:
以上實作之中,我們會以數字的大小來建立資料結構 。然而,若數值為 或是負值,則無法正常宣告 中的陣列 ,因此我們需要用離散化的技巧解決問題
離散化的實作非常簡短,步驟只有以下:
此演算法的時間複雜度為:
離散化的精華在於,陣列在保持了原本數值大小順序的情況下,縮小數值的值域,是個常見的解題技巧
給定兩個長度為 的陣列 ,問總共有幾組 滿足 且
可以將每個 與 看做數對 ,合起來就是一個數對陣列 。為了滿足 ,可以先將 數對陣列 以 做排序,如此一來就可以將問題轉化成對 求反的逆序數對
以上程式碼可以對 進行離散化
AtCoder Fenwick Tree (裸的)
CSES Range Update Queries (區間修改?)
Zerojudge b373. [福州19中]车厢重组 (逆序數對 or 窮舉)
ABC231 - F. Jealous Two (二維偏序)
Zerojudge a457. TOI2010 第五題:餐廳評鑑 (離散化 + 逆序數對)
Zerojudge d542. 10810 - Ultra-QuickSort (逆序數對)
CSES Sliding Window Median (二分搜 + BIT)
Zerojudge f315. 4. 低地距離 (計數)
Codeforces Round 261 D. Pashmak and Parmida's problem (計數)
Codeforces Beta Round 57 E. Enemy is weak (3-逆序數對)
LeetCode - 493. Reverse Pairs (2 倍逆序數對)
Zerojudge d799. 区间求和 (開兩個 BIT 或當線段樹毒瘤)
海大競程 - 離散化+BIT
A New Data Structure for Cumulative Frequency Tables - peter m. fenwick
CP-Algorithms - Fenwick Tree
資訊之芽 - Fenwick tree
麗山演算法讀書會 - Fenwick(BIT, 樹狀數組)
wikipedia - Fenwick tree
ShanC 程式競賽筆記
作者: ShanC
更新: 2025/3/2