題意:
T組數據,每組數據給你n(<=1e5)個點,m(<=min(1e5,n*(n-1)/2))條無向邊,你需要構造一個合法的序列,其中每一項輸出三個數:
點x,你選擇的點集的大小,然後給出這些點。(初始爲空圖,之後系統會增加一個新點x,並將x與你給出的這些點所在的連通塊的每一個結點連邊!)
最後形成題中給你的圖。問你是否存在合法方案,如果存在輸出Yes和任意一種方案,否則輸出No。
思路:
直接正着做找合法序列太難了,我們考慮從原圖往下一個一個拆點,拆成一個合法序列,最後倒着輸出。
注意到我們拆這一個點u,它的度數 必須 等於 所在連通塊的大小 -1 。
因此我們將所有點按度數從小到大排序,先用並查集(注意,這裏用的是可撤銷並查集,因爲要拆點會造成連通塊數變多,不能路徑壓縮!!!)建立初始的連通塊,記錄度數大的點向度數小的點連的邊。
之後再從度數最大的點開始拆,一直拆到度數最小的點(顯然度數最大的點一定是後面才添加進圖裏去的)。
對於某個點u,如果它的度數d[u] != u所在的連通塊的大小 -1 則答案一定不存在。否則u點便可以拆下來。
然後更新u所連的所有點的度數(顯然連的點的度數一定小於等於u的度數)。然後撤銷u向度數小的點連的邊,記錄答案。
並查集這一塊還是用的不夠熟練,還需要多加練習。
代碼:
#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
#define mst(head,x,n) memset(head+1,x,n*sizeof(head[0]))
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dep(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
const int maxn=1e5+5;
//const double pi=acos(-1.0);
//const double eps=1e-9;
//const ll mo=1e9+7;
int n,m,k;
int mp[maxn];
int tmp,cnt;
int flag;
bool ok[maxn];
vector<int>vc[maxn];
template <typename T>
inline void read(T &X){
X=0;int w=0; char ch=0;
while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
if(w) X=-X;
}
struct node{
int x,y,fax,szx,hx;
}stk[maxn];
struct st{
int id;
int v;
}d[maxn];
struct BCJ{
int fa[maxn];
int sz[maxn];
int h[maxn];
void init(int n){
cnt=0;
rep(i,0,n){
fa[i]=-1;
sz[i]=1;
h[i]=0;
}
}
int find(int x){return fa[x]==-1?x:find(fa[x]);}
int un(int ox,int oy){
int x=find(ox);
int y=find(oy);
if(x==y) return 0;
if(h[x]>h[y]) swap(x,y);
if(h[x]==h[y]) h[y]++;
stk[++cnt]=node{x,y,fa[x],sz[x],h[x]};
fa[x]=y;
sz[y]+=sz[x];
return 1;
}
void undo(int num){
while(num--){
node k=stk[cnt--];
h[k.x]=k.hx;
sz[k.y]-=k.szx;
fa[k.x]=k.fax;
}
}
int get(int x){
x=find(x);
return sz[x];
}
}bcj;
bool cmp(st x,st y){
return x.v<y.v||(x.v==y.v&&x.id<y.id);
}
int main(){
#ifdef ONLINE_JUDGE
#else
freopen("D:/Temp/in.txt", "r", stdin);
#endif
int T,cas=1;
read(T);
while(T--)
{
//cout<<" &^% "<<endl;
read(n);read(m);
bcj.init(n);
rep(i,1,n) {
vc[i].clear();
d[i].v=0;
d[i].id=i;
ok[i]=false;
}
rep(i,1,m){
int u,v;
read(u);read(v);
vc[u].push_back(v);
vc[v].push_back(u);
d[u].v++;d[v].v++;
}
sort(d+1,d+1+n,cmp);
vector<vector<int> >tp(n+1);
//cout<<" *&(^^ "<<endl;
for(int i=1;i<=n;i++){
int u=d[i].id;
mp[u]=i;
for(int j=0;j<vc[u].size();j++){
int v=vc[u][j];
if(!ok[v]) continue;
if(bcj.un(u,v)){
tp[u].push_back(v);
}
}
ok[u]=true;
}
//cout<<" *&(^^ "<<endl;
vector<pair<int,vector<int> > >ans;
int fg=1;
dep(i,n,1){
int u=d[i].id;
//cout<<u<<" "<<d[i].v<<" "<<bcj.get(u)-1<<endl;
if(d[i].v!=bcj.get(u)-1) {
puts("No");
fg=0;
break;
}
for(int j=0;j<vc[u].size();j++){
int v=vc[u][j];
d[mp[v]].v--;
}
ans.push_back(make_pair(u,tp[u]));
bcj.undo(tp[u].size());
}
if(!fg) continue;
puts("Yes");
reverse(ans.begin(),ans.end());
for(int i=0;i<ans.size();i++){
int nm=ans[i].first;
vector<int> mm=ans[i].second;
int msz=mm.size();
printf("%d %d",nm,msz);
for(int j=0;j<msz;j++){
printf(" %d",mm[j]);
}
puts("");
}
}
return 0;
}