##[$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 ### 二、解题思路 与扫描线专题的模板题基本一致,有两点需要注意: - 多组测试数据,记得清空 - 浮点数不能直接使用线段树,需要离散化(当然,模板也是必须使用离散化的,所以,就当我没说) ### 三、实现代码 ```cpp {.line-numbers} #include 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; } ```