前言
这道题怎么可以没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; }