線段樹 (Segment Tree)
支援單點修改的區間和查詢
給定一個長度為 的序列 和 筆操作,有兩種操作:
1 x v
:將 改成 。2 x y
:詢問 之間的和。
線段樹是一種常用來於處理區間查詢及修改的題目,根節點紀錄 之間的數據,令每個紀錄 節點 ,令 ,左子節點為 ,右子節點為 。
儲存
線段樹可以用和 Complete Binary Tree 一樣的方式儲存(雖然不完全是 Complete Binary Tree),一般來說會開大小為 的陣列避免編號超出陣列範圍。
除了陣列,指標也可用來時做線段樹。
1 2 3 4 5 6 7 8 9 |
|
單點修改
假設要更新的位置為 ,那麼所有包含 的節點就要更新。從起點開始,遍歷所有包含 的節點,最深的節點為 。 直接更新值,其他遍歷的節點 則是根據 和 的值合併。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
每次往下一層節點區間長度會減半,最多往下 層,時間複雜度為 。
初始化寫法
有一些人會寫一個 build
函式遍歷並更新所有節點,時間複雜度為 。
1 2 3 4 5 6 7 8 9 10 11 12 |
|
另一種方式是利用 次單點修改初始化線段樹,時間複雜度為 。
不論哪種寫法,都不會影響最終的時間複雜度。
區間查詢
支援區間修改的區間和查詢
給定一個長度為 的序列 和 筆操作,有兩種操作:
1 x y v
:將 到 改成 。2 x y
:詢問 之間的和。
假設要查詢的範圍 ,要找出所有節點 其中 。
1 2 3 4 5 6 7 8 9 10 11 12 |
|
符合的區間最多有 個,最多會拜訪 個節點1,時間複雜度 。
區間修改
假設要修改的範圍 ,仿效區間查詢的思維,更新所有節點 其中 ,並在該節點上新增一個懶人標記,當要拜訪 的子節點時,會將懶人標記傳遞給 的子節點。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
|
時間複雜度 ,原因和區間查詢相同。
應用
可用來查詢區間總和或極值,支援區間修改,不支援區間刪除、翻轉。