扫描线
问题:给你\(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;
}