題解 POJ1151【Atlantis】
阿新 • • 發佈:2018-12-03
題目大意
給你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軸上的線(圖中的黑線)分隔開的就可以抽象成幾段線段。
我們只需要把這些交點用線段樹維護就好。然後我們把所有掃描線從最小到最大排序一下。我們首先記錄一條掃描線的左端點與右端點,它的高度,它是下底邊還是上界邊,如果是下底邊就記為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; }