線段樹與離線詢問
線段樹與離線詢問結合的問題在 OI 領域也有出現。這種技巧又被稱為線段樹分治。
假如你需要維護一些信息,這些信息會在某一個時間段內出現,要求在離線的前提下回答某一個時刻的信息並,則可以考慮使用線段樹分治的技巧。
實際上線段樹分治常用於不帶刪的數據結構轉成可以帶刪的數據結構,抑或是對於某一個屬性的信息分別計算。
過程
首先我們建立一個線段樹來維護時刻,每一個節點維護一個 vector 來存儲位於這一段時刻的信息。
插入一個信息到線段樹中和普通線段樹的區間修改是類似的。
然後我們考慮如何處理每一個時間段的信息並。考慮從根節點開始分治,維護當前的信息並,然後每到一個節點的時候將這個節點的所有信息進行合併。回溯時撤銷這一部分的貢獻。最後到達葉子節點時的信息並就是對應的答案。
如果更改信息的時間複雜度為 \(O(T(n))\),可以通過設置一個棧保留更改,以 \(O(T(n))\) 的時間複雜度撤銷。撤銷不維持均攤複雜度。
整個分治流程的總時間複雜度是 \(O(n\log n(T(n) + M(n)))\) 的,其中 \(O(M(n))\) 為合併信息的時間複雜度,空間複雜度為 \(O(n\log n)\)。
實現
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 | |
例題
luogu P5787 二分圖/【模板】線段樹分治
你需要維護一個 \(n\) 個點 \(m\) 條邊的無向圖。第 \(i\) 條邊為 \((x_i,y_i)\),出現的時刻為 \([l_i,r_i)\),其餘時刻消失。
對於每一個時刻,若此時該圖為二分圖,輸出 Yes,否則輸出 No。
解題思路
使用種類並查集來維護一個圖是否是二分圖,然後就可以套用線段樹分治了。
注意可撤銷的並查集不能路徑壓縮,只能按秩合併。
參考代碼
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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | |
顏色限制 restriction
一個 \(n\) 點 \(m\) 邊的無向圖,有 \(k\) 種顏色編號為 \(0\sim k-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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | |
luogu P4219 [BJOI2014] 大融合
需要維護一個 \(n\) 個點的森林,初始時是散點。
有 \(q\) 個操作,支持:
A x y連邊 \((x,y)\)。Q x y輸出經過邊 \((x,y)\) 的路徑數。
允許離線。
解題思路
考慮允許離線,因此可以想到線段樹分治。
然後考慮如何支持 Q 操作。如果不存在 \((x,y)\) 這條邊,答案就是 \(x\) 所在連通塊大小乘上 \(y\) 所在連通塊大小。可以用並查集維護。
因此你可以將 Q 拆成三個時間 \(k-1,k,k+1\)。其中 \(k-1\) 是這條邊的終止時刻,\(k+1\) 是這條邊的起始時刻。這樣 \(k\) 就沒有這條邊,正好回答詢問。
參考代碼
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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | |
luogu P2056 [ZJOI2007] 捉迷藏
出一個 \(n\) 個點的樹,每個點有黑白兩種顏色。初始時每個點都是黑色的。\(q\) 次操作,支持:
C x將第 \(x\) 個點的顏色反轉。G詢問樹上兩個黑色點的最遠距離。特別地,若不存在黑色點,輸出 \(-1\)。
允許離線。
解題思路
首先考慮如何維護樹上點集的直徑,有下面的推論:
對於一個集合 \(S\) 和只有一個點的集合 \(\{P\}\)。若集合 \(S\) 的直徑為 \((U,V)\)。則點集 \(S\cap\{P\}\) 的直徑只可能為 \((U,V),(U,P)\) 或 \((V,P)\)。
然後考慮解決原問題。我們可以考慮維護黑色點集,維護每一個點在黑色點集中的若干個時間段(具體你開一個桶記錄一下上一次進入黑色點集的時刻即可)。
然後就自然地想到離線,將所有時間刻插入到線段樹中。然後在線段樹上分治,每次線段樹上的點會記錄當前時間段點集新增的點,新增點可以使用上面的推論,找到新點集直徑的兩個端點。
撤銷是平凡的,開一個棧記錄一下直徑端點的變化即可。
參考代碼
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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | |
習題
- CF601E A Museum Robbery 線段樹分治 + 揹包 dp。
- CF19E Fairy 線段樹分治 + 種類並查集。
- luogu P5227 [AHOI2013] 連通圖 線段樹分治 + 並查集。
- luogu P4319 變化的道路 線段樹分治 + Link Cut Tree 維護最小生成樹。
- luogu P3733 [HAOI2017] 八縱八橫 線段樹分治 + 線性基。
本頁面部分內容參考自博文 Deleting from a data structure,版權協議為 CC-BY-SA 4.0。
本页面最近更新:,更新历史
发现错误?想一起完善? 在 GitHub 上编辑此页!
本页面贡献者:xiezheyuan
本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用