Favorite Colors G[USACO20OPEN][并查集][启发式合并]

文章目录

题目

在这里插入图片描述
在这里插入图片描述
注意是都仰慕一头喜欢颜色 c 的奶牛,奶牛不一定相同

思路

发现其实就是一个模拟。。。
首先每个点看成一个集合,然后发现出度 ≥ 2 \ge2 2 就加入队列
队列里面元素 u u u 代表儿子们需要合并,并且只保留一条边
然后出边继承可用启发式合并
所以一条边最多继承 l o g log log
时间复杂度 O ( n l o g m ) O(nlogm) O(nlogm)

代码

#include<set>    
#include<map>    
#include<stack>    
#include<ctime>    
#include<cstdio>    
#include<queue>    
#include<cmath>    
#include<vector>    
#include<ctime>   
#include<cstring>   
#include<climits>    
#include<iostream>   
#include<algorithm>
using namespace std;
#define LL long long
int read(){
    int f=1,x=0;char c=getchar();
    while(c<'0'||'9'<c){if(c=='-')f=-1;c=getchar();}
    while('0'<=c&&c<='9'){x=x*10+c-'0';c=getchar();}
    return f*x;
}
#define mp make_pair
const int MAXN=1000000;
const int INF=0x3f3f3f3f;
queue<int> Q;
int fa[MAXN+5];
int Find(int u){return fa[u]==u?u:(fa[u]=Find(fa[u]));}
vector<int> G[MAXN+5];
void Merge(int u,int v){
	if(G[u].size()<G[v].size())
		swap(u,v);
	for(int i=0;i<(int)G[v].size();i++)
		G[u].push_back(G[v][i]);
	if(G[u].size()>=2) Q.push(u);
	fa[v]=u;
	return ;
}
int col[MAXN+5];
int main(){
	int n=read(),m=read();
	for(int i=1;i<=m;i++){
		int u=read(),v=read();
		if(u==v) continue;
		G[u].push_back(v);
	}
	for(int i=1;i<=n;i++){
		fa[i]=i;
		if(G[i].size()>=2)
			Q.push(i);
	}
	while(!Q.empty()){
		int u=Q.front();Q.pop();
		if(!G[u].size()) continue;
		while(G[u].size()>=2){
			int lst=G[u][G[u].size()-1];G[u].pop_back();
			int t=G[u][G[u].size()-1];
			if(Find(lst)!=Find(t)) Merge(Find(lst),Find(t));
		}
	}
	int cnt=0;
	for(int i=1;i<=n;i++){
		int u=Find(i);
		if(!col[u]) col[u]=++cnt;
		printf("%d\n",col[u]);
	}
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值