题解 POJ1151【Atlantis】

题目大意

给你n个矩形,让你求所有矩形覆盖的总面积,重叠的地方只算一次

输入格式

输入的第一行包含一个整数n,表示可得到的地图数目。

以下n行,每行描述一张地图。每行包含4个整数x1,y1,x2和y2(0≤x1<x2≤30000,0≤y1<y2≤30000)。数值(x1,y1)和(x2,y2)是坐标,分别表示绘制区域的左下角和右上角坐标。每张地图是矩形的,并且它的边是平行于x坐标轴或y坐标轴的。

数据可能有多组,当n为零时停止输入

输出格式

对于每个测试数据,你的程序应该输出一个答案。每个答案的第一行必须是“Test case #k”,其中k是测试数据的编号(从1开始)。第二个必须是“Total explored area: a”,其中a是总探索面积(即在本测试案例中所有矩形的并集面积),精确到小数点右边两位。
在每个测试用例后输出一个空行。

样例输入

2
10 10 20 20
15 15 25 25.5
0

样例输出

 Test case #1
 Total explored area: 180.00 
 

数据范围

 n <= 100

主要思路:线段树 + 扫描线

这是一道扫描线裸题。

我们把要覆盖的矩形抽象成两个线,这两条线就被称为扫描线。如图(网上扒拉来的图QwQ,若有侵权请联系博主删除QwQ)

对于扫描线,我们可以把扫描线的高度进行离散化。然后我们把x轴上的线(图中的黑线)分隔开的就可以抽象成几段线段。

扫描二维码关注公众号,回复: 4336676 查看本文章

我们只需要把这些交点用线段树维护就好。然后我们把所有扫描线从最小到最大排序一下。我们首先记录一条扫描线的左端点与右端点,它的高度,它是下底边还是上界边,如果是下底边就记为1,上界边记为-1。(这里实际是做了个差分,就是维护两条扫描线穿过(或切于边界的)矩形有多少。

线段树中维护的是这段区间的下底边个数和下底边总长度。我们扫描的作是每次更新下底边总长度和下底边个数增加新面积。我们只要从最下向上扫描一遍统计总面积就好了。

code:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <vector>
using namespace std;
#define go(i, j, n, k) for(int i = j; i <= n; i += k)
#define fo(i, j, n, k) for(int i = j; i >= n; i -= k)
#define inf 1 << 30
#define mn 100010
#define ll long long
inline int read() {
    int x = 0, f = 1; char ch = getchar();
    while(ch > '9' || ch < '0') { if(ch == '-') f = -f; ch = getchar(); }
    while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}
struct tree{
    int mark; double sum;
} z[mn << 2];
struct seg{
    double l, r, h;
    int d;
    seg() {}
    seg(double _l, double _r, double _h, int _d) : l(_l), r(_r), h(_h), d(_d) {}
    bool operator < (const seg &b) const { return h < b.h; }
} s[mn];
int n, num, kkk;
double ha[mn];
double x, y, xx, yy;
#define root 0, m - 1, 1
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define bson l, r, rt
inline void update(int l, int r, int rt) {
    if(z[rt].mark) z[rt].sum = ha[r + 1] - ha[l];
    else if(l == r) z[rt].sum = 0;
    else z[rt].sum = z[rt << 1].sum + z[rt << 1 | 1].sum;
}
inline void modify(int l, int r, int rt, int nowl, int nowr, int d) {
    if(nowl <= l && r <= nowr) {
        z[rt].mark += d;
        update(bson);
        return;
    }
    int m = (l + r) >> 1;
    if(nowl <= m) modify(lson, nowl, nowr, d);
    if(m < nowr)  modify(rson, nowl, nowr, d);
    update(bson);
} 
inline int search(double key, double* x, int n) {
    int l = 0, r = n - 1;
    while(l <= r) {
        int m = (l + r) >> 1;
        if(x[m] == key) return m;
        if(x[m] > key) r = m - 1;
        else l = m + 1; 
    }
    return -1;
}
int main() {
    while(cin >> n, n) {
        num = 0;
        go(i, 0, n - 1, 1) {
            cin >> x >> y >> xx >> yy;
            ha[num] = x;
            s[num++] = seg(x, xx, y, 1);
            ha[num] = xx;
            s[num++] = seg(x, xx, yy, -1);
        }
        sort(ha, ha + num);
        sort(s, s + num);
        int m = 1;
        go(i, 1, num - 1, 1) 
            if(ha[i] != ha[i - 1]) ha[m++] = ha[i];
        double ans = 0;
        go(i, 0, num - 1, 1) {
            int L = search(s[i].l, ha, m);
            int R = search(s[i].r, ha, m) - 1;
            modify(root, L, R, s[i].d);
            ans += z[1].sum * (s[i + 1].h - s[i].h);
        }
        printf("Test case #%d\nTotal explored area: %.2lf\n", ++kkk, ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/yizimi/p/10056346.html