给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积.
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
用线段数维护y轴,每次入边或出边时结算面积,要注意离散化
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <stack>
#include <cmath>
#include <vector>
#include <map>
using namespace std;
const int NUM=4005;
struct point
{
int l,r,f;
int dv; //dv表示区间被覆盖次数,如果区间不均匀dv==-1
}tree[NUM*4];
int LL,RR,val;
double interval,cod[NUM];
struct edge
{
double x,y1,y2;
int val;
}scanline[2005];
bool cmp(edge a,edge b)
{
return a.x<b.x;
}
void build(int k,int LL,int RR)
{
tree[k].l=LL,tree[k].r=RR;
tree[k].f=tree[k].dv=0;
if(tree[k].l==tree[k].r)
return ;
int bet=(tree[k].l+tree[k].r)/2;
build(k*2,LL,bet);
build(k*2+1,bet+1,RR);
}
void pushdown(int k)
{
tree[k*2].f+=tree[k].f;
tree[k*2+1].f+=tree[k].f;
tree[k*2].dv+=tree[k].f;
tree[k*2+1].dv+=tree[k].f;
tree[k].f=0;
}
void pushup(int k)
{
if(tree[k*2].dv==tree[k*2+1].dv)
tree[k].dv=tree[k*2].dv;
else
tree[k].dv=-1;
}
void change(int k)
{
if(LL<=tree[k].l&&RR>=tree[k].r&&tree[k].dv!=-1){
tree[k].f+=val;
tree[k].dv+=val;
return;
}
if(tree[k].f) pushdown(k);
int bet=(tree[k].l+tree[k].r)/2;
if(LL<=bet) change(k*2);
if(RR>bet) change(k*2+1);
pushup(k);
}
void ask(int k)
{
if(LL<=tree[k].l&&RR>=tree[k].r&&tree[k].dv!=-1){
if(tree[k].dv>=2){
interval+=cod[tree[k].r+1]-cod[tree[k].l]; //注意+1;
}
return ;
}
if(tree[k].f) pushdown(k);
int bet=(tree[k].l+tree[k].r)/2;
if(LL<=bet) ask(k*2);
if(RR>bet) ask(k*2+1);
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
build(1,0,NUM-1);
int n;
scanf("%d",&n);
double x1,y1,x2,y2;
int index=0;
for(int i=0;i<n;i++){
scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2);
cod[index]=y1,cod[index+1]=y2;
scanline[index].val=1;
scanline[index].x=x1;
scanline[index].y1=y1;
scanline[index].y2=y2;
scanline[index+1].val=-1;
scanline[index+1].x=x2;
scanline[index+1].y1=y1;
scanline[index+1].y2=y2;
index+=2;
}
sort(cod,cod+index);
sort(scanline,scanline+index,cmp);
int k=1;
for(int i=1;i<index;i++){ //离散化排重
if(cod[i]!=cod[k-1])
cod[k++]=cod[i];
}
double ans=0;
for(int i=0;i<index-1;i++){
LL=lower_bound(cod,cod+k,scanline[i].y1)-cod;
RR=lower_bound(cod,cod+k,scanline[i].y2)-cod-1; //面积是连续的,要先将区间转化为点再用线段树维护,这里要注意-1;
val=scanline[i].val;
change(1);
LL=0,RR=NUM-1,interval=0;
ask(1);
ans+=interval*(scanline[i+1].x-scanline[i].x);
}
printf("%.2lf\n",ans);
}
return 0;
}