原题: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=6011
抛开zoj的问题,如果要百分百过的话(不被数据制裁),需要用到启发式合并。即每次将小的连到大的连通块,这样得出的结构一定是log级别层数。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1000005;
int fa[maxn],mi[maxn],head[maxn];
int siz[maxn];
int Ans[maxn],cnt,ans;
bool vis[maxn];
struct edge{
int to,nex;
}e[maxn<<1];
void add(int u,int v){
e[cnt].to=v,e[cnt].nex=head[u];
head[u]=cnt++;
}
int fin(int x){
return fa[x]==x?x:fa[x]=fin(fa[x]);
}
priority_queue<int,vector<int>,greater<int> > Q;
int main(){
int t;
scanf("%d",&t);
while(t--){
int n,m;scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
head[i]=-1;
fa[i]=i;
siz[i]=1;
mi[i]=i;
vis[i]=0;
}
for(int i=1;i<=m;i++){
int a,b; scanf("%d%d",&a,&b);
add(a,b);
add(b,a);
int f1=fin(a),f2=fin(b);
if(f1!=f2){
if(siz[f1]>siz[f2])swap(f1,f2);
fa[f1]=f2;
mi[f2]=min(mi[f1],mi[f2]);
siz[f2]+=siz[f1];
}
}
ans=0;
for(int i=1;i<=n;i++){
if(fin(i)==i){
ans++;
Q.push(mi[i]);
vis[mi[i]]=1;
}
}
int now=0;
while(!Q.empty()){
int p=Q.top();Q.pop();
Ans[++now]=p;
for(int i=head[p];i!=-1;i=e[i].nex){
int to=e[i].to;
if(vis[to]) continue;
Q.push(to);
vis[to]=1;
}
}
printf("%d\n",ans);
for(int i=1;i<=now;i++){
printf("%d%c",Ans[i],(i==now?'\n':' '));
}
}
return 0;
}