zoukankan      html  css  js  c++  java
  • HDU 1542 Atlantis

    Atlantis

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 17606    Accepted Submission(s): 7154


    Problem 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 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.
     
    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
     
    1 记录好所有的矩形坐标、按照高度排序
    2.离散化x坐标
    3 接着扫描线从下往上扫描,每遇到一条上下边就停下来,将这条线段投影到总区间上(总区间就是整个多边形横跨的长度),
    这个投影对应的其实是个插入和删除线段操作。还记得给他们赋的值1或-1吗,下边是1,扫描到下边的话相当于往总区间插入一条线段,
    上边-1,扫描到上边相当于在总区间删除一条线段(如果说插入删除比较抽象,那么就直白说,扫描到下边,投影到总区间,
    对应的那一段的值都要增1,扫描到上边对应的那一段的值都要减1,如果总区间某一段的值为0,说明其实没有线段覆盖到它,为正数则有
    每扫描到一条上下边后并投影到总区间后,就判断总区间现在被覆盖的总长度,然后用下一条边的高度减去当前这条边的高度,
    乘上总区间被覆盖的长度,就能得到一块面积,并依此做下去,就能得到最后的面积
     
    代码如下
    #include <map>
    #include <set>
    #include <cmath>
    #include <ctime>
    #include <stack>
    #include <queue>
    #include <cstdio>
    #include <cctype>
    #include <bitset>
    #include <string>
    #include <vector>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <functional>
    #define fuck(x) cout<<"["<<x<<"]";
    #define FIN freopen("input.txt","r",stdin);
    #define FOUT freopen("output.txt","w+",stdout);
    #pragma comment(linker, "/STACK:102400000,102400000")
    #define clr(x) memset(x,0,sizeof(x));
    using namespace std;
    const int  maxn 105+5;
    struct segment//保存矩形的上下边
    {
        double l,r,h;//左右横坐标,纵坐标
        int f;//1为下边界,-1为上边界
        segment() {};
        segment(double x1,double x2,double y,int ic)
        {
            l=x1,r=x2,h=y,f=ic;
        }
        bool operator < (const segment&A)const//按高度从小到大排序
        {
            return h<A.h;
        }
    } p[maxn];
    struct node{
        int le,ri;
        int cnt;//该节点被覆盖的情况
        double len;//该区间被覆盖的总长度
        int mid()
        {
            return (le+ri)>>1;
        }
    } tree[maxn<<2];
    double pos[maxn];
    
    void Build(int rt,int le,int ri){
        tree[rt].le=le;
        tree[rt].ri=ri;
        tree[rt].len=0;
        tree[rt].cnt=0;
        if(le==ri)
            return ;
        int mid=tree[rt].mid();
        Build(rt<<1,le,mid);
        Build(rt<<1|1,mid+1,ri);
    }
    
    void Upfather(int rt){
    
        //计算长度的时候需要把原来的点+1,因为要算这一段的长度
       if(tree[rt].cnt)//非0,已经被整段覆盖
            //计算节点的长度 
            tree[rt].len=pos[tree[rt].ri+1]-pos[tree[rt].le];
        else if(tree[rt].le==tree[rt].ri)//已经不是一条线段
            tree[rt].len=0;
        else//是一条线段但是又没有整段覆盖,那么只能从左右孩子的信息中获取
            tree[rt].len=tree[rt<<1].len+tree[rt<<1|1].len;
    }
    
    void Update(int rt,int val,int left,int right){
        if(left<=tree[rt].le&&tree[rt].ri<=right)
        {
            tree[rt].cnt+=val;//更新这个区间被覆盖的情况
            Upfather(rt);//更新这个区间被覆盖的总长度
            return ;
        }
        int mid=tree[rt].mid();
        if(left<=mid)
            Update(rt<<1,val,left,right);
        if(right>mid)
            Update(rt<<1|1,val,left,right);
        Upfather(rt);//计算该区间被覆盖的总长度
    }
    
    int Search(int le,int ri,double k){
        while(le<=ri)
        {
            int mid=(le+ri)>>1;
            if(pos[mid]==k)
                return mid;
            else if(pos[mid]>k)
                ri=mid-1;
            else
                le=mid+1;
        }
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
        FIN
    #endif
        int n,k=0;
        double x1,x2,y1,y2;
        while(~scanf("%d",&n),n){
            int tot=0;
            for(int i=0; i<n; ++i){
                scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
                pos[tot]=x1;
                p[tot++]=segment(x1,x2,y1,1);//记录下边界的信息
                pos[tot]=x2;
                p[tot++]=segment(x1,x2,y2,-1);//记录上边界的信息
            }
            sort(pos,pos+tot);//横坐标升序排序
            sort(p,p+tot);//按高度排序
            int m=1;
            for(int i=1; i<tot; ++i)//去重
                if(pos[i]!=pos[i-1])
                    pos[m++]=pos[i];
            Build(1,0,m-1);//离散化后的区间就是[0,m-1],以此建树
            double ans=0;
            // cout<<tot<<endl;
            // cout<<m<<endl;
            for(int i=0; i<tot; ++i)//拿出每条横线并且更新
            {
                //线段树记录的是点
                //所以每个点的查询从0开始,后面每个坐标要 -1
                //树上的节点的区间
                int le=Search(0,m-1,p[i].l); //线段左边坐标
                int ri=Search(0,m-1,p[i].r)-1; //线段右边坐标
                //cout<<le<<"------"<<ri<<endl;
                Update(1,p[i].f,le,ri);
                ans+。=tree[1].len*(p[i+1].h-p[i].h);//求面积
            }
            printf("Test case #%d
    Total explored area: %.2f
    ",++k,ans);
            puts("");
        }
        return 0;
    }
    View Code
    每一个不曾刷题的日子 都是对生命的辜负 从弱小到强大,需要一段时间的沉淀,就是现在了 ~buerdepepeqi
  • 相关阅读:
    R语言中gsub使用示例记录
    linux 系统中wget实现并行下载
    R语言中实现将多行数据合并为一行
    python安装包国内镜像加速
    VMware Workstation 与 Device/Credential Guard不兼容
    缩放矩阵, 这里面有关于矩阵的 种种操作 这个要学下 很有用
    ffd 点的控制效果、
    摘抄 : max mel 的一些用法。
    帮朋友写的查找选择的父子骨骼。之前我都是用递归,这个好、
    距离的算法。 下面两个是对等的。
  • 原文地址:https://www.cnblogs.com/buerdepepeqi/p/9374605.html
Copyright © 2011-2022 走看看