159 lines
4.6 KiB
Markdown
159 lines
4.6 KiB
Markdown
##[$AcWing$ $247$. 亚特兰蒂斯](https://www.acwing.com/problem/content/249/)
|
||
|
||
### 一、题目描述
|
||
|
||
有几个古希腊书籍中包含了对传说中的亚特兰蒂斯岛的描述。
|
||
|
||
其中一些甚至包括岛屿部分地图。
|
||
|
||
但不幸的是,这些地图描述了亚特兰蒂斯的不同区域。
|
||
|
||
您的朋友 $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$。
|
||
|
||
**输入样例**:
|
||
```cpp {.line-numbers}
|
||
2
|
||
10 10 20 20
|
||
15 15 25 25.5
|
||
0
|
||
```
|
||
**输出样例:**
|
||
```cpp {.line-numbers}
|
||
Test case #1
|
||
Total explored area: 180.00
|
||
```
|
||
|
||
**样例解释**
|
||
样例所示地图覆盖区域如下图所示,两个矩形区域所覆盖的总面积,即为样例的解。
|
||
<center><img src='https://cdn.acwing.com/media/article/image/2019/12/26/19_4acba44c27-%E6%97%A0%E6%A0%87%E9%A2%98.png'></center>
|
||
|
||
### 二、解题思路
|
||
|
||
与扫描线专题的模板题基本一致,有两点需要注意:
|
||
|
||
- 多组测试数据,记得清空
|
||
- 浮点数不能直接使用线段树,需要离散化(当然,模板也是必须使用离散化的,所以,就当我没说)
|
||
|
||
### 三、实现代码
|
||
```cpp {.line-numbers}
|
||
#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;
|
||
}
|
||
|
||
``` |