백준 17469번, 트리의 색깔과 쿼리 풀이
2020. 10. 6. 00:20ㆍProblem Solving/백준
문제
풀이
Union-Find 자료구조를 사용하여 트리를 관리해줍니다.
UF 자료구조 특성상 간선을 제거하는데 상당히 느립니다.
입력을 다 받고 이를 거꾸로 봐주면서 쿼리를 처리하면, 간선을 제거하는 것이 아니라 합치는 연산으로 볼 수 있습니다.
이를 합쳐주면서 "색깔"이라는 요소를 같이 관리해야 합니다.
색깔의 개수를 출력할 때는 중복되는 요소가 없어야 하니 set을 사용하면 될 것 같습니다.
여기서 백준 13306번 트리와는 다른 테크닉이 하나 더 필요합니다.
small to large입니다.
Union by rank와 유사하게 간선을 합치는 연산을 처리할 때, set 역시 합치는 연산을 할 것 입니다.
이 set을 작은 것에서 큰쪽으로 옮겨주면 모든 원소가 최대 $ log N $만큼 이동합니다.

역순으로 구성된 매 질의에 대해 답한 것을 다시 역순으로 출력해주면 정답입니다.
소스코드
#include <bits/stdc++.h>
using namespace std;
vector<int> UF(100001), parent(100001);
vector<set<int>> color(100001);
int find(int a) {
return a == UF[a] ? a : UF[a] = find(UF[a]);
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int n, q;
cin >> n >> q;
for (int i = 1; i < 100001; i++) UF[i] = i;
for (int i = 2; i <= n; i++) cin >> parent[i];
for (int i = 1; i <= n; i++) {
int a; cin >> a;
color[i].insert(a);
}
stack<pair<int, int>> query;
for (int i = 1; i < q + n; i++) {
int a, b; cin >> a >> b;
query.push({a, b});
}
stack<string> ans;
while(!query.empty() && q) {
auto a = query.top(); query.pop();
if (a.first == 1 && q--) { //merge
int k = find(parent[a.second]);
if (color[a.second].size() > color[k].size()) color[a.second].swap(color[k]);
for (int b : color[a.second]) color[k].insert(b);
UF[a.second] = find(parent[a.second]);
} else ans.push(to_string(color[find(a.second)].size()));
}
string res;
while (!ans.empty()) {
res += ans.top() + "\n"; ans.pop();
}
cout << res;
}
'Problem Solving > 백준' 카테고리의 다른 글
백준 2406번, 안정적인 네트워크 풀이 (0) | 2020.10.07 |
---|---|
백준 12024번, 사각형 찾기 풀이 (0) | 2020.10.06 |
백준 2881번, 산책길 풀이 (0) | 2020.10.05 |
백준 1396번 (병렬 이분 탐색/PBS), 크루스칼의 공 (0) | 2020.10.03 |
백준 6549번, 히스토그램에서 가장 큰 직사각형 (2) | 2020.10.02 |