step 1
더보기
원래 상태에서 연결을 끊는다고 생각하지 말고 이미 연결을 다 끊어놓은 상태에서 거꾸로 연결을 한다고 생각합니다.
step 2
더보기
$Q$번의 연결을 다 끊어놓은 상태를 구할 수 있습니다. 유니온 파인드를 이용해서 어떤 정점들이 이어져 있는지 확인합니다. 그 상태에서 쿼리를 반대로 봅니다. 두 정점이 같은 집합에 있다면 해당 쿼리를 실행했을 때 통신망이 나뉘어지지 않았다는 뜻입니다. 두 정점이 다른 집합에 있다면 각 집합의 크기를 곱한 값만큼 비용이 발생했다는 뜻입니다.
코드
더보기
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
struct data {
long long int x, y;
}b[200000];
long long int tr[200000];
long long int lv[200000], cnt[200000], p[200000],ch[200000];
long long int merge(long long int x, long long int y) {
while (x != p[x]) x = p[x];
while (y != p[y]) y = p[y];
if (x == y) return 0;
long long int v = cnt[x] * cnt[y];
if (lv[x] < lv[y]) {
p[x] = p[y];
cnt[y] += cnt[x];
}
else if (lv[x] > lv[y]) {
p[y] = p[x];
cnt[x] += cnt[y];
}
else {
p[y] = p[x];
cnt[x] += cnt[y];
lv[x]++;
}
return v;
}
int main() {
long long int n, m, q, i,countt=0;
scanf("%lld%lld%lld", &n, &m, &q);
for (i = 1;i <= m;i++) {
scanf("%lld%lld", &b[i].x, &b[i].y);
}
for (i = 1;i <= q;i++) {
scanf("%lld", &tr[i]);
ch[tr[i]] = 1;
}
for (i = 1;i <= n;i++) {
lv[i] = 1;
cnt[i] = 1;
p[i] = i;
}
for (i = 1;i <= m;i++) {
if (ch[i] == 0) {
merge(b[i].x, b[i].y);
}
}
for (i = q;i >= 1;i--) {
countt += merge(b[tr[i]].x, b[tr[i]].y);
}
printf("%lld", countt);
return 0;
}
'PS - 알고리즘' 카테고리의 다른 글
9642 - Omar’s Bug (1) | 2024.06.13 |
---|---|
17242 - Kaka & Bebe (0) | 2024.06.13 |
13209 - 검역소 (0) | 2024.06.02 |
3043 - 장난감 탱크 (0) | 2024.05.31 |
11873 - 최대 직사각형 (0) | 2024.05.26 |