我用【l,r】来表示【l,r+1】这个区间,保证所有的区间都不会漏,可以自己尝试着画出线段树,就好理解了。
于是,只需要维护线段树的【1,len-1】这个区间即可维护整个区间(len为离散化之后的长度)
从左到右扫描,将每一条离散化后的竖边用结构体打包保存,包括了(x,y1,y2,flag),flag是1表示是矩形左边的竖边,-1表示右边的。
排序后,从左到右遍历竖边(最后一条竖边不用遍历),对于遍历的每条竖边,先将其对于的y轴的【y1,y2】区间加1或者减1,表示对于区间+1或者-1,然后累加每条竖边和他的下一条竖边夹着的矩形的面积即可,最后一条竖边没有下一条竖边了,于是不用遍历最后一条竖边
#include<bits/stdc++.h>
#define ls id<<1
#define rs id<<1|1
#define mid (l+r>>1)
using namespace std;
const int maxn = 1e2+7;
int n,len;
double x[maxn<<1],xx[maxn<<1];
int len_x;
double y[maxn<<1],yy[maxn<<1];
int len_y;
struct tt{
int x,y1,y2,flag;
}p[maxn<<1];
bool cmp(tt p1,tt p2){
return p1.x<p2.x;
}
void init(){
for(int i=1;i<=n;i++){
double x1,y1,x2,y2;
cin>>x1>>y1>>x2>>y2;
int l=(i<<1)-1,r=i<<1;
x[l]=xx[l]=x1,x[r]=xx[r]=x2;
y[l]=yy[l]=y1,y[r]=yy[r]=y2;
}
sort(x+1,x+1+len);
sort(y+1,y+1+len);
len_x=unique(x+1,x+1+len)-x-1;
len_y=unique(y+1,y+1+len)-y-1;
for(int i=1;i<=n;i++){
int l=(i<<1)-1,r=i<<1;
int px1=lower_bound(x+1,x+1+len_x,xx[l])-x;
int py1=lower_bound(y+1,y+1+len_y,yy[l])-y;
int px2=lower_bound(x+1,x+1+len_x,xx[r])-x;
int py2=lower_bound(y+1,y+1+len_y,yy[r])-y;
p[l]={px1,py1,py2,1};
p[r]={px2,py1,py2,-1};
}
sort(p+1,p+1+len,cmp);
}
int tree[maxn<<3];
double num[maxn<<3];
int lazy[maxn<<3];
void build(int l,int r,int id){
if(l==r){
tree[id]=0;
num[id]=y[l+1]-y[l];
return;
}
build(l,mid,ls);
build(mid+1,r,rs);
num[id]=num[ls]+num[rs];
tree[id]=0;
}
void up(int id){
tree[id]=min(tree[ls],tree[rs]);
if(tree[ls]==tree[rs])num[id]=num[ls]+num[rs];
else if(tree[ls]<tree[rs])num[id]=num[ls];
else num[id]=num[rs];
}
void down(int id){
lazy[ls]+=lazy[id];
lazy[rs]+=lazy[id];
tree[ls]+=lazy[id];
tree[rs]+=lazy[id];
lazy[id]=0;
}
void update(int l,int r,int id,int x,int y,int val){
if(x<=l&&r<=y){
tree[id]+=val;
lazy[id]+=val;
return;
}
if(lazy[id]){
if(l==r)lazy[id]=0;
else down(id);
}
if(x<=mid)update(l,mid,ls,x,y,val);
if(y>mid)update(mid+1,r,rs,x,y,val);
up(id);
}
int main(void){
int cnt=0;
int f=0;
while(cin>>n&&n){
len=n<<1;
init();//离散化数据
build(1,len_y-1,1);//初始化线段树
memset(lazy,0,sizeof(lazy));//别忘记初始化lazy数组 不然多个样例可能会wa
double ans=0;
for(int i=1;i<len;i++){
//每次更新一条竖边,对应y轴的区间[p[i].y1,p[i].y2-1]加上flag(左边为1,右边为-1),表示被覆盖或者取消覆盖
update(1,len_y-1,1,p[i].y1,p[i].y2-1,p[i].flag);
//矩形面积计算:底 ×高
ans+=(x[p[i+1].x]-x[p[i].x])*((y[len_y]-y[1])-(tree[1]?0:num[1]));
}
printf("Test case #%d\n",++cnt);
printf("Total explored area: %.2lf\n\n",ans);
}
/*
Test case #1
Total explored area: 180.00
*/
return 0;
}