题目
[USACO 20OPEN] Favorite Colors G
分析
按拓扑序枚举各个点,只需要合并把他们的邻接点(即仰慕它的奶牛)合并在一起即可,采用启发式合并。
代码
#include <bits/stdc++.h>
int Read() {
int x = 0; char c = getchar();
while (c < '0' || c > '9')
c = getchar();
while (c >= '0' && c <= '9')
x = x * 10 + (c ^ 48), c = getchar();
return x;
}
const int MAXN = 200000;
int N, M;
int Bel[MAXN + 5], Cnt;
std::queue<int> Q;
std::vector<int> G[MAXN + 5];
int Par[MAXN + 5];
std::vector<int> Son[MAXN + 5];
void Merge(const int &u, const int &v) {
int x = Par[u], y = Par[v];
if (Son[y].size() > Son[x].size())
std::swap(x, y);
for (int c: Son[y])
Par[c] = x, Son[x].push_back(c);
for (int c: G[y])
G[x].push_back(c);
if (G[x].size() > 1) Q.push(x);
}
int main() {
N = Read(), M = Read();
for (int i = 1; i <= M; i++) {
int u = Read(), v = Read();
G[u].push_back(v);
}
for (int i = 1; i <= N; i++) {
Par[i] = i;
Son[i].push_back(i);
if (G[i].size() > 1)
Q.push(i);
}
while (!Q.empty()) {
int u = Q.front(); Q.pop();
while (G[u].size() > 1) {
int v = G[u].back(); G[u].pop_back();
if (Par[v] != Par[G[u].back()])
Merge(v, G[u].back());
}
}
for (int i = 1; i <= N; i++) {
if (!Bel[Par[i]])
Bel[Par[i]] = ++Cnt;
printf("%d\n", Bel[Par[i]]);
}
return 0;
}