前言

     这道题怎么可以没you题解呢

思路分析

       即使每个人都有朋友,但是一定会有一个人的前面没有站着朋友,那么我们就把这些朋友放在一个连通块里,
那么如果里面有一个点(i==f[i])说明他必须要站在最前面,,题目要求字典序最小,那么我么就尽量把编号较
大的点合并到最小的点里,然后把每队朋友关系连边,把能到达的点存入一个优先队列里(小根堆),这样每次
记录答案是得到的就是最小的

代码

//#pragma GCC optimize(3,"inline","Ofast","fast-math","no-stack-protector","unroll-loops")
//#pragma GCC target("sse","sse2","sse3","sse4","avx","avx2","popcnt")
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>

#define RG register
#define ll long long
#define INF 0x3f3f3f3f

using namespace std;

const int N=1e6+10;

int n,m,tot,cnt;
int f[N],ans[N];
int h[N],nex[N<<1],ver[N<<1],vis[N];

priority_queue<int>q;

inline int find(int x)
{
    if(x==f[x]) return x;
    return f[x]=find(f[x]);
}

inline void add(int x,int y)
{
    nex[tot]=h[x];
    ver[tot]=y;
    h[x]=tot++;
}

int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);tot=0;
        memset(h,-1,sizeof(h));cnt=0;
        memset(vis,0,sizeof(vis));
        for (int i=1;i<=n;i++) f[i]=i;
        for (int i=1;i<=m;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            add(x,y),add(y,x);
            int xx=find(x),yy=find(y);
            if(xx==yy) continue;
            if(xx<yy) swap(xx,yy);
//大的往小的合并
            f[xx]=yy;
        }

        int tot=0;
        for (int i=1;i<=n;i++)
            if(f[i]==i) q.push(-i),vis[i]=1,tot++;
//取负是为了满足大根堆性质
        printf("%d\n",tot);

        while(!q.empty())
        {
            int k=-q.top();q.pop();
            ans[++cnt]=k;
            for (int i=h[k];~i;i=nex[i])
            {
                int j=ver[i];
                if(vis[j]) continue;

                vis[j]=1;
                q.push(-j);
            }
        }

        for (int i=1;i<=cnt;i++) printf("%d ",ans[i]);
        puts("");
    }

    return 0;
}