扫描线

关于扫描线

基础是求周长并和面积并的算法。

注意,扫描线是一条不存在的线。

假设有一条扫描线从一个图形的下方扫向上方(或者左方扫到右方),那么通过分析扫描线被图形截得的线段就能获得所要的结果。

实现扫描线

这里将出现的所有矩形以横坐标为分割线划分成一个个竖直的长条,计算每个长条的面积,相加就可以得到答案,如下图:

每个长条内部都是一堆等宽的小矩形,我们求出这些矩形在竖直方向上的长度,然后乘以宽度就是这个长条的面积。

如何求解每个长条竖直方向上的长度之和呢?首先遍历所有矩形,找到这个长条中所有的线段,然后使用区间合并即可。

时空复杂度 \(O(n^2×log\) \(n)\)

//关于此题卡掉了yxc STl做法。。。。 
#include<bits/stdc++.h>

#define int long long
#define rint register int
#define endl '\n' 

using namespace std;
const int N = 2e5 + 5;

#define find(x) lower_bound(a+1,a+1+k,x)-a

int n,xx1,yy1,xx2,yy2,a[N],k,ans;

struct node{int x,yy1,yy2,v;friend bool operator<(node i,node j){return i.x<j.x;}}line[N];
int l[N],r[N],sum[N],tot[N];

void build(int i,int lt,int rt){
	l[i]=lt;r[i]=rt;
	if(lt==rt) return;
	int m=(lt+rt)>>1;
	build(i<<1,lt,m);
	build(i<<1|1,m+1,rt);
	return ;
}

void update(int i){
	sum[i]=tot[i]?a[r[i]+1]-a[l[i]]:sum[i<<1]+sum[i<<1|1];
	return ;
}

void fix(int i,int x,int y,int z){
	if(l[i]>y||r[i]<x) return;
	if(x<=l[i]&&y>=r[i]){tot[i]+=z;update(i);return;}
	fix(i<<1,x,y,z);fix(i<<1|1,x,y,z);update(i);
	return ;
}

signed main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>xx1>>yy1>>xx2>>yy2;
		a[(i<<1)-1]=yy1;a[i<<1]=yy2;
		line[(i<<1)-1].x=xx1;line[i<<1].x=xx2;
		line[(i<<1)-1].v=1;line[i<<1].v=-1;
		line[(i<<1)-1].yy1=line[i<<1].yy1=yy1;
		line[(i<<1)-1].yy2=line[i<<1].yy2=yy2;
	}
	n<<=1;
	
	sort(line+1,line+1+n);
	sort(a+1,a+1+n);
	k=unique(a+1,a+1+n)-a-1;
	
	build(1,1,k-1);
	
	for(rint i=1;i<=n;i++){
		ans+=1ll*(line[i].x-line[i-1].x)*sum[1];
		fix(1,find(line[i].yy1),find(line[i].yy2)-1,line[i].v);
	}
	
	cout<<ans<<endl;
	
	return 0;
}

posted @ 2022-07-18 11:36  PassName  阅读(71)  评论(0编辑  收藏  举报