1. 程式人生 > 其它 >「JOI 2014 Final」裁剪線

「JOI 2014 Final」裁剪線

掃描線好題

做法一

首先將邊界也視作四條裁剪線,整個平面作為一張紙,視存在 \(y = -\infty, y = +\infty, x = -\infty, x = +\infty\) 四條直線。

按照縱座標依次掃描每條線,每次維護當前縱座標水平無窮長的直線和每個位置下面第一條之前插入過的縱座標之間圍成區域的連通性,如下圖所示:

圖中箭頭指向的就是當前掃描(維護)到的(水平)線,紅綠藍分別為所圍成的區域(有效)。

具體地,由於上述掃描過程中連通性只會在:水平線段,豎直線段底部,豎直線段頂部發生改變,因此我們將這些位置按照縱座標排序依次考慮。

同時,為了方便我們直接讓每條豎直線段管轄其右邊第一個區域和其他區域的連通性。

  • 豎直線段底部

將原本一整段區域分成了兩段,考慮對新加入的豎直線段新建一個區域,其餘左邊最近的區域聯通,那麼在並查集上連邊。

  • 豎直線段頂部

無論如何,只需要將左右兩個區域在並查集上聯通即可。

  • 水平線段

加入水平線段後,中間被完全覆蓋的區域與外界且兩兩之間不連通,需要賦予全新的並查集編號,這裡顯然不能暴力,考慮用資料結構維護。

首先對於豎直線段我們要支援插入,刪除,查詢前驅,平衡樹顯然可以直接勝任。

水平線段需要整個區域打上重新標號的懶標記,下次再進行橫向覆蓋的時候,整個區間存在懶標記的節點接下來一定都不會與外界聯通需要直接加入答案,因此平衡樹上還需要維護區間內懶標記沒有被釋放的點的數量。

最後我們再統計所有區域在並查集節點中構成的連通塊數量加入答案即可。

因為有查詢前驅操作,所以可以事先插入 \(x = -\infty\) 這條直線,最後答案需要減一。

注意在下傳懶標記的時候只需要新建點而不需要在並查集上連邊,時空複雜度均為 \(\mathcal{O}(n \log n)\).

做法二

注意到本題是網格圖的一部分,那麼一定是一張平面圖,考慮利用尤拉公式求平面圖面的數量。

注意本題可能不連通,設交點數量為 \(V\)線段 數(不是交點之間的邊數!)為 \(E\),面數為 \(F\)線段 聯通塊(不是交點連通塊個數)個數為 \(C\).

之所以和尤拉定理設的不同是因為統計線段連通塊數比交點連通塊數好做,原本交點間邊數和交點連通塊個數差可以抵掉一部分變為 \(E, C\)

之間的關係,即:

\[V - E - F + C = -1 \]

那麼只需要求出 \(V, E, C\) 即可,\(E\) 顯然是好求的,\(V\) 是經典掃描線問題,考慮如何求 \(C\).

依然考慮掃描線,沿水平從下往上掃描,每次相當於支援加刪豎直線段,將水平線段和一個區間內的豎直線段連邊。

考慮線段樹優化區間連邊,我們把每個豎直線段插入到線段樹上對應的 \(\log\) 個區間,每次水平線段找到區間線上段樹上 \(\log\) 個子區間。

注意到整個區間內的點如果全部和一個點聯通那麼這些點都是聯通的,我們只需要保留一個代表節點即可。

很顯然,代表節點就是頂端縱座標最大的點,這樣可以保證正確性。

複雜度與做法一的複雜度相同但思維難度降低了。

GO!