문제
- 문제 링크
BOJ 28277 - 뭉쳐야 산다
$N$개의 집합 $S_1, S_2,$ $...$ $S_N$이 주어질 때, 두 종류로 이루어진 $Q$개의 쿼리를 처리하자.
TL : $2$ sec, ML : $1024$ MB
$1 ≤ N, Q ≤ 500,000$ $1 ≤ ΣN_i ≤ 500,000$ $1 ≤ S_{i,j} ≤ 1,000,000,000$
알고리즘 분류
- 자료 구조(data_structures)
- 트리를 사용한 집합과 맵(tree _ set / map)
- 작은 집합에서 큰 집합으로 합치는 테크닉(small_to_large)
풀이
$Small$_$To$_$Large$ 테크닉 그 자체인 문제이다.
최근에 만들어진 문제라 솔브수가 적어서 그렇지, 머지 않아 위 테크닉의 대표 예제로 꼽힐 문제일 듯 싶다.
문제로 돌아가서, 우선 $N$개의 집합을 관리해야 함은 필수적이다.
결국 최적화를 시도해 볼 껀덕지는 집합 간 $Merge$가 일어날 때 뿐이다.
단순히 쿼리 그대로 $Merge$를 진행 한다고 해보자.
최악의 경우 큰 집합을 작은 집합으로 매번 복사해주고 있을 테고,
문제를 총 $O(Q * NlogN)$의 시간 복잡도로 풀게 될 것이다.
이를 조금만 건드려, 방향이 항상 작은 집합에서 큰 집합으로 향하도록 일반화를 시켜보자.
결국 크기 차이가 발생하는 집합 간 이동은 $O(logN)$번을 넘을 수 없으므로, 문제를 총 $O(Q * log^2N)$에 근사하게 풀 수 있게된다.
이제 우리는 위를 바탕으로 쉽게 문제를 해결할 수 있다.
전체 코드
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 | #include<bits/stdc++.h> using namespace std; int main() { ios_base::sync_with_stdio(0); cin.tie(0); int n, q; cin >> n >> q; vector <set<int>> V(n); for (auto& S : V) { int i; cin >> i; for (int j; i--; S.insert(j)) cin >> j; } for (int o, i, j; q--;) { cin >> o; if (o & 1) { cin >> i >> j; if (V[--i].size() < V[--j].size()) swap(V[i], V[j]); for (auto& x : V[j]) V[i].insert(x); V[j].clear(); } else { cin >> i; cout << V[--i].size() << '\n'; } } } | cs |
comment
끝
'Problem Solving > Baekjoon Online Judge (Platinum)' 카테고리의 다른 글
백준 13038 - Tree (C++) (0) | 2023.08.07 |
---|---|
백준 28425 - 점수 계산하기 (C++) (0) | 2023.08.05 |
백준 4787 - Covered Walkway (C++) (0) | 2023.08.04 |
백준 10293 - Ranks in groups (C++) (0) | 2023.07.19 |
백준 28073 - PSAT 특별과정 (C++) (0) | 2023.06.28 |