1. 程式人生 > 其它 >2021ICPC臺北F What a Colorful Wall (掃描線,並查集)

2021ICPC臺北F What a Colorful Wall (掃描線,並查集)

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;
}