HDU - 1542 Atlantis (扫描线+线段树)

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.

InputThe 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.OutputFor 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个矩形,和它们的左下角和右上角的坐标,求所有矩形的覆盖面积

分析:扫描线的经典题,用线段树维护当前状态覆盖的横坐标的区间总和,这样到下一条扫描线为止的高度和它的乘积,一定是被覆盖的面积。
由于题目的坐标是浮点数,所以首先需要进行离散化处理,对应到整型数上
然后用[l,r]代表l到r+1的区间,因为要让线段树的每个节点都覆盖一个区间,所以[l,l]代表[l,l+1]的区间
线段树节点还需要维护区间的flag值,将矩形的横向边,分为入边和出边,当遇到入边时,flag++,遇到出边时flag--,当flag>0时,就代表当前节点的区间被覆盖
这样树的根节点的权值,就代表总的被覆盖区间的和,再乘以扫描线高度的差,即为当前状态下被覆盖的面积,进行累加即可

关于扫描线,这篇博客讲的很详细:https://blog.csdn.net/u013480600/article/details/22548393

代码如下:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
const int MAXN=1010;
typedef long long ll;
vector<double>V;
int get_id(double x) //将浮点数进行离散化处理
{
  return lower_bound(V.begin(),V.end(),x)-V.begin();
}

struct node2
{
    double l,r;
    double h;
    int flag;
}line[MAXN];
double sum[MAXN<<2];//储存该节点区间的被覆盖的长度
double tot[MAXN<<2];//储存该节点区间的总的长度
struct node
{
    int l;
    int r;
    int f;
}tree[MAXN<<2];
void PushUp(int rt)
{
  sum[rt]=sum[rt<<1]+sum[rt<<1|1];
  tot[rt]=tot[rt<<1]+tot[rt<<1|1];
}

void BuildTree(int l,int r,int rt)
{
    tree[rt].l=l;
    tree[rt].r=r;
    tree[rt].f=0;
    if(l==r)
    {
      tot[rt]=V[l+1]-V[l];
      sum[rt]=0;
      return;
    }
    int mid=(tree[rt].l+tree[rt].r)/2;
    BuildTree(l,mid,rt<<1);
    BuildTree(mid+1,r,rt<<1|1);
    PushUp(rt);
}
void Update(int c,int l,int r,int rt)
{
    if(tree[rt].l==l&&tree[rt].r==r)
    {
        tree[rt].f+=c;
       // cout<<V[l]<<" "<<V[r+1]<<" "<<tree[rt].f<<endl;
        if(tree[rt].f>0)
          sum[rt]=tot[rt];
        else
          sum[rt]=0;
    }
    if(tree[rt].l==tree[rt].r)
    return;
    int mid=(tree[rt].l+tree[rt].r)/2;

    if(r<=mid) Update(c,l,r,rt<<1);
    else if(l>mid)Update(c,l,r,rt<<1|1);
    else
    {
        Update(c,l,mid,rt<<1);
        Update(c,mid+1,r,rt<<1|1);
    }
    PushUp(rt);
}

bool cmp(node2 a,node2 b)
{
   if(a.h!=b.h)
   return a.h<b.h;
   else if(a.l!=b.l)
   return a.l<b.l;
   return a.r<b.r;
}
int n,cnt,Case=0;;
double x1,x2,y1,y2,ans;
int main()
{
    while(scanf("%d",&n)&&n)
    {
        Case++;
        ans=0;
        cnt=0;
        V.clear();
        V.push_back(-1);
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            ++cnt;
            line[cnt].l=x1,line[cnt].r=x2,line[cnt].h=y1,line[cnt].flag=1;//分出所有入边
            ++cnt;
            line[cnt].l=x1,line[cnt].r=x2,line[cnt].h=y2,line[cnt].flag=-1;//分出所有出边
            V.push_back(x1);
            V.push_back(x2);
        }
       sort(V.begin(),V.end());
       V.erase(unique(V.begin(),V.end()),V.end());
       sort(line+1,line+cnt+1,cmp);//将边按纵坐标进行排列
       int len=V.size()-1;
       BuildTree(1,len,1);

    //  cout<<cnt<<endl;
       for(int i=1;i<=cnt;i++)
       {
            if(i>1)
           ans+=sum[1]*(line[i].h-line[i-1].h);
           Update(line[i].flag,get_id(line[i].l),get_id(line[i].r)-1,1);
        //   cout<<sum[1]<<" "<<ans<<endl;
       }
       printf("Test case #%d\n",Case);
       printf("Total explored area: %.2f\n\n",ans);
    }
    return 0;
}

 

posted @ 2018-09-18 12:39  hinata_hajime  阅读(103)  评论(0编辑  收藏  举报