Atlantis(hdu1542)
阅读原文时间:2023年07月11日阅读:1

题意:求n个矩阵的面积并。

/*
线段树维护扫描线
把每个矩形看成两条线段,从左到右添加线段,如果是矩形左边的线段,那就给线段所在的区间(y值)cover+1,反之则cover-1。
并且如果这条线段添加之前它所在的区间的cover>0,则统计面积。
另外如果求面积的交集,线段所在的区间的cover>1时统计面积。

PS:个人认为某位大神写的博客很好理解(这位大神还搞了一个线段树专辑?%%%):
http://www.cnblogs.com/ka200812/archive/2011/11/13/2247064.html
但是我觉得第一种算法每次都要找到叶子节点,貌似有点浪费时间,然而第二种又不会。。。
*/
#include
#include
#include
#define N 110
using namespace std;
double y[N*];int n,cnt,Cas;
struct node{
double x,y_down,y_up;int flag;
bool operator < (const node &s1)const{
return x<s1.x;
}
};node e[N*];
struct Node{
double x,y_down,y_up;int cover;
int flag;//是否为叶子节点
};Node tree[*N];

void build(int k,int l,int r){
tree[k].cover=;
tree[k].x=-;//代表这个区间最近一次的横坐标
tree[k].y_down=y[l];
tree[k].y_up=y[r];
tree[k].flag=;
if(l+==r){
tree[k].flag=;
return;
}
int mid=l+r>>;
build(k*,l,mid);
build(k*+,mid,r);
}

double insert(int k,double x,double l,double r,int flag){
if(r<=tree[k].y_down||l>=tree[k].y_up) return ;
if(tree[k].flag){
if(tree[k].cover>){
double ans=(x-tree[k].x)*(tree[k].y_up-tree[k].y_down);
tree[k].cover+=flag;
tree[k].x=x;
return ans;
}
else {
tree[k].cover+=flag;
tree[k].x=x;
return ;
}
}
double ans=;
ans+=insert(k*,x,l,r,flag);
ans+=insert(k*+,x,l,r,flag);
return ans;
}

int main(){
while(scanf("%d",&n)){
if(!n) break;
cnt=;
for(int i=;i<=n;i++){
double x1,y1,x2,y2;
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
y[++cnt]=y1;
e[cnt].x=x1;
e[cnt].y_down=y1;
e[cnt].y_up=y2;
e[cnt].flag=;
y[++cnt]=y2;
e[cnt].x=x2;
e[cnt].y_down=y1;
e[cnt].y_up=y2;
e[cnt].flag=-;
}
sort(y+,y+cnt+);//写成了sort(y,y+cnt+1),1WA
sort(e+,e+cnt+);
build(,,cnt);
double ans=;
for(int i=;i<=cnt;i++){
ans+=insert(,e[i].x,e[i].y_down,e[i].y_up,e[i].flag);
}
printf("Test case #%d\nTotal explored area: %.2f\n\n",++Cas,ans);
}
return ;
}