[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;
}