扫描线

其实没有想象的那么高端

给你一堆平面内的矩形,求他们的面积并(就是覆盖的面积)

如果直接每次覆盖记录会导致部分面积重复计算,我们考录扫描线算法

图是luogu上找的(

就这么张图吧:

图1

从图中可以看到会有重复覆盖的地方

如果把它分割一下:

图2

然后可以把问题分到每两条线之间求面积在加起来,就不会出现算重的情况

所以我们要顺着从下往上(从哪往哪都行)扫描,产生的线就叫扫描线

$ Q: $ 那么如何区分是上边还是下边呢?

$ A: $ 赋值:把上边赋值为 $ -1 $,下边赋值为 $ 1 $ ,然后扫的时候记录一下就好了

这时候就需要在根据横坐标进行再分了:

把每个输入的横坐标记录下来排个序,然后扫描按区间进行操作就好了

示意图:

图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);
}

咕咕咕~

posted @ 2020-10-15 15:11  Dickson  阅读(157)  评论(0)    收藏  举报