/**
* 题目:给出一张无向图 求无向图的最小路径覆盖。换句话说就是一张图最少需要几笔画出来。
* 那么很容易想到的是欧拉路径 -> 欧拉路径可以一笔画完 -> 欧拉路径是奇数度点个数为0 或则 为2的路径。
* 扩展一下可以想到的是 对于无向图中的一个联通块来说 需要的最小路径数(欧拉路径数)为 max(d/2,1) d为图中奇数度点的个数。
* 那么 接下来就是对该无向图中的每一个联通块跑一遍求欧拉路径的算法。
* 对于每一个联通块来说。因为其是无向图,所以满足性质无向图中奇数度点的个数为偶数。
* 于是只需要将奇数度点两两配对添边。那么该联通块就是一张欧拉图,我们用其跑求欧拉路径的算法,最后将增加的边删去,就得到了所有的欧拉路径。
**/
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
struct Edge{
int from,to,id;
bool flag;
};
vector<Edge> edges;
vector<int> ways[maxn];
int degree[maxn],visn[maxn],n,m,res;
vector<int> expect,path,ans[maxn];
inline void init() {
edges.clear();
expect.clear();
path.clear();
memset(visn,0,sizeof(visn));
for(int i=0;i<maxn;i++) {
ways[i].clear();
ans[i].clear();
degree[i] = 0;
}
res = 0;
}
inline void addedge(int u,int v,int id) {
edges.push_back((Edge){u,v,id,0});
edges.push_back((Edge){v,u,-id,0});
int sz = edges.size();
ways[u].push_back(sz-2);
ways[v].push_back(sz-1);
degree[u]++;
degree[v]++;
}
void dfs1(int rt) {
visn[rt] = 1;
if(degree[rt] & 1) expect.push_back(rt);
for(int i=0;i<ways[rt].size();i++) {
int to = edges[ways[rt][i]].to;
if(!visn[to]) dfs1(to);
}
}
void dfs2(int rt) {
for(int i=0;i<ways[rt].size();i++) {
int e = ways[rt][i];
if(edges[e].flag) continue;
edges[e].flag = edges[e^1].flag = true;
dfs2(edges[e].to);
path.push_back(edges[e].id);
}
}
int main()
{
int u,v;
while(~scanf("%d%d",&n,&m))
{
init();
for(int i=1;i<=m;i++) {
scanf("%d%d",&u,&v);
addedge(u,v,i);
}
for(int i=1;i<=n;i++) {
if(visn[i] || degree[i] == 0) continue;
expect.clear();
dfs1(i);
for(int j=2;j<expect.size();j+=2) {
addedge(expect[j],expect[j+1],0);
}
path.clear();
int rt = (expect.size()==0 ? i :expect[0]);
dfs2(rt);
for (int j = path.size() - 1; j >= 0; j--) {
if (path[j] == 0) continue;
res++;
while (path[j] != 0 && j >= 0) {
ans[res].push_back(path[j]);
j--;
}
j++;//没用
}
}
printf("%d\n", res);
for (int i = 1; i <= res; i++) {
printf("%d", ans[i].size());
for (int j = 0; j < ans[i].size(); j++) {
printf(" %d", ans[i][j]);
}
printf("\n");
}
}
return 0;
}