2021ICPC臺北F What a Colorful Wall (掃描線,並查集)
阿新 • • 發佈:2022-05-08
https://codeforces.com/gym/103443/problem/F
掃描線核心思想就是從下到上暴力跑一維,把另一維的線段化為兩個點處理,若處理兩個點的線段的時間複雜度是log,這樣平面上n個矩形,值域為X,Y的問題,能夠在nXlogn(Y)的複雜度內處理
- 離散化
- 暴力一個一個點的塗色是n^3
- 考慮用掃描線從下往上掃,那麼問題就是怎麼處理平行x的線段。
- 因為是顏色覆蓋問題,我們倒著處理,那麼一段線段[l, r]塗過色後,這段顏色不能再邊,掃到這一段時候就要從l直接跳到r。可以想到並查集來實現。
- 時間複雜度約為 nXlog(Y), (並查集比logn還快一些)
#include<bits/stdc++.h> using namespace std; #define IOS ios::sync_with_stdio(false) ,cin.tie(0), cout.tie(0); //#pragma GCC optimize(3,"Ofast","inline") #define ll long long //#define int long long const int N = 1e4 + 5; const int M = 1e5 + 5; const int INF = 0x3f3f3f3f; const ll LNF = 0x3f3f3f3f3f3f3f3f; const int mod = 1e9 + 7; const double PI = acos(-1.0); struct node{ int x1, y1, x2, y2, c; } rta[N]; int lisan( vector<int> v, int x ) { return lower_bound(v.begin(), v.end(), x) - v.begin(); } int p[N]; int find ( int x ) { return x == p[x] ? x : p[x] = find(p[x]); } void merge( int a, int b ) { a = find(a), b = find(b), p[a] = b; } int main () { IOS int n; cin >> n; vector<int> X, Y; //離散化 for ( int i = 1; i <= n; ++ i ) { int x1, y1, x2, y2, c; cin >> x1 >> y1 >> x2 >> y2 >> c; rta[i] = { x1, y2, x2, y1, c }; X.push_back(x1), X.push_back(x2), Y.push_back(y1), Y.push_back(y2); } sort(X.begin(), X.end()); X.erase( unique(X.begin(), X.end()), X.end()); sort(Y.begin(), Y.end()); Y.erase ( unique ( Y.begin(), Y.end()), Y.end()); for ( int i = 1; i <= n; ++ i ) { int x1 = lisan(X, rta[i].x1); int x2 = lisan(X, rta[i].x2); int y1 = lisan(Y, rta[i].y1); int y2 = lisan(Y, rta[i].y2); int c = rta[i].c; rta[i] = { x1, y1, x2, y2, c}; } //離散化後的值域 int lx = X.size(), ly = Y.size(); vector<bool> st(n + 1); for ( int i = 0; i < ly; ++ i ) { for ( int j = 0; j < lx ; ++ j) p[j] = j; // 並查集初始化要大一 for ( int j = n; j >= 1; -- j ) { int x1 = rta[j].x1, x2 = rta[j].x2, y1 = rta[j].y1, y2 = rta[j].y2, c = rta[j].c; if( i >= y1 && i < y2) { // 注意根據題目,得出這裡比較帶不帶等號 for ( int k = find(x1); k < x2; k = find(k) ) { //跳過已經塗色的 merge( k, k + 1 ); st[c] = 1; } } } } cout << count( st.begin(), st.end(), 1 ) << '\n'; return 0; }