线段树-扫描线
这其实是计算几何的一部分。一般被用来解决图形面积、周长等问题。
Atlantis 问题(板题)
题意
求给定的 \(n\) 个矩形的面积并
解法
如图:
-
每一块颜色不同的部分都是一个矩形,这 \(n\) 个矩形的面积并就是重新划分后各个颜色的矩形的面积和
-
扫过的距离 乘 当前的宽度就是当前矩形的面积
(从左到右扫)
若一个矩形的左下顶点坐标为 \((x_1,y_1)\) ,右上顶点坐标为 \((x_2,y_2)\)
-
将它的左沿和右沿两条边存成一个四元组;左:\((x_1,y_1,y_2,1)\),右:\((x_2,y_1,y_2)\) 。最后的标记:\(1\) 表示加入这条边;\(-1\) 表示减去这条边
-
将 \(n\) 个矩形都这样做处理,就得到 \(2n\) 条边,把这 \(2n\) 条边按照 \(x\) 的大小从小到大排序
-
因为数据可能很大而且不一定是整数,所以要对 \(y\) 进行 离散化 处理
模板代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+5;
int n;
double ls[N<<1];
struct line{
int x,y1,y2,mrk;
}a[N<<4];
struct node{
int l,r,sum,len;//sum:被完全覆盖的次数 ; len:被选取的长度
}tr[N<<4];
bool cmp(line x,line y){
return x.x<y.x;
}
void build(int node,int l,int r){
tr[node].l=l,tr[node].r=r;
tr[node].len=0;
tr[node].sum=0;
if(l==r)
return;
int mid=(l+r)>>1;
build(node<<1,l,mid);
build(node<<1|1,mid+1,r);
return;
}
void pushup(int node){
int l=tr[node].l,r=tr[node].r;
if(tr[node].sum)
tr[node].len=ls[r+1]-ls[l];
else
tr[node].len=tr[node<<1].len+tr[node<<1|1].len;
}
void change(int node,int l,int r,int x){
int L=tr[node].l,R=tr[node].r;//L,R与l,r 意义完全不同
if(ls[R+1]<=l || ls[L]>=r)//R+1才能覆盖完区间
return;
if(l<=ls[L] && r>=ls[R+1]){
tr[node].sum+=x;
pushup(node);
return;
}
change(node<<1,l,r,x);
change(node<<1|1,l,r,x);
pushup(node);
}
signed main(){
cin>>n;
for(int i=1;i<=n;++i){
int x1,y1,x2,y2;
cin>>x1>>y1>>x2>>y2;
a[i*2-1].x=x1,a[i*2-1].y1=y1,a[i*2-1].y2=y2;
a[i*2].x=x2,a[i*2].y1=y1,a[i*2].y2=y2;
a[i*2-1].mrk=1,a[i*2].mrk=-1;
ls[i*2-1]=y1,ls[i*2]=y2;
}
n<<=1;//后面用起来方便
sort(a+1,a+n+1,cmp);
sort(ls+1,ls+n+1);//离散化
int tot=unique(ls+1,ls+n+1)-ls-1;//去重
ls[tot+1]=0x3f3f3f3f;
build(1,1,tot);//建树
int ans=0;
for(int i=1;i<n;++i){
change(1,a[i].y1,a[i].y2,a[i].mrk);
ans+=tr[1].len*(a[i+1].x-a[i].x);
}
cout<<ans;
return 0;
}