题目
注意是都仰慕一头喜欢颜色 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;
}