如果我們要統計乙個由多個矩形重疊組成的圖形的面積。
暴力太麻煩,而計算機又不能想人一樣計算,那怎麼求解呢?
我們可以使用掃瞄線fa
想象一下,有一條線,按照乙個順序(從左到右呀,從上到下呀...)掃瞄乙個圖形。
我們很容易可以得到,兩條最近的相鄰線段間,所包含的這乙個圖形的面積是規整的矩形,又因為這些矩形的長or寬我們已經知道(就是資料中給定矩形的邊),所以我們只需要統計另一條邊就可以了。
維護線段,我們就可以使用西安段素了。
同乙個矩形,在遇到他的第一條和掃瞄線(是乙個線段樹)平行的的邊時,在這條邊和掃瞄線重疊的部分上累加1(一定是累加),然後繼續往後掃瞄,遇到其他矩形的第一條邊時亦是。
知道碰到某個矩形的第二條邊,在減去。
那在掃瞄中怎麼算面積呢? 我們需要統計的是掃瞄線上有多少長度被覆蓋,然後乘上兩條線段之間的垂直距離就可以了。
那統計周長怎麼算呢?
(現在都是從下往上掃)先來看平行於掃瞄線的邊。
兩次掃瞄後,掃瞄線上的被覆蓋長度的差的絕對值就是所增加的長度。
為什麼是差呢?又為什麼是絕對值呢?
我們通過一張圖來解釋:
可以看出,這是兩個矩形巢狀,然後自己在寬扁的矩形的左邊第一條邊的掃瞄線上的被覆蓋的長度,和另乙個矩形的第一條邊時的差就是第二個矩形延展出來的長度,然後絕對值的意思是當乙個矩形結束時,他有可能會與他有重疊的矩形凹陷,然後絕對值就將這種情況的邊取了出來。
那於掃瞄線垂直的呢?
我們可以發現,兩次掃瞄中間的那些與掃瞄線垂直的線段,他的長度都是兩次掃瞄之間的距離,然後我們就需要統計他的個數
可以發現, 兩次掃瞄中,有多少個不相連的空隙,就有相同個數*2條如此線段
然後具體實現會從詳解。請先從main()看起
#include#include#includeusing namespace std;
const int manx=5010;
struct edge
};struct node
;int te,tx,k;
edge line[manx<<1];
int base[manx<<1];
int datx[manx<<1];
node t[manx<<5];
void add(int a,int b,int c,int d)
bool compare(const edge &a,const edge &b)
void make_base()
//簡簡單單的去重
return ;
}void build(int root,int l,int r)
int check(int val)
int mid=(l+r)>>1;
updata(root<<1,l,mid,al,ar,k);
updata(root<<1|1,mid+1,r,al,ar,k);
push_up(root,l,r);//合併,這裡沒有push_down
}int main()
sort(line+1,line+1+te,compare);//排序,有重邊一定要下邊先被處理
sort(datx+1,datx+1+tx);//離散化
make_base();//真離散化
build(1,1,k-1);//建樹,注意k為離散化後的座標個數,這裡要建立k-1個葉子節點,線段樹中存的是相鄰兩個座標之間的間隙
int ans=0; //周長
int last=0;//用於記錄兩次掃瞄的被覆蓋的長度的變數
for(int i=1;i<=te;i++)
printf("%d",ans);
}
P5490 模板 掃瞄線 掃瞄線
題目描述 求 n 個矩形的面積並。輸出格式 一行乙個正整數,表示 n 個矩形的並集覆蓋的總面積。発生 線段樹開小了,因為n變成了兩倍,線段樹就得開4 2 8倍 對每一根掃瞄線,維護所截得的長度,每次乘以兩根掃瞄線高度差就得到了面積並 截得長度用線段樹維護即可 注意線段樹需要離散化 include i...
掃瞄線入門
聽說掃瞄線很牛掰,於是就見識了一下。之前做過一道掃瞄線的題,brother,就是判斷矩形是否被矩形內部的車攻擊到。當時是把矩形拆成出邊和入邊 豎直的 把所有小於x2的車加進圖中,掃 y1,y2 中x最小的車的x.和x1判斷比較。然後交換x,y掃一遍 當時只是感覺線段樹很神奇,還可以這樣搞,後來才知道...
模板 掃瞄線
矩形有重疊,求總面積。橫縱兩條掃瞄線 includeusing namespace std double x 2002 y 2002 最多100個矩形,所以最多只有200條橫線或縱線 double a 1002 4 矩形實際座標,分別是左下角橫 縱,右下角橫 縱 bool cover 2002 20...