You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4.6 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

##AcWing 247. 亚特兰蒂斯

一、题目描述

有几个古希腊书籍中包含了对传说中的亚特兰蒂斯岛的描述。

其中一些甚至包括岛屿部分地图。

但不幸的是,这些地图描述了亚特兰蒂斯的不同区域。

您的朋友 Bill 必须知道地图的总面积

你自告奋勇写了一个计算这个总面积的程序。

输入格式 输入包含多组测试用例。

对于每组测试用例,第一行包含整数 n,表示总的地图数量。

接下来 n 行,描绘了每张地图,每行包含四个数字 x_1,y_1,x_2,y_2 不一定是整数(x_1,y_1) 和 (x_2,y_2) 分别是地图的左上角位置和右下角位置。 【注:这个左上和右下是与本题给的坐标系相关,不用过于纠结是左下+右上,还是左上+右下

注意,坐标轴 x 轴从上向下延伸,y 轴从左向右延伸。

当输入用例 n=0 时,表示输入终止,该用例无需处理。

输出格式 每组测试用例输出两行。

第一行输出 Test case #k,其中 k 是测试用例的编号,从 1 开始。

第二行输出 Total explored area: a,其中 a 是总地图面积(即此测试用例中所有矩形的面积并,注意如果一片区域被多个地图包含,则在计算总面积时只计算一次),精确到小数点后两位数。

在每个测试用例后输出一个空行。

数据范围 $1≤n≤10000, \ 0≤x_1<x_2≤100000, \ 0≤y_1<y_2≤100000$

注意,本题 n 的范围上限加强至 10000

输入样例

2
10 10 20 20
15 15 25 25.5
0

输出样例:

Test case #1
Total explored area: 180.00 

样例解释 样例所示地图覆盖区域如下图所示,两个矩形区域所覆盖的总面积,即为样例的解。

二、解题思路

与扫描线专题的模板题基本一致,有两点需要注意:

  • 多组测试数据,记得清空
  • 浮点数不能直接使用线段树,需要离散化(当然,模板也是必须使用离散化的,所以,就当我没说)

三、实现代码

#include <bits/stdc++.h>
using namespace std;

const int N = 100010;

struct ScanLine {
    double y1, y2, x;
    int mark;
    bool operator<(const ScanLine &t) const {
        return x < t.x;
    }
} line[N << 1];

struct Node {
    int l, r;
    int cnt;
    double len;
} tr[N << 2];

double b[N << 2]; // 离散化数组

void pushup(int u) {
    if (tr[u].cnt)
        tr[u].len = b[tr[u].r + 1] - b[tr[u].l];
    else
        tr[u].len = tr[u << 1].len + tr[u << 1 | 1].len;
}

void build(int u, int l, int r) {
    tr[u].l = l, tr[u].r = r;
    if (l == r) return;
    int mid = (l + r) >> 1;
    build(u << 1, l, mid);
    build(u << 1 | 1, mid + 1, r);
}

void modify(int u, int l, int r, int v) {
    if (l <= tr[u].l && r >= tr[u].r) {
        tr[u].cnt += v;
        pushup(u);
        return;
    }
    int mid = (tr[u].l + tr[u].r) >> 1;
    if (l <= mid) modify(u << 1, l, r, v);
    if (r > mid) modify(u << 1 | 1, l, r, v);
    // 更新统计信息
    pushup(u);
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("247.in", "r", stdin);
#endif
    ios::sync_with_stdio(false), cin.tie(0);

    int n, T = 1;
    while (cin >> n, n) {
        // 多组测试数据,记得清空
        memset(tr, 0, sizeof tr);
        memset(b, 0, sizeof b);

        for (int i = 1; i <= n; i++) {
            double x1, y1, x2, y2;
            cin >> x1 >> y1 >> x2 >> y2;
            b[2 * i - 1] = y1;
            b[2 * i] = y2;
            line[2 * i - 1] = {y1, y2, x1, 1};
            line[2 * i] = {y1, y2, x2, -1};
        }
        n *= 2;
        sort(line + 1, line + 1 + n);

        sort(b + 1, b + 1 + n);
        int tot = unique(b + 1, b + 1 + n) - b - 1;

        build(1, 1, tot - 1);

        double res = 0;
        for (int i = 1; i < n; i++) {
            int L = lower_bound(b + 1, b + 1 + tot, line[i].y1) - b;
            int R = lower_bound(b + 1, b + 1 + tot, line[i].y2) - b;
            modify(1, L, R - 1, line[i].mark);
            res += tr[1].len * (line[i + 1].x - line[i].x);
        }
        printf("Test case #%d\n", T++);
        printf("Total explored area: %.2lf\n\n", res);
    }
    return 0;
}