Description
给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积.
Input
输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据的第一行是一个正整数N(1<=N<=1000),代表矩形的数量,然后是N行数据,每一行包含四个浮点数,代表平面上的一个矩形的左上角坐标和右下角坐标,矩形的上下边和X轴平行,左右边和Y轴平行.坐标的范围从0到100000.
注意:本题的输入数据较多,推荐使用scanf读入数据.
Output
对于每组测试数据,请计算出被这些矩形覆盖过至少两次的区域的面积.结果保留两位小数.
Sample Input
2
5
1 1 4 2
1 3 3 7
2 1.5 5 4.5
3.5 1.25 7.5 4
6 3 10 7
3
0 0 1 1
1 0 2 1
2 0 3 1
Sample Output
7.63
0.00
Solution
矩形面积交,扫描线+线段树或者扫描线+暴力都可以,线段树的话就维护区间被至少覆盖两次部分的长度。
代码:(扫描线+暴力)
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
template<typename T>inline void read(T &x){
T f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(x=0;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
x*=f;
}
const int maxn=3010;
const double eps=1e-10;
struct Seg{
double l,r,y,len;
int f;
bool operator<(Seg b)const{
if(fabs(y-b.y)<=eps)return f<b.f;
return y<b.y;
}
}q[maxn];
int n,cnt,T,tot,tot2,mp[maxn];
double ans,a[maxn],b[maxn];
int lower_bound(double *p,int l,int r,double val){
int pos=r+1,mid;
while(l<=r){
mid=(l+r)>>1;
if(val-p[mid]>eps)l=mid+1;
else r=mid-1,pos=mid;
}
return pos;
}
int main(){
read(T);
while(T--){
read(n);
ans=0;cnt=tot=tot2=0;
memset(mp,0,sizeof mp);
for(int i=1;i<=n;i++){
double x1,y1,x2,y2;
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
a[++tot]=x1;a[++tot]=x2;
q[++cnt].l=x1;q[cnt].r=x2;
q[cnt].y=y1;q[cnt].f=0;q[cnt].len=x2-x1;
q[++cnt].l=x1;q[cnt].r=x2;
q[cnt].y=y2;q[cnt].f=1;q[cnt].len=x2-x1;
}
sort(a+1,a+tot+1);
sort(q+1,q+cnt+1);
for(int i=1,j;i<=tot;i=j){
b[++tot2]=a[i];j=i;
while(fabs(a[j]-a[i])<=eps&&j<=tot)j++;
}
for(int i=1;i<=cnt;i++){
q[i].l=lower_bound(b,1,tot2,q[i].l);
q[i].r=lower_bound(b,1,tot2,q[i].r);
}
double lasty=0;
for(int i=1;i<=cnt;i++){
double l=0;
for(int j=1;j<tot2;j++)if(mp[j]>1)l+=(b[j+1]-b[j]);
ans+=(q[i].y-lasty)*l;lasty=q[i].y;
if(!q[i].f)for(int j=q[i].l;j<q[i].r;j++)mp[j]++;
else for(int j=q[i].l;j<q[i].r;j++)mp[j]--;
}
printf("%.2lf\n",ans);
}
return 0;
}