Segement tree
用來存放紀錄在特定區間內 ( segement, interval ) 的資訊。
- Pros
- 可以動態的更新欲求數組之元素。
- 數組區間的查詢
- 區間求和值
- 區間最大值
- 區間最小值
- 區間異或值 ( Exclusive or;XOR )
- Cons
- 無法刪除數值
線段樹無法新增節點,只能更新節點的數值並保持區間的最大最小值仍保持正確。
實現
- 特性
- 完全二元樹
- 節點保存特定區間的訊息
- 採取 Buttom-up 的方式建構,從每一個葉節點建構
- 上面的分段樹根節點保存 0 ~ 7 的資訊,2 號節點保存 0 ~ 3 的資訊,以此類推。
初始化
在建構的過程中,內部節點之建構會使用兩個子節點的資訊,而建構的方式以處理的問題而作法不同 ( 最大、最小、和、XOR )。
- Segement create ( 求區間最小值 )
- ST:線段樹
- A:欲判斷之數組資料
- 線段樹因為為完全二元樹所以通常以陣列製作
- 陣列大小需求:\(2 \times 2^{\lfloor\lg N\rfloor + 1}\),N 為數組大小 (見下圖)
- 程式碼 ( c++ )
1 | typedef vector<int> vi; |
- 時間複雜度
- \(\Theta(\log n)\)
更新
與建立線段樹的方法相同,將位於數組 i
的數字更新後,即從此葉節點向上執行更新至根節點。
1 | // 以數值 v 更新 A[p] |
查詢
分為三種情形討論,若當前節點所代表的區間
- 完全位於欲求取之區間之外
- 完全位於欲求取之區間之內
- 部分位於欲求取之區間
1 | int query (vi &ST, const vi &A, int x, int L, int R, int ql, int qr) { |
其它實現
Efficient Segment Tree Tutorial
1 |
|
Sparse table
「Sparse table」為古代之稱,如今詞不達意
- Pros
- 數組區間的查詢
- 區間最大值
- 區間最小值
- 數組區間的查詢
- Cons
- 不能更新、插入、刪除值
- 浪費空間
- 無法數組區間的
- 求和值
- 異或值 ( Exclusive or;XOR )
實現
初始化
- Construct sparse table
- N:資料量
- value[N]:數組
- cnt[logN][N]:Sparse table
依序先求出寬度為 \(2^0, 2^1, 2^2, \ldots, 2^{\lfloor\lg N\rfloor}\) 的區間最小值,區間的所有可能位置都要算一遍。兩個窄區間可以快速合成出一個寬區間。
將所有區間算完存入 Sparse table
實作時,通常表格中記錄的是索引值、指標,而不是直接記錄數值的最小值。(如下程式碼)
- 程式碼 (c++)
1 | const int N = 1000000; //No. of elements |
- 時間複雜度
- \(\Theta(N\log N)\)
- 空間複雜度
- \(\Theta(N \log N)\)
查詢
從表格中找到寬度略短於(相等於)查詢區間的區間,以靠左、靠右的兩條等寬區間,求得查詢區間的最小值:
- 如何知道要查「Range」大小為何的表?
- 令 \(k\) 為我們所求 → \(k = \lfloor \lg N \rfloor\)
1 | int query(int a, int b) { |
- 時間複雜度
- \(\Theta(1)\)
參考
輔大張信宏老師講義