算法筆記-初階資料結構
初階資料結構
1.Segment Tree - 線段樹
Segment Tree是一種二元樹,適合解決RMQ問題(查詢區間極值)、區間和,
適合用於單點修改、區間修改。
成功實現Sparse Table做不到的事。
每個節點可以存一種區間的數據(比如區間和),
根節點存[1,n]的數據,每個左子節點編號是index*2,右邊為index*2+1,
左邊紀錄[l,(l+r)/2),右邊紀錄[(l+r)/2+1,r]。
通常,線段樹會開4倍大
|
|
建立線段樹,若l==r,此節點即a[l]
子樹建完後就把資料合併
|
|
詢問區間(ql,qr:要查的區間 l,r:此節點儲存的左右界)
|
|
單點修改
|
|
懶人標記
如果想在[l,r]中的所有元素加值怎麼辦? 不可能一個一個呼叫modify吧。
我們可以先在要加的區間內貼標籤,最後要查詢時再加上去就好
- 這裡用了更多變數,建議改用結構體來實作可以減少程式碼
|
|
練習:
ZeroJudge d539
ZeroJudge d668
ZeroJudge d799
2.Fenwick Tree(BIT) - 樹狀數組
大家都說他是線段樹的精簡版本,因為他實作比較簡單,也更省空間,支援單點加值、前綴求和。
時間複雜度為 $O(log(N))$
空間複雜度為 $O(N)$
其運用了一個數字都可以寫成好幾個2的n次方之和,將數進行分段。
BIT最重要的是$lowbit()$函式,表示把某數寫成二進位後,最低位的1所代表的數,
例如: $lowbit(6_{10}) = lowbit(110_2) = 10_2 = 2_{10}$,$lowbit(20_{10}) = lowbit(10100_2) = 100_2 = 4_{10}$
要計算lowbit,可以用 $x \& (-x)$ 得到,
要計算 $lowbit(20_{10})$,$20$ 寫成二進位為 $10100_2$,$-20_{10}$ 寫成二進位為 $01011_2 + 1_2 = 01100_2$,$20_{10}\& (-20_{10}) = 10100_2 \& 01100_2 = 00100_2 = 4_{10}$。
現在我們有一個陣列 $a[1…n]$,我們再建另一個陣列 $T[i] = \sum^i_{j=i-lowbit(i)+1} a[j] $
前綴和
想計算 $a[1…20]$ 的和,因為 $T[20] = a[17…20]$,可以遞迴算出 $a[1…16]$ 的和,加上 $T[20]$ 就是答案了。
要算出 $a[1…16]$ 的和,$T[16] = a[1…16]$,是我們已經算好的答案,
最後看起來 $sum(x) = T[x] + sum(x-lowbit(x))$。
單點加值
如果想在 $a[12]$ 加上 $x$ ,那直接 $T[12] += x$ 就好了,但是 $T[12]$ 會影響到 $T[13…20]$,所以要把 $T[13…20]$ 都更新一次。
最後就是實作了,為了方便,包成struct
|
|
如果要初始化,直接把原陣列一個一個update進去就可以了,時間複雜度為 $O(Nlog(N))$。