一.關於掃瞄線
基礎是求周長並和面積並的演算法。
注意,掃瞄線是一條不存在的線。
假設有一條掃瞄線從乙個圖形的下方掃向上方(或者左方掃到右方),那麼通過分析掃瞄線被圖形截得的線段就能獲得所要的結果。
二.掃瞄線求面積並(由於本人不會做圖,以下均來自洛谷的題解)
我們看一下這個東西。
我們模擬一條掃瞄線,從下到上掃過整個平面。
這條掃瞄線會在遇到橫向線段的時候停下來更新一些東西。那麼整個圖形就可以找出四條線段。
如圖:
我們要更新什麼呢?當然是計算線段的長度了。
所以我們要記錄的第一種東西就確定了。是每條線段的左右端點座標。
然後我們把這些座標放到乙個陣列,就叫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=σ線段覆蓋長度*掃過的高度,即縱座標的差。
**如下:(我覺得上面沒理解透徹的同學看下**也應該理解得差不多了吧)
題目:洛谷【模板】掃瞄線
#includeusingview codenamespace
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;
}
三.掃瞄線求周長並
待補充~
其實可以理解一下 是掃瞄線左右掃一次和上下掃一次~
掃瞄線學習
對掃瞄線步驟的理解 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 ...
掃瞄線 線段樹學習筆記
如果仔細觀察掃瞄器工作就會發現,掃瞄器掃瞄時是一條線從頭到尾掃一遍成像。這個演算法形象化表示也是如此。首先是掃瞄線板子題 矩形面積並。題意 在平面直角座標系中,給出若干個矩形,求所有矩形的面積並。太長不看版 對於所有矩形的端點按照縱座標排序,然後依次掃瞄矩形每加入一條線段覆蓋,線段樹查詢所有區間中覆...