정점이 하나씩 영구적으로 삭제되는 과정마다, 남아있는 정점이 1개 이상 존재하고 그래프가 **연결(모든 정점 쌍이 도달 가능)**인지 빠르게 판별해야 한다.
삭제는 DSU로 직접 처리하기 까다로우므로, 삭제 순서를 역순으로 뒤집어 “추가” 문제로 바꾸는 오프라인 풀이가 핵심이다.
문제 정보
문제 링크: https://www.acmicpc.net/problem/25172
문제 요약:
- \(N\)개의 관광지(정점)와 \(M\)개의 길(무방향 간선)로 이루어진 그래프가 주어진다.
- 이후 정점이 \(N\)번에 걸쳐 하나씩 삭제되며, 삭제되는 정점과 연결된 모든 간선도 함께 사라진다(영구 삭제).
- 각 시점(처음 포함)마다, 남은 정점이 비어있지 않고 그래프가 연결이면
CONNECT, 아니면DISCONNECT를 출력한다.
제한 조건:
- 시간 제한: 2초
- 메모리 제한: 512MB
- \(1 \le N \le 200,000\)
- \(1 \le M \le 200,000\)
입출력 예제
입력 1:
| |
출력 1:
| |
접근 방식
핵심 관찰 1: “삭제”를 “추가”로 바꾸면 DSU로 처리 가능
정점 삭제는 DSU가 지원하지 않지만, 삭제 순서를 역순으로 보면 정점이 하나씩 추가되는 과정이 된다.
- 원래 문제: \(v_1, v_2, \ldots, v_N\) 순서로 정점 삭제
- 역순 문제: \(v_N, v_{N-1}, \ldots, v_1\) 순서로 정점 추가
- 정점 \(v\)를 추가할 때, 이미 활성화(active)된 이웃과만 간선을 “복원”해 DSU로 합친다.
핵심 관찰 2: 연결 여부는 “활성 컴포넌트 수”로 판정
각 시점에서
- 활성 정점 수가 0이면 무조건
DISCONNECT - 활성 정점 수가 1 이상이고, 활성 컴포넌트 수가 정확히 1이면
CONNECT
정점 \(v\)를 새로 활성화하면 컴포넌트가 1 증가하고, 활성 이웃과 DSU로 합칠 때마다(서로 다른 컴포넌트였다면) 컴포넌트 수가 1 감소한다.
알고리즘 설계 (Mermaid Flowchart)
flowchart TD
A["입력: N, M, 간선 목록, 삭제 순서 v[1..N]"] --> B["활성 배열 active 초기화 (모두 false)"]
B --> C["DSU 초기화, activeCnt=0, comps=0"]
C --> D["i = N..1 (역순)"]
D --> E["v = v[i] 를 활성화"]
E --> F["activeCnt += 1, comps += 1"]
F --> G["v의 모든 이웃 u에 대해, active[u]면 DSU.union(v,u)"]
G --> H["union 성공 시 comps -= 1"]
H --> I{"activeCnt > 0 && comps == 1 ?"}
I -- "yes" --> J["ok[t] = CONNECT 저장"]
I -- "no" --> K["ok[t] = DISCONNECT 저장"]
J --> L["다음 i"]
K --> L
L --> M["정방향 출력: k번 삭제 상태 = 역순에서 (N-k)개 추가 상태"]
단계별 로직
- 입력 파싱: 인접 리스트로 그래프 저장, 삭제 순서 배열 저장
- 역순 처리:
- 정점을 하나 활성화하고(
activeCnt++,comps++) - 활성 이웃과 DSU union하여 컴포넌트 수 감소
activeCnt>0 && comps==1이면 그 시점은 연결
- 정점을 하나 활성화하고(
- 정방향 매핑:
- 정방향에서 \(k\)개 삭제한 상태 ↔ 역순에서 \(N-k\)개 추가한 상태
- \(k=0..N\)에 대해 정답 출력(총 \(N+1\)줄)
복잡도 분석
| 항목 | 복잡도 | 비고 |
|---|---|---|
| 시간 복잡도 | \(O((N+M)\alpha(N))\) | 각 간선은 양 끝이 활성화될 때 최대 1번 union 시도 |
| 공간 복잡도 | \(O(N+M)\) | 인접 리스트 + DSU + 활성 배열 |
코너 케이스 및 실수 포인트
| 케이스 | 설명 | 처리 방법 |
|---|---|---|
| 모든 정점 삭제 후 | 정점이 0개면 연결 개념 성립 불가 | activeCnt==0이면 무조건 DISCONNECT |
| 처음부터 비연결 | 초기 그래프가 이미 여러 컴포넌트 | 역순 처리 후 ok[N]가 false가 될 수 있음 |
| 간선이 없는 그래프 | \(M=0\) | 정점 1개일 때만 CONNECT, 그 외 DISCONNECT |
| 중복 union | 같은 컴포넌트끼리 합치기 시도 | union 성공 여부로 comps 감소 여부 결정 |
| 출력 줄 수 | 처음 상태 + N번 삭제 결과 | 총 \(N+1\)줄 출력 |
구현 코드 (C++)
| |
![Featured image of post [Algorithm] C++ 백준 25172번: 꼼꼼한 쿠기의 졸업여행](/post/algorithm/2026-01-24-boj-25172-graduation-trip-dynamic-connectivity-dsu-offline-cpp-solution/wordcloud_hu_35360f0de3ce2f61.png)
![[Algorithm] C++ 백준 14288번: 회사 문화 4](/post/algorithm/2026-01-24-boj-14288-company-culture-4-tree-queries-fenwick-cpp-solution/wordcloud_hu_71f27d76781ea5f9.png)
![[Algorithm] C++ 백준 24271번: xor²](/post/algorithm/2026-01-24-boj-24271-xor-squared-xor-permutation-segment-tree-cpp-solution/wordcloud_hu_26a096bd3c9cd391.png)
![[Algorithm] C++ 백준 25172번: 꼼꼼한 쿠기의 졸업여행](/post/algorithm/2026-01-24-boj-25172-graduation-trip-dynamic-connectivity-dsu-offline-cpp-solution/wordcloud_hu_e9b1b16e9501050b.png)
![[Algorithm] C++ 백준 18874번: Haircut](/post/algorithm/2026-01-05-boj-18874-haircut-fenwick-tree-inversion-cpp-solution/wordcloud_hu_ff0c2f02e81b4f7e.png)
![[Algorithm] C++ 백준 9120번: Oulipo 다국어](/post/algorithm/2026-01-05-boj-9120-oulipo-multilingual-kmp-string-matching-cpp-solution/wordcloud_hu_801cf29e8e8a768d.png)
![[Algorithm] C++ 백준 12012번: Closing the Farm (Gold)](/post/algorithm/2025-12-23-boj-12012-closing-the-farm-dsu-offline-cpp-solution/wordcloud_hu_259cfe713fe34755.png)
![[Algorithm] C++ 백준 1185번: 유럽여행](/post/algorithm/2025-12-19-boj-1185-europe-travel-mst-kruskal-cpp-solution/wordcloud_hu_2db8f33297494ac2.png)
![[Algorithm] C++ 백준 2988번: 아보가드로](/post/algorithm/2025-12-19-boj-2988-avogadro-cpp-solution/wordcloud_hu_f8c8ed89136241ec.png)
![[Algorithm] C++ 백준 14289번: 본대 산책 3](/post/algorithm/2026-01-02-boj-14289-bondae-walk-3-matrix-exponentiation-cpp-solution/wordcloud_hu_dfec1c79bcd6ef2.png)
![[Algorithm] C++ 백준 13232번: Domain clusters](/post/algorithm/2025-12-22-boj-13232-domain-clusters-scc-tarjan-cpp-solution/wordcloud_hu_3afc94f58759c413.png)