Atlantis(扫描线+线段树+离散化)

来源:互联网 发布:概率图模型 知乎 编辑:程序博客网 时间:2024/05/31 19:39

AtlantisCrawling in process...Crawling failedTime Limit:1000MS    Memory Limit:10000KB    64bit IO Format:%I64d & %I64u

SubmitStatus

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 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 
题目大意:给出n组测试数据,每组测试数据上都有两个点左下方(x1,y1),右上方(x2,y2)【两个点能确定一个矩形】,让你求n个矩形的面积(注意有重叠的部分)
思路:此题是按照平行于y轴进行的扫描;多谢学长的悉心教导
#include <stdio.h>#include <string.h>#include <stdlib.h>#include <algorithm>#include <map>#include <string>#include <queue>using namespace std;struct node{    int l,r,c;//l,r分别记录左右节点,c记录覆盖情况;    double lf,rf,cnt;//lf,rf分别记录实际结点,cnt记录当前这一段的长度;}tree[1010];struct line{    double x,y1,y2;//x记录该段的x坐标,y1,y2记录投影的边界;    int f;//记录在y轴上的投影,f=1表示线段的开始,f=-1表示线段的结束;}line[210];int cmp(struct line a,struct line b){    return a.x<b.x;}double y[210];//记录y坐标的数组;void build(int rt,int l,int r)//构造线段树;{    tree[rt].l=l;    tree[rt].r=r;    tree[rt].c=0;    tree[rt].cnt=0;    tree[rt].lf=y[l];//相当于;离散化,把左右节点离散成l,r,并不是赋值,而是代替实际结点的长度;    tree[rt].rf=y[r];    if(r==l+1)        return ;    int mid=(r+l)>>1;    build(rt<<1,l,mid); //注意是mid,不是mid+1,因为要所有段覆盖    build(rt<<1|1,mid,r);}void calen (int rt)//计算长度;{    if(tree[rt].c>0)//如果这段被覆盖,就更新这段的长度为实际长度    {        tree[rt].cnt=tree[rt].rf-tree[rt].lf;        return;    }    else if(tree[rt].l+1==tree[rt].r)//如果这段被撤销,而且是最后的就把长度变为0        {        tree[rt].cnt=0;    }    else    {        tree[rt].cnt=tree[rt<<1].cnt+tree[rt<<1|1].cnt; //如果被撤销但不是最后的,就加一下左右        }}void updata(int rt,struct line e)//加入线段e,后更新线段树{    if(e.y1==tree[rt].lf&&e.y2==tree[rt].rf)    {        tree[rt].c+=e.f;        calen(rt);        return ;    }    if(e.y2<=tree[rt<<1].rf)    {        updata(rt<<1,e);    }    else if(e.y1>=tree[rt<<1|1].lf)    {        updata(rt<<1|1,e);    }    else //跨区间的情况      {        struct line temp=e;        temp.y2=tree[rt<<1].rf;        updata(rt<<1,temp);        temp=e;        temp.y1=tree[rt<<1|1].lf;        updata(rt<<1|1,temp);    }    calen(rt);}int main(){    int n,i,t;    int k=0;    double x1,y1,x2,y2;    while(~scanf("%d",&n))    {        if(n==0)            break;            t=1;        for(i=1;i<=n;i++)        {            scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2);            line[t].x=x1;            line[t].y1=y1;            line[t].y2=y2;            line[t].f=1;            y[t]=y1;            t++;            line[t].x=x2;            line[t].y1=y1;            line[t].y2=y2;            line[t].f=-1;            y[t]=y2;            t++;        }        sort(line+1,line+t,cmp);        sort(y+1,y+t);        build(1,1,t-1);        updata(1,line[1]);        double ans=0;        for(i=2;i<t;i++)        {            ans+=tree[1].cnt*(line[i].x-line[i-1].x);            updata(1,line[i]);        }        printf("Test case #%d\nTotal explored area: %.2lf\n\n",++k,ans);    }    return 0;}

此处另附一个链接http://blog.csdn.net/u013480600/article/details/22548393
这是从平行于x轴,即从下到上扫描的

0 0