[USACO20OPEN] Favorite Colors G
思路:
一个点的儿子如果有多个的话,那么就合并他们,因此可以想到用启发式合并不断合并两个点。
代码:
#include <bits/stdc++.h>
#define int long long
#define fi first
#define se second
using namespace std;
const int inf = 0x3f3f3f3f3f3f3f;
const int N = 2e5+5;
int n,m;
vector<int>g[N];
vector<int>son[N];
int color[N];
int pre[N];
int idx = 0;
queue<int>q;
int root(int x){
return pre[x] = (pre[x] == x)?x:root(pre[x]);
}
void merge(int x,int y){
x = root(x);
y = root(y);
if(son[x].size()<son[y].size())swap(x,y);//儿子多的合并儿子少的
for(const auto &i:g[y]){
g[x].push_back(i);
}
for(const auto &i:son[y]){
pre[i] = x;
son[x].push_back(i);
}
if(g[x].size()>1)q.push(x);
}
void solve(){
cin>>n>>m;
for(int i=1;i<=m;i++){
int x,y;cin>>x>>y;
g[x].push_back(y);
}
for(int i=1;i<=n;i++){
pre[i] = i;
son[i].push_back(i);
if(g[i].size()>1)q.push(i);
}
while(!q.empty()){
int fa = q.front();
q.pop();
while(g[fa].size()>1){//如果儿子>=2个那么就合并
int x = g[fa][0];
int y = g[fa][1];
g[fa].erase(g[fa].begin());
if(root(x)!=root(y)){
merge(x,y);
}
}
}
for(int i=1;i<=n;i++){
if(!color[root(i)]){
color[root(i)] = ++idx;
}
cout<<color[root(i)]<<"\n";
}
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int T=1;
//cin>>T;
while(T--){
solve();
}
return 0;
}