zoukankan      html  css  js  c++  java
  • HDU

    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
    ",Case);
           printf("Total explored area: %.2f
    
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    Linux常用命令3
    清空指定表的所有记录数据。
    向已经创建好的表添加和删除指定的列族或列。
    在终端打印出指定表的所有记录数据。
    列出HBASE所有表的相关信息,如表名、创建时间等。
    我在校园自动签到系统
    charles配置
    计算机网络第7版 PDF+ 计算机网络释疑与习题解答第7版 PDF 计算机网络 课后答案
    在HDFS中将文件从源路径移动到目的路径。
    删除HDFS中指定的文件。
  • 原文地址:https://www.cnblogs.com/a249189046/p/9668272.html
Copyright © 2011-2022 走看看