掃描線

其實沒有想象的那麼高端

給你一堆平面內的矩形,求他們的面積並(就是覆蓋的面積)node

若是直接每次覆蓋記錄會致使部分面積重複計算,咱們考錄掃描線算法c++

圖是luogu上找的(算法

就這麼張圖吧:數組

圖1

從圖中能夠看到會有重複覆蓋的地方ui

若是把它分割一下:spa

圖2

而後能夠把問題分到每兩條線之間求面積在加起來,就不會出現算重的狀況3d

因此咱們要順着從下往上(從哪往哪都行)掃描,產生的線就叫掃描線code

$ Q: $ 那麼如何區分是上邊仍是下邊呢?blog

$ A: $ 賦值:把上邊賦值爲 $ -1 $,下邊賦值爲 $ 1 $ ,而後掃的時候記錄一下就行了get

這時候就須要在根據橫座標進行再分了:

把每一個輸入的橫座標記錄下來排個序,而後掃描按區間進行操做就行了

示意圖:

圖3

以上操做能夠用線段上維護。

PS.線段樹別忘了開二倍數組

code(模板題 Luogu P5490):

#include<bits/stdc++.h>
#define ls(x) x<<1 //左兒子
#define rs(x) x<<1|1 //右兒子
#define int long long //十年oi一場空,不開longlong見祖宗 
using namespace std;
int read()//快讀 
{
int x=0,y=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')y=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0',c=getchar();}
return x*y;
}
int ch[2000010][2],dat[2000010],cnt,f[2000010],xx[2000010];//ch、dat是線段樹內容,f是記錄每一個縱區間的操做結果(是否在矩形內),cnt是記錄邊的個數 ,xx是因此橫座標(用於分縱區間) 
struct node//記錄每條線(矩形的上下邊) 
{
int l,r,h,dat;//l是左端點,r是右端點,h是y(縱座標),dat是上下邊(-1上,1下) 
}e[2000010];
bool cmp(node x,node y)//從下到上枚舉(模擬掃描過程) 
{
return x.h<y.h;
}
void build(int l,int r,int x)
{
ch[x][0]=l;
ch[x][1]=r;//定義左右區間
dat[x]=0;
f[x]=0;
if(l==r)
return;
int mid=l+r>>1;
build(l,mid,ls(x));
build(mid+1,r,rs(x));
}
void pushup(int x)//修改每個區間的面積和
{
if(f[x])//還在矩陣內
dat[x]=xx[ch[x][1]+1]-xx[ch[x][0]];//繼續計算面積
else
dat[x]=dat[ls(x)]+dat[rs(x)];//不然正常上傳(pushup操做) 
}
void update(int x,int l,int r,int d)
{
//一下兩句別忘了套xx,ch[x][1]別忘了+1 
if(xx[ch[x][1]+1]<=l||xx[ch[x][0]]>=r)//徹底不相交
return;//直接return
if(xx[ch[x][0]]>=l&&xx[ch[x][1]+1]<=r)//徹底包含
{
f[x]+=d;//記錄通過的上下邊
pushup(x);//上傳 
return;
}
//其餘狀況爲有相交但不包含
update(ls(x),l,r,d);
update(rs(x),l,r,d);
pushup(x);
}
int n,ans;//字面意思 
signed main()
{
n=read();
for(int i=1;i<=n;i++)//輸入 
{
int x1=read(),y1=read(),x2=read(),y2=read();
e[++cnt].dat=1,e[cnt].l=x1,e[cnt].r=x2,e[cnt].h=y1,xx[cnt]=x1;
e[++cnt].dat=-1,e[cnt].l=x1,e[cnt].r=x2,e[cnt].h=y2,xx[cnt]=x2;
}
sort(xx+1,xx+cnt+1);
sort(e+1,e+1+cnt,cmp);
int ji=unique(xx+1,xx+cnt+1)-xx-1;//橫座標去重
build(1,cnt-1,1);//建(線段)樹
for(int i=1;i<cnt;i++)//小於cnt不是小於等於 
{
update(1,e[i].l,e[i].r,e[i].dat);
ans+=dat[1]*(e[i+1].h-e[i].h);//整個橫區間的寬度乘高度 
}
printf("%lld",ans);
}

咕咕咕~

相關文章
相關標籤/搜索