#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
struct my{
int next;
int v;
};
const int maxn=10000;
int low[maxn],dfsn[maxn],adj[maxn],fa,sfa,dfn;
int bs[maxn],cnt;
bool bridge[maxn*2];
int sadj[maxn];
my sbian[maxn*2];
my bian[maxn*2];
void myinsert(int u,int v){
bian[++fa].v=v;
bian[fa].next=adj[u];
adj[u]=fa;
}
void smyinsert(int u,int v){
sbian[++sfa].v=v;
sbian[sfa].next=sadj[u];
sadj[u]=sfa;
}
void tarjan(int x,int dage){
dfsn[x]=low[x]=++dfn;
for (int i=adj[x];i;i=bian[i].next){
int v=bian[i].v;
if(!dfsn[v]){
tarjan(v,i);
low[x]=min(low[x],low[v]);
if(dfsn[x]<low[v]){
bridge[i]=bridge[i^1]=1;
}
}
else if(i!=(dage^1)){
low[x]=min(low[x],dfsn[v]);
}
}
}
void dfs(int x){
bs[x]=cnt;
for (int i=adj[x];i;i=bian[i].next){
int v=bian[i].v;
if(bs[v]||bridge[i]) continue;
dfs(v);
}
}
int main(){
int n,m;
int u,v;
fa=1;
sfa=1;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&u,&v);
myinsert(u,v);
myinsert(v,u);
}
for (int i=1;i<=n;i++) if(!dfsn[i]) tarjan(i,0);
for (int i=1;i<=n;i++){
if(!bs[i]){
cnt++;
dfs(i);
}
}
//for (int i=2;i<fa;i+=2) if(bridge[i]) printf("%d %d\n",bian[i].v,bian[i^1].v);
for (int i=2;i<=fa;i++){
int x=bian[i].v,y=bian[i^1].v;
if(bs[x]==bs[y]) continue;
smyinsert(bs[x],bs[y]);//不需连两条边,算法自己会连成双向边
}
for (int i=1;i<=cnt;i++){
printf("%d ",i);
for (int j=sadj[i];j;j=sbian[j].next){
printf("%d ",sbian[j].v);
}
printf("\n");
}
return 0;
}