如图,我们来求两个矩形所覆盖的总面积
我们先定义一条平移于y轴的扫描线(如图,黄线标识),另其从左到右逐个扫描每个所给矩形的竖边,我们命名为线1,线2,线3,线4(横坐标为下,x1,x2,x3,x4),每个矩形的纵坐标的上下限依次为y1 y2 y3 y4
当扫描线从线1扫描到线2的时候,扫描到的面积为s1=(y3-y1)*(x2-x1)
当扫描线从线2扫到线3的时候,面积s2=(y4-y1)*(x3-x2)
……
这样总面积s=s1+s2+s3
实现
我们先定义一个结构体表示每个矩形中的竖边
struct line{
double x;//横坐标
double y_up;//竖线的纵坐标上限
double y_down;//下限
int state;//1表示矩形的左竖边,-1表示右竖边
}q[maxn];
还要对存储竖边的结构体根据x进行从小到大的排序
然后呢我每次扫描到一个竖边都对询问其所扫描到的矩形高度,这个过程我们是通过将y轴上的每个区间的线段树上
我们定义一个结构体表示线段树的节点
struct node{
double left;//线段树的左结界,也就是y轴上的大的坐标
double right;//右结界,同理
int cover;//目前扫描线所覆盖的矩形个数
double len;//目前扫描线于矩形重合的长度
}p[maxn];
对于每个区间节点,cover 表示目前扫描线覆盖的矩形数量,如果cover==0,说明在这个区间并没有全部与矩形重合,只是部分子区间与矩形重合,每次扫描到矩形竖边,都对线段树进行更新,最后将线段树区间与矩形重合的长度全部返回到线段树的主根,然后用这个长度乘以扫描线从上一个竖边到这个竖边所走的距离(x轴上距离)得出面积
代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#define maxn 10000
using namespace std;
struct node{
double left,right;
int cover;
double len;
}p[maxn];
struct line{
double x;
double y_up;
double y_down;
int state;
}q[maxn];
bool cmp(line a, line b){
return a.x<b.x;
}
double point[maxn];
void build(int root,int left,int right){
p[root].left=point[left];
p[root].right=point[right];
if(right-left>1){
int mid=(left+right)>>1;
build(root<<1|1,left,mid);
build((root<<1)+2,mid,right);
}
}
void update(int root,double left,double right,int val){
if(p[root].left==left&&p[root].right==right){
p[root].cover+=val; //更新
if(p[root].cover==0)
p[root].len=p[root<<1|1].len+p[(root<<1)+2].len;
if(p[root].cover!=0)
p[root].len=p[root].right-p[root].left;
return;
}
int left_root=root<<1|1; //左儿子
int right_root=(root<<1)+2; //右儿子
int mid=p[left_root].right;
if(right<=p[left_root].right){
update(left_root,left,right,val);
}
else if(left>=p[right_root].left){
update(right_root,left,right,val);
}
else{
update(left_root,left,mid,val);
update(right_root,mid,right,val);
}
if(p[root].cover==0)
p[root].len=p[right_root].len+p[left_root].len;
}
int main()
{
double x,y,x1,y1;
int cnt=0;
int n;
int t=0;
while(cin>>n&&n){
t++;
cnt=0;
for(int i=0;i<n;i++){
cin>>x>>y>>x1>>y1; //左下角坐标 右上角坐标
q[cnt]=(line){x,y1,y,1};
point[cnt]=y;
q[++cnt]=(line){x1,y1,y,-1};
point[cnt]=y1;
cnt++;
}
sort(q,q+cnt,cmp);
sort(point,point+cnt);
build(0,0,cnt-1);
double s=0;
update(0,q[0].y_down,q[0].y_up,q[0].state);
for(int i=1;i<cnt;i++){
s+=p[0].len*(q[i].x-q[i-1].x);
update(0,q[i].y_down,q[i].y_up,q[i].state);
}
cout<<"Test case #"<<t<<endl;
printf("Total explored area: %.2lf\n\n",s);
}
return 0;
}