线段树---Atlantis

题目网址:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=110064#problem/A

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

2
10 10 20 20
15 15 25 25.5
0

Sample Output

Test case #1
Total explored area: 180.00 

题意: 给了n个矩形的左下角和右上角的坐标,求矩形面积的并(矩形可能覆盖在一起,求总面积);

思路:使用线段树记录所有矩形上下两条边的高度,用结构体数组记录矩形的左右两条边,并按照从左往右的顺序排序,从左到右加上每一个小矩形的面积。


代码如下:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#define N 210
using namespace std;
double y[N];

struct node
{
    double x,y1,y2;
    int f;
}Line[N];

struct node1
{
    double lf,rf,cnt;
    int l,r,c;
}tree[N*3];

int cmp1(const node a,const node b)
{
    return a.x < b.x;
}

int cmp2(const void *a,const void *b)
{
    return *(double *)a>*(double *)b?1:-1;
}

void bulid(int t,int l,int r)
{
    int mid;
    tree[t].c=0; tree[t].cnt=0;
    tree[t].l=l;
    tree[t].r=r;///记录着所有矩形的两条竖边从左到右的顺序编号;
    tree[t].lf=y[l];
    tree[t].rf=y[r];
    if(l+1==r) return;
    mid=(l+r)/2;
    bulid(2*t,l,mid);
    bulid(2*t+1,mid,r);
}

void calen(int t)
{
    if(tree[t].c>0)
    {
        tree[t].cnt=tree[t].rf-tree[t].lf;
        return ;
    }
    if(tree[t].l+1==tree[t].r) tree[t].cnt=0;///是矩形右面的边则将树节点的值清零;
    else tree[t].cnt=tree[2*t].cnt+tree[2*t+1].cnt;///计算父节点的值;
}

void updata(int t,node e)
{
    if(e.y1 == tree[t].lf && e.y2==tree[t].rf)
    {
        tree[t].c+=e.f;
        calen(t);
        return;
    }
    if(e.y2 <=tree[2*t].rf ) updata(2*t,e);
    else if(e.y1 >=tree[2*t+1].lf) updata(2*t+1,e);
    else
    {
        node tmp=e;
        tmp.y2=tree[2*t].rf;
        updata(2*t,tmp);
        tmp=e;
        tmp.y1=tree[2*t+1].lf;
        updata(2*t+1,tmp);
    }
    calen(t);///计算各个父节点的cnt值;
}

int main()
{
    int Case=0,n,t;
    double x1,y1,x2,y2,ans;
    while(scanf("%d",&n)!=EOF && n)
    {
        Case++;
        t=1;
        for(int 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;

            Line[t+1].x=x2;
            Line[t+1].y1=y1;
            Line[t+1].y2=y2;
            Line[t+1].f=-1;
            y[t+1]=y2;
            t+=2;
        }
        sort(Line+1,Line+t-1,cmp1);///对结构体Line按x值从小到大进行排序;
        qsort(y+1,t-1,sizeof(y[1]),cmp2);///对y[]数组进行从小到大的排序;
        bulid(1,1,t-1);
        ans=0;
        for(int i=1;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",Case,ans);
    }
    return 0;
}

 

posted @ 2016-03-26 22:10  茶飘香~  阅读(157)  评论(0编辑  收藏  举报