考虑到对于一个联通块,最后一个加的点一定是度数最大的点,并且度数是联通块的siz-1。而把这个点删掉之后的图,因为每个点的度数同减一,依然满足上述性质。于是反过来想可以发现,若有解,则将最终度数从小到大依次加入图的方案一定是一组解。判断这种加点方式是否成立即可。用并查集维护联通性。
#include <bits/stdc++.h>
using namespace std;
const int maxn=105000;
vector<int>g[maxn], ans[maxn];
int n, m;
int fa[maxn], siz[maxn], id[maxn], degree[maxn];
bool vis[maxn];
bool cmp(int x, int y){
return degree[x]<degree[y];
}
int f(int x){
if(x==fa[x])return x;
return fa[x]=f(fa[x]);
}
int main(){
int T;
scanf("%d", &T);
while(T--){
scanf("%d%d", &n, &m);
for(int i=1;i<=n;i++){
g[i].clear();
ans[i].clear();
fa[i]=id[i]=i, siz[i]=1;
degree[i]=0;
vis[i]=false;
}
for(int i=1;i<=m;i++){
int u, v;
scanf("%d%d", &u, &v);
degree[u]++, degree[v]++;
g[u].push_back(v);
g[v].push_back(u);
}
sort(id+1, id+1+n, cmp);
//for(int i=1;i<=n;i++)printf("%d%c", id[i], i==n?'\n':' ');
bool ok=true;
for(int i=1;i<=n;i++){
int u=id[i];
int sum=0;
vis[u]=true;
for(int j=0;j<g[u].size();j++){
int v=g[u][j];
if(!vis[v])continue;
sum++;
v=f(v);
if(v==u)continue;
ans[i].push_back(v);
fa[v]=u;
siz[u]+=siz[v];
}
if(siz[u]!=sum+1){
ok=false;
break;
}
}
if(!ok)printf("No\n");
else {
printf("Yes\n");
for(int i=1;i<=n;i++){
printf("%d %d", id[i], (int)ans[i].size());
for(int j=0;j<ans[i].size();j++){
printf(" %d", ans[i][j]);
}
printf("\n");
}
}
}
}