P3535. TOU-Tour de Byteotia

考点

  • 并查集

题解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <bits/stdc++.h>
using namespace std;
const int LEN = 1e6 + 50;
int n, m, k, fa[LEN];
vector<int> e[LEN];

int find(int x) {
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}

void join(int x, int y) {
int a = find(x), b = find(y);
fa[a] = b;
}

int main() {
int x, y, ans = 0;
cin >> n >> m >> k;
for (int i = 1; i <= m; ++i) {
cin >> x >> y;
e[x].emplace_back(y), e[y].emplace_back(x);
}
for (int u, v, i = n; i > k; --i) {
fa[i] = u = i;
for (int j = 0; j < e[u].size(); ++j) {
v = e[u][j];
if (fa[v] && find(u) != find(v)) join(u, v);
}
}
for (int u, v, i = k; i >= 1; --i) {
fa[i] = u = i;
for (int j = 0; j < e[u].size(); ++j) {
v = e[u][j];
if (!fa[v]) continue;
if (find(u) == find(v))
++ans;
else
join(u, v);
}
}
cout << ans;
return 0;
}

思路

并查集其中一个用途就是用来判环:

A、B两结点已连通(祖先相同),若此时再赋A、B两点一条边,必存在环

由于题目要求编号小于等于k的点都不在环上,那也得先有环啊:

  1. 反向建图,编号从n遍历到k+1,编号大于k的点先构成图
  2. 编号从k遍历到1,判断当前结点的所有边,若与之前的图构成环,则删除