扫描线

问题:给你\(n\)个矩形的左上角的坐标和右下角的坐标,问你这\(n\)个矩形所覆盖的总面积。
对于这个问题,我们可以使用扫描线。
扫描线
将几个矩形分成如下图所示的样子(不同的颜色分开求,蓝色表示原矩形):

使用线段树维护\(y\)轴,\(x\)轴上的直线从左到右作添加删除操作(矩形左边就加,右边就减),同时计算两相邻直线间距离乘上线段树上的覆盖长度,将它加入总面积中。
使用线段树维护时,可以用一个\(cover\)记录整个区间被整条线段覆盖了几次(大于0次覆盖长度就是整个区间的长度,等于0次就是左右子树的覆盖长度和)。
注意:如果要离散化,离散化后的单位可能不均,如10-->1,20-->2,50-->3,那么[1,2]间的距离就是10,[2,3]间的距离就是30,这里需要再开数组记录。
代码

#include<iostream>
#include<algorithm>
#define int unsigned long long
using namespace std;
int n;
struct node{
	int x[3];
	int y[3];
}juzhen[100010];
struct nod{
	int zhi;
	int id;
	int p;
}a[200010];
int d[200010];
bool cmp(nod x,nod y){
	return x.zhi<y.zhi;
}
int cnt=0;
struct nde{
	int l,r;
	int cover;
	int chang;
}tree[1600010];
void build(int i,int l,int r){
	tree[i].l=l;
	tree[i].r=r;
	if(l+1>=r){
		return ;
	}
	int mid=(l+r)/2;
	build(i*2,l,mid);
	build(i*2+1,mid,r);
	return ;
}
void add(int i,int l,int r){
	if(tree[i].l>=l&&tree[i].r<=r){
		tree[i].cover++;
		tree[i].chang=d[tree[i].r]-d[tree[i].l];
		return ;
	}
	if(tree[i].r<l||tree[i].l>r){
		return ;
	}
	if(tree[i*2].r>=l){
		add(i*2,l,r);
	}
	if(tree[i*2+1].l<=r){
		add(i*2+1,l,r);
	}
	if(tree[i].cover==0){
		tree[i].chang=tree[i*2].chang+tree[i*2+1].chang;
	}
	return ;
}
void del(int i,int l,int r){
	if(tree[i].l>=l&&tree[i].r<=r){
		tree[i].cover--;
		if(tree[i].cover==0){
			tree[i].chang=tree[i*2].chang+tree[i*2+1].chang;
		}
		return ;
	}
	if(tree[i].r<l||tree[i].l>r){
		return ;
	}
	if(tree[i*2].r>=l){
		del(i*2,l,r);
	}
	if(tree[i*2+1].l<=r){
		del(i*2+1,l,r);
	}
	if(tree[i].cover==0){
		tree[i].chang=tree[i*2].chang+tree[i*2+1].chang;
	}
	return ;
}
signed main(){
	cin>>n;
	build(1,1,n*2);
	for(int i=1;i<=n;i++){
		cin>>juzhen[i].x[1]>>juzhen[i].y[1]>>juzhen[i].x[2]>>juzhen[i].y[2];
		a[2*i-1].zhi=juzhen[i].x[1];
		a[2*i-1].id=i;
		a[2*i-1].p=1;
		a[2*i].zhi=juzhen[i].x[2];
		a[2*i].id=i;
		a[2*i].p=2;
	}
	sort(a+1,a+2*n+1,cmp);
	for(int i=1;i<=2*n;i++){
		if(a[i].zhi==a[i-1].zhi&&i!=1){
			juzhen[a[i].id].x[a[i].p]=cnt;
		}
		else{
			d[++cnt]=a[i].zhi;
			juzhen[a[i].id].x[a[i].p]=cnt;
		}
	}
	for(int i=1;i<=n;i++){
		a[2*i-1].zhi=juzhen[i].y[1];
		a[2*i-1].id=i;
		a[2*i-1].p=1;
		a[2*i].zhi=juzhen[i].y[2];
		a[2*i].id=i;
		a[2*i].p=2;
	}
	sort(a+1,a+2*n+1,cmp);
	int ans=0;
	for(int i=1;i<2*n;i++){
		if(a[i].p==1){
			add(1,juzhen[a[i].id].x[1],juzhen[a[i].id].x[2]);
		}
		else{
			del(1,juzhen[a[i].id].x[1],juzhen[a[i].id].x[2]);
		}
		ans+=(a[i+1].zhi-a[i].zhi)*tree[1].chang;
	}
	cout<<ans;
	return 0;
}
posted @ 2022-06-06 10:01  zzzzzz2  阅读(72)  评论(0)    收藏  举报