• Hdu1542 Atlantis


    Atlantis

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


    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
     
    Source
     
    Recommend
    linle
    题目大意:求矩形并的面积.
    分析:比较固定的解法:线段树+扫描线.矩形的面积公式是底乘高,每次把相同y坐标的底的长度给加起来,同时向上跳,直到遇到另外一条线位置,那么底的和*高就是扩展得到的面积,这样不断地扩展就能得到答案.具体算法可以参看:传送门
              直接套线段树会有一个问题,[x,x]在这道题中表示的是一个点,是不合法的,而线段树中确是有意义的,如果处理到[x,x+1]继续分治成[x,x],[x+1,x+1]就会出现问题,正确的做法是每次将右端点往左移一位,特判如果此时的l=r,那么就是之前的[x,x+1]这种情况,直接判掉,否则就可以像线段树那样正常地递归下去.
              这道题因为坐标比较大,需要离散化一下,因为高度是需要计算的,所以只需要离散横坐标就可以了.那么线段树记录的就是下标,每次修改一个值都必须要二分查找这个值对应的下标是哪一位.
              比较坑的一个点是数据可能会有0,我在处理的时候没考虑到这种情况,一直爆栈,主要还是离散化的部分鲁棒性不强.
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 210;
    
    struct node
    {
        double l, r, h;
        int id;
    }e[maxn];
    
    double X[maxn], c[maxn << 2], XX[maxn], ans;
    int cnt, n, tot, tag[maxn << 2], cas = 1;
    
    bool cmp(node a, node b)
    {
        return a.h < b.h;
    }
    
    int find(double x)
    {
        
        int l = 1, r = cnt, res = cnt - 1;
        while (l <= r)
        {
            int mid = (l + r) >> 1;
            if (X[mid] >= x)
            {
                res = mid;
                r = mid - 1;
            }
            else
                l = mid + 1;
        }
        return res;
    }
    
    void pushup(int o, int l, int r)
    {
        if (tag[o])
            c[o] = X[r + 1] - X[l];
        else
            if (l == r) //没有被完全覆盖就是两个点
                c[o] = 0;
            else
                c[o] = c[o * 2] + c[o * 2 + 1];
    }
    
    void update(int o, int l, int r, int x, int y, int v)
    {
        if (x <= l && r <= y)
        {
            tag[o] += v;
            pushup(o, l, r);
            return;
        }
        int mid = (l + r) >> 1;
        if (x <= mid)
            update(o * 2, l, mid, x, y, v);
        if (y > mid)
            update(o * 2 + 1, mid + 1, r, x, y, v);
        pushup(o, l, r);
    }
    
    int main()
    {
        while (~scanf("%d", &n) , n)
        {
            memset(c, 0, sizeof(c));
            memset(tag, 0, sizeof(tag));
            ans = 0.0;
            tot = cnt = 0;
            for (int i = 1; i <= n; i++)
            {
                double a, b, c, d;
                scanf("%lf%lf%lf%lf", &a, &b, &c, &d);
                e[++tot].l = a;
                e[tot].r = c;
                e[tot].h = b;
                e[tot].id = 1;
                X[tot] = a;
                e[++tot].l = a;
                e[tot].r = c;
                e[tot].h = d;
                e[tot].id = -1;
                X[tot] = c;
            }
            sort(X + 1, X + tot + 1);
            sort(e + 1, e + 1 + tot, cmp);
            XX[1] = X[1];
            cnt = 1;
            for (int i = 2; i <= tot; i++)
                if (X[i] != X[i - 1])
                    XX[++cnt] = X[i];
            memcpy(X, XX, sizeof(XX));
            for (int i = 1; i < tot; i++)
            {
                int l = find(e[i].l), r = find(e[i].r) - 1;
                update(1, 1, cnt, l, r, e[i].id);
                ans += c[1] * (e[i + 1].h - e[i].h);
            }
            printf("Test case #%d
    Total explored area: %.2lf
    
    ", cas++, ans);
        }
    
        return 0;
    }
  • 相关阅读:
    设置MYSQL允许用IP访问
    EasyUI中那些不容易被发现的坑——EasyUI重复请求2次的问题
    Oracle初级性能优化总结
    Asp.Net MVC3.0网站统计登录认证的在线人数
    App.config和Web.config配置文件的配置节点的解析
    App.config和Web.config配置文件的自定义配置节点
    Asp.Net Web API 2第十八课——Working with Entity Relations in OData
    win7凭据管理、win7多用户远程登录、主机头设置、nuget.org无法访问
    Asp.Net Web API 2第十七课——Creating an OData Endpoint in ASP.NET Web API 2(OData终结点)
    C#基础知识系列八(const和readonly关键字)
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8006704.html
Copyright © 2020-2023  润新知