HDU1542--Atlantis

来源:互联网 发布:佛山市2015年经济数据 编辑:程序博客网 时间:2024/05/16 16:02
Problem Description
There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of parts of the island. But unfortunately, these maps describe different regions of Atlantis. Your friend Bill has to know the total area for which maps exist. You (unwisely) volunteered to write a program that calculates this quantity.

Input
The input file consists of several test cases. Each test case starts with a line containing a single integer n (1<=n<=100) of available maps. The n following lines describe one map each. Each of these lines contains four numbers x1;y1;x2;y2 (0<=x1<x2<=100000;0<=y1<y2<=100000), not necessarily integers. The values (x1; y1) and (x2;y2) are the coordinates of the top-left resp. bottom-right corner of the mapped area.

The input file is terminated by a line containing a single 0. Don’t process it.

Output
For each test case, your program should output one section. The first line of each section must be “Test case #k”, where k is the number of the test case (starting with 1). The second one must be “Total explored area: a”, where a is the total explored area (i.e. the area of the union of all rectangles in this test case), printed exact to two digits to the right of the decimal point.

Output a blank line after each test case.

Sample Input
210 10 20 2015 15 25 25.50

Sample Output
Test case #1Total explored area: 180.00 

 

/*从下往上扫描。先将所有的横坐标排序。然后离散化。然后建立线段树。用Line记录所有的横边。其中结构体中的vis用来标记是上边还是下边。然后扫描上去的时候,根据上边还是下边选择add+还是add-;注意此题的建树方法跟一般线段树不一样int mid=(l+r)>>1;buildtree(2*id,l,mid);buildtree(2*id+1,mid,r);自己想想为什么。*/#include <iostream>#include <cstdio>#include <string>#include <cstring>#include <algorithm>#include <map>using namespace std;map <double,int> collx;map <int,double> coll;#define maxn 108double X[2*maxn];bool vis[2*maxn];int n,tree;struct ST{    int l,r,add;    double len;//len表示这一段的长度和}st[8*maxn];struct Line{    double x1,x2,y;    bool vis;//用来标记这是上边还是下边}line[2*maxn];//用map实现double到int的映射。将端点的横坐标排序后从小到大映射到整数bool cmp(Line a,Line b)//将边按照从小到大排序{    if(a.y<b.y)return 1;    else return 0;}void lisanx(double * x){tree=0;    sort(x+1,x+2*n+1);//从小到大排序    for(int i=1;i<=2*n;i++)    {        if(collx[x[i]]==0){collx[x[i]]=++tree;coll[tree]=x[i];}    }}void buildtree(int id,int l,int r){    st[id].l=l;    st[id].r=r;    if(l==r||l+1==r)    {        st[id].len=0;        st[id].add=0;        return;    }    int mid=(l+r)>>1;    buildtree(2*id,l,mid);    buildtree(2*id+1,mid,r);    st[id].len=0;    st[id].add=0;}//接下来得搞个什么东西呢?每次更新都需要得到横轴上的总长度之和//先写个询问,因为比较好写double query(int id,int l,int r){    if(st[id].add>=1)//这里写st[id].add会WA。想想为什么    {        return coll[st[id].r]-coll[st[id].l];    }    if(l==r||l+1==r)return 0;    if(st[id].add!=0)    {        st[2*id].add+=st[id].add;        st[2*id+1].add+=st[id].add;        st[id].add=0;    }    return query(2*id,l,st[2*id].r)+query(2*id+1,st[2*id+1].l,r);}void update(int id,int l,int r,int ope)//l到r这一段。。。{    if(st[id].l==l&&st[id].r==r)    {        st[id].add+=ope;        st[id].len=query(id,l,r);        return;    }    if(st[id].add!=0)    {st[2*id].add+=st[id].add;        st[2*id+1].add+=st[id].add;        st[id].add=0;    }    if(st[2*id].r>=r)    {        update(2*id,l,r,ope);        st[id].len=st[2*id].len+st[2*id+1].len;        return;    }    if(st[2*id+1].l<=l)    {        update(2*id+1,l,r,ope);        st[id].len=st[2*id].len+st[2*id+1].len;        return;    }    update(2*id,l,st[2*id].r,ope);    update(2*id+1,st[2*id+1].l,r,ope);    st[id].len=st[2*id].len+st[2*id+1].len;}int main(){    int t=0;    while(scanf("%d",&n)!=EOF&&n)    {collx.clear();coll.clear();        t++;        int k=1;//这是边数。对了,我需要两个double数组,一个用来离散X轴,一个用来离散Y轴        int xx=1;memset(vis,0,sizeof(vis));        for(int i=1;i<=n;i++)        {            double x1,y1,x2,y2;            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);            line[k].x1=x1;            line[k].x2=x2;            line[k].y=y2;            line[k++].vis=0;//下边的标记是1            line[k].x1=x1;            line[k].x2=x2;            line[k].y=y1;            line[k++].vis=1;            X[xx++]=x1;            X[xx++]=x2;        }        //X轴的点和Y轴的点都离散好了,接下来就要建树了。        //要根据X轴建树,因为等下我要从下到上进行扫描        lisanx(X);        buildtree(1,1,tree);//这里等下得根据X离散的情况来建树        //对了,我还没有对线进行排序        //好吧,我又错了。就是得map <int,double> .        sort(line+1,line+1+2*n,cmp);for(int i=2;i<=2*n;i++){if(line[i].y!=line[i-1].y){vis[i]=1;}}//vis标记在该高度的第一线段。因为同个高度只可以算一次面积        double lxlen=0,lyhigh=line[1].y;        double ns=0;        for(int i=1;i<=2*n;i++)        {            if(line[i].vis)//如果这是下边,也就是现在ope=1            {                if(vis[i])ns+=lxlen*(line[i].y-lyhigh);//想想为什么要标记                update(1,collx[line[i].x1],collx[line[i].x2],1);lxlen=query(1,1,tree);            }            else            {                if(vis[i])ns+=lxlen*(line[i].y-lyhigh);                update(1,collx[line[i].x1],collx[line[i].x2],-1);lxlen=query(1,1,tree);            }if(vis[i])lyhigh=line[i].y;        }        printf("Test case #%d\n",t);        printf("Total explored area: %.2lf\n\n",ns);    }    return 0;}