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;
}

原文地址:https://www.cnblogs.com/a249189046/p/9668272.html

时间: 2024-10-18 09:58:22

HDU - 1542 Atlantis (扫描线+线段树)的相关文章

HDU 1542 Atlantis (线段树求矩阵覆盖面积)

题意:给你n个矩阵求覆盖面积. 思路:看了别人的结题报告 给定一个矩形的左下角坐标和右上角坐标分别为:(x1,y1).(x2,y2),对这样的一个矩形,我们构造两条线段,一条定位在x1,它在y坐标的区间是[y1,y2],并且给定一个cover域值为1:另一条线段定位在x2,区间一样是[y1,y2],给定它一个cover值为-1.根据这样的方法对每个矩形都构造两个线段,最后将所有的线段根据所定位的x从左到右进行排序 #include <iostream> #include <stdio.h

HDU 1542 Atlantis(线段树扫描线+离散化求面积的并)

Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 11551    Accepted Submission(s): 4906 Problem Description There are several ancient Greek texts that contain descriptions of the fabled

HDU 1542 Atlantis(线段树扫描线&#183;面积并)

题意  给你一些矩形的左下和右上的坐标  求这些矩形的面积并 最基础的扫描线  理解了就是个水题了  先看一些图吧                                恩  看完了有什么感觉没有  那些红色的线就可以当作传说中的扫描线  就像从左到右扫描嘛  可以发现  矩形有竖直边的地方就有这些线  这些线把把拼在一起的矩形切成了一个个的小矩形  我们把这些小矩形的面积加起来不就是要求的面积吗 那么现在这些小矩形的面积怎么求呢  长乘宽嘛  长是什么  两条红线之间的距离  恩  我

POJ 1151 Atlantis 扫描线+线段树

点击打开链接 Atlantis Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 17252   Accepted: 6567 Description There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of pa

POJ 1151 HDU 1542 Atlantis(扫描线)

题目大意就是:去一个地方探险,然后给你一些地图描写叙述这个地方,每一个描写叙述是一个矩形的右下角和左上角.地图有些地方是重叠的.所以让你求出被描写叙述的地方的总面积. 扫描线的第一道题,想了又想,啸爷还给我讲了讲,最终有点理解了啊. 先说扫描线:书上说扫描线不是一个物体.而是一个概念. 在计算几何中的作用类似于图论中的bfs与dfs.所以还是须要多做题目来体会一下啊. 这道题目的做法是:离散化x坐标.然后依照y坐标的大小进行排序,每一条保存它的左边界的位置与右边界的位置.以及自身的高度. 还有就

poj1151 Atlantis——扫描线+线段树

题目:http://poj.org/problem?id=1151 经典的扫描线问题: 可以用线段树的每个点代表横向被矩形上下边分割开的每一格,这样将一个矩形的出现或消失化为线段树上的单点修改: 每个格子记录两个值:c(矩形存在情况),sum(对当前答案作出贡献的长度): 将y离散化作为建树的依据: 一开始没想到线段树上的点应该是横向的格子,写了个乱七八糟: #include<iostream> #include<cstdio> #include<cstring> #i

HDU 1542 Atlantis 线段树+离散化+扫描线

题意:给出一些矩形的最上角坐标和右下角坐标,求这些矩形的面积并. NotOnlySuccess 线段树专辑中扫描线模板题,弱智的我对着大大的代码看了一下午才搞懂. 具体见思路见注释=.= #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #define lson rt<<1,l,mid #define rson rt<<1|1,mid

HDU 1542 Atlantis(线段树扫描线)

http://acm.hdu.edu.cn/showproblem.php?pid=1542 Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6788    Accepted Submission(s): 2970 Problem Description There are several ancient Greek

hdu 1542 Atlantis(线段树&amp;扫描线&amp;面积并)

Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6386    Accepted Submission(s): 2814 Problem Description There are several ancient Greek texts that contain descriptions of the fabled i

线段树+扫描线+离散化解poj1151 hdu 1542 ( Atlantis )

受此链接很大启发才明白扫描线: http://www.cnblogs.com/scau20110726/archive/2013/04/12/3016765.html 我的代码如下: #include<iostream> #include<map> #include<string> #include<cstring> #include<cstdio> #include<cstdlib> #include<cmath> #i