度数大的点肯定时后加进去的。那么按度数小的顺序加可能是一组合法解(图有解的情况下肯定是合法解)。并查集维护连通性,每次看连出去的边和图中存在的边的数量是否合法。就对了…看了别的网友写的可撤销并查集维护感觉是一个道理但是麻烦很多。
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
#define wzh(x) cerr<<#x<<'='<<x<<endl;
int f[N],sz[N];
int find(int x){
return f[x]==x?x:(f[x]=find(f[x]));
}
vector<int>ans[N];
int res=0;
void merge(int x,int y){
int dx=find(x),dy=find(y);
if(dx==dy)
return;
ans[x].pb(y);
res+=sz[dy];
sz[dx]+=sz[dy];
f[dy]=dx;
}
int t,n,m,d[N],F[N],vis[N];
vector<int>v[N];
int main() {
for(scanf("%d",&t);t;t--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)d[i]=0,v[i].clear(),F[i]=i,
sz[i]=1,f[i]=i,vis[i]=0,ans[i].clear();
for(int i=1;i<=m;i++){
int s,t;
scanf("%d%d",&s,&t);
v[s].pb(t);
v[t].pb(s);
d[s]++;
d[t]++;
}
sort(F+1,F+1+n,[](int x,int y){
return d[x]<d[y];
});
int ok=1;
for(int i=1;i<=n;i++){
res=0;
for(auto k:v[F[i]]){
if(vis[k]){
merge(F[i],k);
}else res++;
}
if(v[F[i]].size()<res)ok=0;
vis[F[i]]=1;
}
if(!ok){
cout<<"No\n";
continue;
}
cout<<"Yes\n";
for(int i=1;i<=n;i++){
cout<<F[i]<<' '<<ans[F[i]].size();
for(int j=0;j<ans[F[i]].size();j++){
cout<<' '<<ans[F[i]][j];
}
cout<<"\n";
}
}
return 0;
}