HDU 1255 覆盖的面积

来源:互联网 发布:淘宝怎么快速上传宝贝 编辑:程序博客网 时间:2024/04/28 22:43

先将y轴坐标离散化,建树,再将线段横坐标按从小到大排序,从左到右插入,对于同一个矩形的两条对y轴平行的线段,左边的线段标记为-1,右边的线段标记为1,插入时判断y轴上这一段被覆盖的次数,成段更新这部分每太想明白,所以都直接更新到了根子叶,耗时比较长。

Problem Description
给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积.


 

Input
输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据的第一行是一个正整数N(1<=N<=1000),代表矩形的数量,然后是N行数据,每一行包含四个浮点数,代表平面上的一个矩形的左上角坐标和右下角坐标,矩形的上下边和X轴平行,左右边和Y轴平行.坐标的范围从0到100000.

注意:本题的输入数据较多,推荐使用scanf读入数据.
</pre><pre name="code" class="cpp">
</pre><pre name="code" class="cpp">#include<stdio.h>#include<string.h>#include<stdlib.h>int cmp1(const void *a,const void *b);int cmp(const void *a,const void *b);struct node{int high,low;double x;int cover; //cover值存储被覆盖的面积}stu[10000];struct kode    <span style="font-family: 'Times New Roman';">//存储线段信息</span>{double x;int y1,y2;int flag;    <span style="font-family: 'Times New Roman';">//flag代表是左端还是右端</span>}line[10000];    struct mode      //存储顶点信息,用于离散化中对纵坐标排序及建立映射{ double x,y;int flag;   int up;}star[20000];double ff[2100];   //存储映射double ans;void build(int low,int high,int x){stu[x].high=high;stu[x].low=low;stu[x].cover=0;stu[x].x=0;if(high==(low+1))return ;int mid=(high+low)/2;build(low,mid,2*x);    build(mid,high,x*2+1);   //对于求两点之间距离这种情况,建树时右儿子左端点不是mid+1,而是mid}void insert(int low,int high,double x,int flag,int n){if((stu[n].low+1)==stu[n].high){if(stu[n].cover>1)ans+=(ff[stu[n].high]-ff[stu[n].low])*(x-stu[n].x);stu[n].cover+=flag;stu[n].x=x;return ;}if((stu[n].high==high)&&(stu[n].low==low))    //插入时更新到根子叶{insert(stu[n*2].low,stu[n*2].high,x,flag,n*2);insert(stu[n*2+1].low,stu[2*n+1].high,x,flag,n*2+1);return ;}if(low>=stu[2*n+1].low){insert(low,high,x,flag,n*2+1);}else if(high<=stu[2*n].high){insert(low,high,x,flag,n*2);}else{insert(low,stu[n*2].high,x,flag,n*2);insert(stu[n*2+1].low,high,x,flag,n*2+1);}}int main(){int n,m,i,j,k,max,snum,f=1,t;double temp,x1,x2,y1,y2;scanf("%d",&t);while(t--){scanf("%d",&n);snum=0;for(i=0;i<n*2;i=i+2){ scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);    //建立映射,分别存储每个矩形的四个顶点star[snum].x=x1;star[snum].y=y1;star[snum].up=-(i+1);     //存储是第(i+1)条线段的上端点还是下端点,不能从0开始star[snum].flag=1;snum++;star[snum].x=x1;star[snum].y=y2;star[snum].up=i+1;star[snum].flag=1;snum++;star[snum].x=x2;star[snum].y=y1;star[snum].up=-(i+2);star[snum].flag=-1;snum++;star[snum].x=x2;star[snum].y=y2;star[snum].up=2+i;star[snum].flag=-1;snum++;}qsort(star,snum,sizeof(star[0]),cmp);max=1;ff[1]=star[0].y;temp=star[0].y;for(i=0;i<snum;i++){if(star[i].y!=temp){max++;    //根据y坐标数据,去重,建立映射ff[max]=star[i].y;temp=ff[max];}if(star[i].up>0){line[star[i].up-1].y2=max;   //利用顶点中存储的信息,将点还原成线段line[star[i].up-1].x=star[i].x;line[star[i].up-1].flag=star[i].flag;}else{line[-star[i].up-1].y1=max;line[-star[i].up-1].x=star[i].x;line[-star[i].up-1].flag=star[i].flag;}}build(1,max,1);qsort(line,2*n,sizeof(line[0]),cmp1);   //按x左边将线段排序,依次插入ans=0;for(i=0;i<n*2;i++)insert(line[i].y1,line[i].y2,line[i].x,line[i].flag,1);printf("%.2f\n",ans);}return 0;}int cmp(const void *a,const void *b){mode *aa=(mode *)a;mode *bb=(mode *)b;return ((aa->y)>(bb->y)?1:-1);}int cmp1(const void *a,const void *b){kode *aa=(kode *)a;kode *bb=(kode *)b;return ((aa->x)>(bb->x)?1:-1);}


0 0