學習筆記 掃瞄線

2022-09-21 05:27:07 字數 3187 閱讀 8727

一.關於掃瞄線

基礎是求周長並和面積並的演算法。

注意,掃瞄線是一條不存在的線。

假設有一條掃瞄線從乙個圖形的下方掃向上方(或者左方掃到右方),那麼通過分析掃瞄線被圖形截得的線段就能獲得所要的結果。

二.掃瞄線求面積並(由於本人不會做圖,以下均來自洛谷的題解)

我們看一下這個東西。

我們模擬一條掃瞄線,從下到上掃過整個平面。

這條掃瞄線會在遇到橫向線段的時候停下來更新一些東西。那麼整個圖形就可以找出四條線段。

如圖:

我們要更新什麼呢?當然是計算線段的長度了。

所以我們要記錄的第一種東西就確定了。是每條線段的左右端點座標。

然後我們把這些座標放到乙個陣列,就叫x吧。

這個東西是需要排序的。具體原因請往下看。

那麼我們考慮,在掃瞄線單調向上的過程中,怎麼知道**有面積,**是空的呢?

我們想到乙個矩形有上底和下底,在掃瞄線單調向上的過程中,總是先遇到乙個矩形的下底,再遇到上底,然後這個圖形的面積就被掃瞄線掃過了。

所以我們要記錄第二個東西,給每條橫向線段賦上乙個權值,如果是下底則賦為1,如果是下底則賦為-1,這樣掃瞄線掃有權值的部分就有我們要計算的面積。

然後我們考慮面積並的問題,我們知道,兩個矩形相交的部分只能計算一次面積。

兩個矩形相交,乙個矩形的橫向邊上至少有1個另乙個矩形邊上的點。

那麼如上圖x[1]和x[3]作為左右端點組成的線段可以分成兩部分,x[1]和x[2]組成線段和x[2]和x[3]組成線段。

這樣這個圖形就被橫向分成了4條橫向邊3部分,縱向分成4條縱向邊3部分。

但是掃瞄線是從下往上掃的,只能處理橫向邊的分割,縱向邊怎麼辦呢?

這時我們可以想到使用線段樹。

我們用線段樹的每個節點來儲存一條線段,這條線段不一定是一組左右端點截成的,可能是左-左端點或右-右端點,也可能是非同組的左右端點。

如下圖,我們可以對這個圖形像這樣建立一棵線段樹。

對於上面那句話大家可以通過上圖很明顯地看出來。

當一條線段被掃瞄線掃到的時候,立即更新線段樹每個節點維護的線段的覆蓋長度和權值。

比如掃到最下面這條線段的時候,線段樹1,2節點維護的線段覆蓋長度和權值就會被更新。

掃到下數第二條線段的時候,1,2,3,5,6節點維護的線段覆蓋長度和權值就會被更新。

那麼不難看出線段樹所維護的左右節點實際上是線段的編號,另外維護線段覆蓋長度和權值。

這樣掃瞄線掃有權值的部分就有我們要計算的面積,那麼就更新線段覆蓋長度。

那麼對於每一條線段我們也記錄它的左右端點和縱座標以及權值,按照縱座標優先公升序排序,保證掃瞄線從下向上掃。

還剩下乙個問題,x陣列。

另外,相同的x我們其實只需要乙個就夠了,所以我們要離散化處理。

這樣最後就可以進行計算面積了。

s=σ線段覆蓋長度*掃過的高度,即縱座標的差。

**如下:(我覺得上面沒理解透徹的同學看下**也應該理解得差不多了吧)

題目:洛谷【模板】掃瞄線

#includeusing

namespace

std;

struct segment//

從下向上的掃瞄線 那麼就是橫向的線段

//過載運算子 使得縱座標小的線段 也就是每個矩形的下底優先被掃瞄線讀到

}seg[800010];//

空間要開足夠大 每個矩形最少有兩條線段 所以最少應該開兩倍

struct segtree//

線段樹部分

tree[1600010];//

空間要開足夠大 乙個線段樹四倍 最好開到八倍會好一點

long

long x[800010

];long

long

n,x1,x2,yy,y2,ans;

void build(int k,long

long l,long

long

r)

int mid=l+r>>1

; build(k

<<1

,l,mid);

build(k

<<1|1,mid+1

,r);

}void pushup(intk)

else

}void update(int k,long

long l,long

long r,int val)//

當掃瞄線掃到一條線段 執行此操作 l,r分別記錄線段的左右端點座標 val代表這是下底還是上底

if(l<=x[l] && x[r+1]<=r)

//由於有剪枝 我們就不用判斷了 直接修改子樹就好了

update(k<<1

,l,r,val);

update(k

<<1|1

,l,r,val);

pushup(k);

} int

main()

;//記錄線段的資訊

seg[2*i]=(segment);//

按照這個操作 開兩倍是正常的

} n

<<=1;//

線段數是矩形數二倍

sort(seg+1,seg+n+1);//

按照縱座標公升序排序

sort(x+1,x+n+1);//

相同的橫座標我們只需要一次

int cnt=unique(x+1,x+n+1)-x-1;//

因此通過離散化來確定不同橫座標的數量

build(1,1,cnt-1);//

這裡cnt要-1 因為我們cnt代表橫座標的數量

//而線段樹儲存的是線段數量 根據植樹問題 線段數=點數-1

for(int i=1;i//

最後一條邊不需要計算和更新了吧

printf(

"%lld

",ans);

return0;

}

view code

三.掃瞄線求周長並

待補充~

其實可以理解一下 是掃瞄線左右掃一次和上下掃一次~

掃瞄線學習

對掃瞄線步驟的理解 1 首先要儲存所有的邊,並按照x值從小到大排序,如果是左邊,標記為1,如果是右邊,標記為 1。struct line 2 掃瞄線從左往右掃瞄,每遇到一條邊就停下來,將這條邊投影到總區間上,投影 其實就是執行在總區間中插入或者刪除線段操作。掃瞄到flag為1的邊,為左邊,往總區間加...

線段樹掃瞄線 學習筆記

見注釋 參考 include include using namespace std const int n 205 struct line line n struct node tr n 2 int n,cnt double fy n xx1,xx2,yy1,yy2 void build int ...

掃瞄線 線段樹學習筆記

如果仔細觀察掃瞄器工作就會發現,掃瞄器掃瞄時是一條線從頭到尾掃一遍成像。這個演算法形象化表示也是如此。首先是掃瞄線板子題 矩形面積並。題意 在平面直角座標系中,給出若干個矩形,求所有矩形的面積並。太長不看版 對於所有矩形的端點按照縱座標排序,然後依次掃瞄矩形每加入一條線段覆蓋,線段樹查詢所有區間中覆...