#include<bits/stdc++.h>
using namespace std;
int find(vector<int>&father, int x) {
if (father[x] == x)return x;
else return find(father, father[x]);
}
void merg(vector<int>& father, vector<int>& rank, int x, int y) {
int X = find(father, x);
int Y = find(father, y);
if (X != Y) {
if (rank[X] > rank[Y]) father[Y] = X;
else if (rank[X] < rank[Y]) father[X] = Y;
else {
father[X] = Y;
rank[Y]++;
}
}
}
/*fa[1] = 2, fa[2] = 2, fa[3] = 1, fa[4] = 2, fa[5] = 2;
}*/
int main() {
int n, m;
cin >> n >> m;
vector<int>father(n + 1);
vector<int>rank(n + 1);
for (int i = 1; i <= n; ++i) {
father[i] = i;
rank[i] = 1;
}
for (int i = 0; i < m; ++i) {
int a, b;
cin >> a >> b;
merg(father, rank,a, b);
}
/*vector<int>xiaoqu;
for (int i = 1; i <= n; ++i) {
if (father[i] == i) xiaoqu.emplace_back(i);
}
cout << xiaoqu.size() << endl;*/
map<int, vector<int>>mp;
int cnt = 0;
for (int i = 1; i <= n; ++i) {
father[i] = find(father, i);//对父集合重新赋值,将i最终的根节点赋为它的父节点
if(mp[father[i]].size() == 0) cnt++;
mp[father[i]].emplace_back(i);//将父节点相同的i存入同一数组,获取同一集合的所有编号
}
cout << cnt << endl;
map<int, int>smp;//smp[每个集合中最小的小区编号] = mp中每个小区的索引key值
for (auto& [ignor, tem] : mp) smp[tem[0]] = ignor;//对每个集合中最小的值进行排序
for (auto& [ignor, tem] : smp) {//按照每个小区最小值从小到大依次输出相同小区的订单号
vector<int>ort = mp[tem];
cout << ort[0];
for (int i = 1; i < ort.size(); ++i)cout << " " << ort[i];
cout << endl;
}
return 0;
}