문제 출처
1. 문제설명
- $1, 2, …, N$으로 번호가 매겨진 $N$개의 정점이 있다.
- 다음과 같은 쿼리를 수행한 결과를 출력하라
1 u v
: 정점 u
, v
를 잇는 간선 추가
2
: 정점의 개수가 가장 많은 트리의 번호 출력
- 문제 분류
- Data Structure, Set and Map using Tree, Disjoint set
2. 알고리즘 설계
- Union-Find 문제이다.
- 트리가 제거되는 경우는 2가지 이다.
- 사이클이 존재하는 경우
2
연산을 수행한 경우
2
연산의 경우 정렬된 {노드 번호, 연결된 자식의 수}
자료에서 가장 앞의 원소를 꺼내면 되겠다.
- 사이클 처리
Parent[u]
, Parent[v]
의 자료를 지운다.
- 두 개의 값이 같다면 사이클임을 표시한다.
- 이후, 둘 중 하나라도 사이클이 있다면 자료를 지우고 끝이다.
- 둘 다 사이클이 없다면 연결된 자식 수가 많은 노드를 부모 노드로 취하고, 부모 노드의 연결된 자식 수를 갱신한다.
3. 전체 코드
4. 코멘트
- 이 문제 진짜 너무 어려웠다.
- 로직 관련
- 먼저 자료를 지운 후, 이후에 다시 추가한다.
- 처음에는 vector에 사이클이 존재하는 노드를 저장해두었다. 근데, 이렇게 하니까 메모리 초과가 났다…
- set을 이용한 아이디어는 내가 떠올린 게 아니라, 한참동안 방법을 못 찾겠어서 검색을 통해 확인할 수 있었다.
- 개인적으로 union-find를 활용한 끝판왕 문제였다.
x ^ y
- 이 연산자는 피연산자 2개의 값이 서로 다르면 True이다.
- 2중 저장
- 아래의 코드를 보면 저장과 동시에 저장하고 있다.
S.insert({ P[x] = y, Size[y] += Size[x] });
- 평소 나였다면, 아래와 같이 작성했을텐데, 상기 코드가 더 깔끔하고 좋은 거 같다.
P[x] = y, Size[y] += Size[x], S.insert({P[x], Size[y]});