線段樹 + 掃描線加深具體解釋


在線段樹中的掃描線主要是解決矩形面積以及周長問題,比方下圖


讓你求解全部矩形覆蓋的面積和,或者是周長和,假設用平常的方法,很之麻煩。並且效率也不高。這里就會用到線段樹的掃描線

掃描線應對方案:

因為題目提供的矩形比較多。坐標也非常大。所以坐標須要離散化,能夠依照題目要求或者自己的喜好,離散橫坐標或者縱坐標都能夠,這里講的都是離散橫坐標,不離散縱坐標

假設有一條掃描線,從下往上(從上往下)掃描過整個多邊形疊加的區域。假設是豎直方向上掃描,則是離散化橫坐標,假設是水平方向右掃描,

在進行掃描前。要保存好全部矩形的上邊和下邊。而且依照它們所處的高度進行排序,另外我們給上邊賦值為-1。給上邊賦值為1。接着我們用一個結構體來保存全部矩形的上邊和下邊,當中還有兩條邊不用管,由於他們已經包含在了高度中。高度差便能得到邊的長度。

struct seg {
double l,r,h;//l代表着一條邊左邊端點的橫坐標,r表示一條邊右邊端點的橫坐標。h表示這條邊所在的高度

int s;//表示他的值。即我們在前面講的給邊賦值1或者-1
seg() {}
seg(double l,double r,double h,int s):l(l),r(r),h(h),s(s) {}
bool operator < (const seg & object) const {//依照高度排序
return h < object.h;
}
}

然后將掃描線從下往上掃描。每遇到一條上邊或者下邊就停下來,將這條線段增加到總區間上,下邊賦值是1,掃描到下邊的話相當於往總區間插入一條線段。上邊為-1。掃描到上邊相當於在總區間刪除一條線段(也能夠理解為當插入1的時候我們的掃描線在一個矩形中,當插入-1的時候證明我們的掃描線離開了一個矩形的區域,如此能夠知道,區間不會出現負數的情況,由於永遠都是下邊1 >= 上邊-1。他們相加是永遠大於等於零的)

然后用下一條邊的高度減去當前這條邊的高度,乘上總區間被覆蓋的長度,就能得到終於的面積

到此。希望大家能夠做一做這道題目,理解一下大概http://blog.csdn.net/qq_18661257/article/details/47622677

這道題目說明一下,pushup(rt, l, r)的作用以及當中推斷的來由。

  1. void pushup(int rt,int l,int r) {  
  2.     if (Col[rt]) Sum[rt] = X[r+1] - X[l];//利用[ , ),這個區間性質。左閉右開  
  3.     else if (l == r) Sum[rt] = 0;  
  4.     else Sum[rt] = Sum[rt<<1] + Sum[rt<<1|1];  
  5. }  
假設當前的位置為葉子節點,Col[rt] == 1話證明被全然覆蓋了,進行賦值(這里涉及到了離散化,建議讀者能夠學習離散化的知識),假設為Col[rt] == 0,這個葉子節點一定為0

假設當前位置不是葉子節點那么我們就要小心一點了。Col[rt] == 1話證明被全然覆蓋了,假設Col[rt] == 0話。我們能說他沒有被覆蓋嗎,不能,僅僅能說沒有被全然覆蓋,為什么呢,由於他的子節點可能被全然覆蓋了,可是父親節點沒有覆蓋,那么怎么全然的不漏的得到這個區間被全然覆蓋的區間大小呢,能夠直接通過子節點覆蓋的值

Sum[rt] = Sum[rt << 1] + Sum[rt << 1|1]得到rt這個位置總覆蓋區間


好,假設我如今要求被覆蓋兩次以及以上的區間的面積怎么做,圖形例如以下:


那么我們就要多添加一個數組用來記錄覆蓋了兩次或者兩次以上的區間大小。

Sum[rt]表示覆蓋了一次的區間

Sum2[rt]表示覆蓋了兩次的區間

最開始跟上面的沒有什么差別

假設Col[rt] >= 2的話。非常明顯這個區間一定都被覆蓋了至少是兩次

假設Col[rt] == 1的話,這里大家能夠思考一下,直接從Sum2[rt] = Sum[rt << 1] + Sum[rt << 1|1]

這里為什么是從子節點傳上來呢,假設Col[rt] == 1的話。證明此時這個位置已經被覆蓋了一次,假設子節點也被覆蓋了一次那不就是子節點被覆蓋了兩次嗎,如此直接傳給父親節點,表示這個區間被覆蓋了兩次的答案

如此,假設Col[rt] == 0的話,證明這個地方沒有被覆蓋一次。那么我們僅僅有從子節點將覆蓋了兩次的結果傳來了。

Sum2[rt] = Sum2[rt << 1] + Sum2[rt << 1|1];

  1. void pushup(int rt,int l,int r) {  
  2.     if(Col[rt]) Sum[rt] = X[r + 1] - X[l];  
  3.     else if(l == r) Sum[rt] = 0;  
  4.     else Sum[rt] = Sum[rt << 1] + Sum[rt << 1|1];  
  5.   
  6.     if(Col[rt] >= 2) Sum2[rt] = X[r + 1] - X[l];  
  7.     else if(l == r) Sum2[rt] = 0;  
  8.     else if(Col[rt] == 1) Sum2[rt] = Sum[rt << 1] + Sum[rt << 1|1];  
  9.     else if(Col[rt] == 0) Sum2[rt] = Sum2[rt << 1] + Sum2[rt << 1|1];  
  10. }  

提供模板出處:http://blog.csdn.net/qq_18661257/article/details/47658101


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM