#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;

}