https://www.acmicpc.net/problem/12012
거꾸로 생각해서 쉬워지는 문제
<문제설명>
최대 2e5개의 정점과 간선으로 이뤄진 양방향 그래프가 주어진다. 정점의 개수를 n이라고 할때 쿼리가 n개 들어온다.
각 쿼리에선 정점이 하나 주어지는데(u), 현재 전체 컴포넌트의 수가 1이라면 YES를, 1이상이라면 NO를 출력한 후, 해당 정점과 정점에 연결된 간선을 모두 지운다.
<풀이>
문제 설명대로 완성된 그래프에 간선을 지워가면서 컴포넌트의 수를 log시간 이하로 구하는 것은 매우 어렵다. (불가능한 것 같다)
쿼리를 기록해두고 거꾸로 접근하면, 아무것도 없는 그래프에 정점과 연결된 컴포넌트를 이어주며 컴포넌트의 개수를 유지하는 문제로 바뀐다.
정점u를 추가할 때 이미 그래프에 추가된 정점들에 대해서만 merge를 해야 한다는 것에 유의하면 구현은 쉽다
<코드>
#include <iostream>
#include <algorithm>
#include <vector>
#define FAST ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
using namespace std;
typedef long long ll;
const int MAX = 2e5 + 2;
int n, m, uf[MAX], chk[MAX], a[MAX],c;
vector<int> adj[MAX];
int find(int u) {
if (uf[u] == -1) return u;
return uf[u] = find(uf[u]);
}
bool merge(int u, int v) {
u = find(u);
v = find(v);
if (u == v) return false;
uf[u] = v;
return true;
}
int main() {
FAST;
memset(uf, -1, sizeof(uf));
cin >> n >> m;
for (int i = 0, u, v; i < m; i++) {
cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u);
}
for (int i = 0; i < n; i++) cin >> a[i];
vector<bool> ans;
for (int i = n - 1,u; i >= 0; i--) {
c++; u = a[i];
for (int v : adj[u])
if (chk[v])
if (merge(u, v))
c--;
chk[u] = true;
ans.push_back(c == 1);
}
reverse(ans.begin(), ans.end());
for (bool b : ans)
cout << (b ? "YES\n" : "NO\n");
}
<생각>
끝까지 생각이 안나서 solution 찾아봤던 문제
'알고리즘 > 백준 & swacademy' 카테고리의 다른 글
BOJ 12003 - Diamond Collector (전처리) (0) | 2020.02.07 |
---|---|
BOJ 12013 - 248게임 (dp) (0) | 2020.02.07 |
BOJ 12011 - Splitting the field (세그트리) (0) | 2020.02.07 |
BOJ 5719 - 거의 최단 경로 (다익스트라) (0) | 2020.01.27 |
BOJ 1854 - K번째 최단경로 찾기(다익스트라) (2) | 2020.01.25 |