這里用HDU的1542題作為例子,一個經典的掃描線題目,計算矩形並的和。
首先介紹掃描線,就是一根假想的線,從左到右的一條豎線掃描過去。
掃描線可以用來填充多邊形,具體請看 http://blog.csdn.net/orbit/article/details/7368996 寫的很好。
然后就是掃描線在這個題里的應用。
計算這兩個矩形的面積等價於計算紅色,綠色,藍色三塊的面積的和。
所以說從左到右的掃描線掃描的時候,線段樹維護的是區間內被覆蓋的總長度,然后乘以兩條掃描線之間的距離,就是一塊的面積,然后更新線段樹,以此論推,得到的就是總面積了。
不過這個題要注意三個地方:
1,離散化,每條邊的坐標是浮點數,要進行離散化,要記得去重。
2,就是區間覆蓋的長度計算問題,這里我糾結了老久,首先如果按照點來覆蓋的話對區間2,8覆蓋其實是對1,5和6,10進行覆蓋(如果線段樹左右子樹的區間是1,5和6,10的話,那么5和6中間那一塊就沒有被計算上,就出問題了。。。
所以說不能按照點來覆蓋,應該把每個點當作是表示這個點到下一個點之間的這條線段,這樣就不會漏掉中間那一個了。
如果是表示線段的話,那么如果有10個點,那么有9條線段,所以線段樹是1到9(而不是10),每次計算長度的時候記得右邊要加一。
3,就是線段樹的更新問題,每加一條線段或者減一條線段的話,並不是簡單的覆蓋就好,而是應該記錄這個區間被覆蓋了幾次,直到減到零的時候才是沒有線段在覆蓋這個區間。這樣的話每加一條線段就是對線段的區間+1,去一條線段就是-1。
不過這樣的話pushDown就不好用了,因為如果把一個節點的COL值推到下面兩個之后,之后如果再覆蓋,這個節點的COL變成-1了,那就不好算這個節點維護的值了。所以根據杭電大神的寫法,不用pushDown,而是在計算pushUP的時候,如果這個節點已經被覆蓋為大於0的就直接計算(因為這個節點表示的整個區間都被覆蓋了,直接右面減去左面就是了。),否則才求助於下面的兩個節點。而且,詢問只是詢問節點1的值,所以不會出錯。
近來又看到了一個大神的線段樹寫法,他用了pushDown,但是也對pushUP進行了修改,從而保證不會讓某一個節點的值為零,雖說速度不會快,但是可擴展性要高很多,因為可以讓有的矩形第一條邊為-1,第二條邊為1(HDU 3265)這個題。
修改的代碼我在HDU 3265和HDU 1542中都貼出來了。
差不多就這三個了,水平有限,敬請諒解。
例題: