If both cows $b$ and $c$ admire cow $a$ then both $b$ and $c$ must have the same color. From now on, we can treat both $b$ and $c$ as the same cow; change all occurrences of $c$ to $b$ and merge the adjacency list of $c$ into that of $b$. Repeat this process while at least two distinct cows admire the same cow.
Once we reach a configuration in which a cow is admired by at most one cow this process terminates; we can just assign every cow a distinct color. If we always merge the smaller adjacency list of the two cows into the larger one then our solution runs in $O((N+M)\log N)$ time. We ensured that a few slow solutions did not pass but it is likely that many (not necessarily provable) heuristics passed anyways.
#include <bits/stdc++.h>
using namespace std;
void setIO(string s) {
ios_base::sync_with_stdio(0); cin.tie(0);
freopen((s+".in").c_str(),"r",stdin);
freopen((s+".out").c_str(),"w",stdout);
}
const int MX = 2e5+5;
int N,M;
int par[MX],cnt[MX];
vector<int> adj[MX], rpar[MX];
queue<int> q;
void merge(int a, int b) {
a = par[a], b = par[b];
if (rpar[a].size() < rpar[b].size()) swap(a,b);
for (int t: rpar[b]) { par[t] = a; rpar[a].push_back(t); }
adj[a].insert(end(adj[a]),begin(adj[b]),end(adj[b]));
adj[b].clear();
if (adj[a].size() > 1) q.push(a);
}
int main() {
setIO("fcolor");
cin >> N >> M;
for (int i = 0; i < M; ++i) {
int a,b; cin >> a >> b;
adj[a].push_back(b);
}
for (int i = 1; i <= N; ++i) {
par[i] = i; rpar[i].push_back(i);
if (adj[i].size() > 1) q.push(i);
}
while (q.size()) {
int x = q.front(); if (adj[x].size() <= 1) { q.pop(); continue; }
int a = adj[x].back(); adj[x].pop_back();
if (par[a] == par[adj[x].back()]) continue;
merge(a,adj[x].back());
}
int co = 0;
for (int i = 1; i <= N; ++i) {
if (!cnt[par[i]]) cnt[par[i]] = ++co;
cout << cnt[par[i]] << "\n";
}
}