地平線上有許多房子,而這些房子在夕陽的照射之下形成有趣的輪廓,我們稱之為天際線(Skyline)。
為了方便起見,你可以假設所有的房子都是一個位在2D平面上的矩形,並且有一條邊貼在這個假想2D平面上的X軸。
一棟建築可以用三元數組(Li,Hi,Ri)來表示,依序代表該建築物的左界座標、高度、右界座標。下方左圖中的八棟建築就是用此方法表示就是(1,11,5), (2,6,7), (3,13,9), (12,7,16), (14,3,25), (19,18,22), (23,13,29), (24,4,28)。
一個天際線也可以用類似的「X-遞增序列」表示出來,例如上面的八棟建築合併之後上方右圖的天際線可表示為:
(1, 11, 3, 13, 9, 0, 12, 7, 16, 3, 19, 18, 22, 3, 23, 13, 29, 0)
請你寫一個程式,給你這些房子的位置,請你把它們形成的天際線描述出來。
請注意,最後一個數字一定是0。也請不要輸出多餘空白。
$n\le 30000, L_i\le R_i, 1\le L_i,R_i,H_i\le 10^9$
天際線的定義其實就是找出每個x上的房子高度最大值,如果跟前一格不一樣就記錄下來。
可能會發生最大高度變動的只有每個房子的左右界,所以就先記錄下來,將房子按左界排序,然後就能掃描線了。
之後維護一個隨右界遞減的單調對列,不過右界並沒有單調性,所以得用map之類的結構。
先將左邊右界小於當前座標的房子都pop掉,之後加入左界為當前座標的房子。
加入一棟房子時,先檢查它右邊第一個是否比它大,如果比它大那這個房子就用不到,否則就插入,插入後還得將它左邊比它小的都pop掉。
每個點的最大值就會是隊列的首項,一開始先插入[INF, 0],這樣在沒房子時高度會視為0。
時間複雜度:因為左右界最多只會有$2n$個,所以只會迭代$\mathcal{O}(n)$次,配上map的複雜度,總共$\mathcal{O}(nlogn)$。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
|
#include <bits/stdc++.h> using namespace std;
#define EmiliaMyWife ios::sync_with_stdio(0); cin.tie(NULL); #define mem(i,j) memset(i,j,sizeof (i)); using ll = int64_t; using ull = uint64_t; using ld = long double; using uint = uint32_t; const double EPS = 1e-8; const int INF = 0x3F3F3F3F; const ll LINF = 4611686018427387903; const int MOD = 1e9+7;
map<int, int> cur; struct seg { int l, r, y; bool operator<(seg &b) {return l==b.l ? r<b.r : l<b.l;} }; void add(int y, int r) { auto it = cur.lower_bound(r); if(it->second >= y) return; it = cur.upper_bound(r); while(it != cur.begin()) { it--; if(it->second <= y) it = cur.erase(it); else break; } cur[r] = y; }
signed main() { EmiliaMyWife int n; while(cin >> n, n) { cur.clear(); vector<seg> arr(n); vector<int> v; for(int i = 0; i < n; i++) { cin >> arr[i].l >> arr[i].y >> arr[i].r; v.push_back(arr[i].l); v.push_back(arr[i].r); } sort(v.begin(), v.end()); v.erase(unique(v.begin(), v.end()), v.end()); sort(arr.begin(), arr.end()); vector<pair<int, int>> ans; int prv = 0, it = 0; cur[INF] = 0; for(int i : v) { if(cur.count(i)) cur.erase(i); while(it < n && arr[it].l == i) { add(arr[it].y, arr[it].r); it++; } if(cur.begin()->second != prv) ans.push_back({i, prv = cur.begin()->second}); } for(int i = 0; i < ans.size(); i++) cout << ans[i].first << ' ' << ans[i].second << " \n"[i + 1 == ans.size()]; }
return 0; }
|