#include <bits/stdc++.h>
using namespace std;
int nextInt() {
  int x;
  scanf("%d", &x);
  return x;
}
long long nextLong() {
  long long x;
  scanf("%I64d", &x);
  return x;
}
double nextDouble() {
  double x;
  scanf("%lf", &x);
  return x;
}
const int BUFSIZE = 1000000;
char buf[BUFSIZE + 1];
string nextString() {
  scanf("%s", buf);
  return buf;
}
string nextLine() {
  gets(buf);
  return buf;
}
int stringToInt(string s) {
  stringstream in(s);
  int x;
  in >> x;
  return x;
}
struct Point {
  double x, y;
  Point() : x(0), y(0) {}
  Point(double x, double y) : x(x), y(y) {}
  Point operator-(Point op) const { return Point(x - op.x, y - op.y); }
  Point operator+(Point op) const { return Point(x + op.x, y + op.y); }
  Point operator*(double op) const { return Point(x * op, y * op); }
  double operator*(Point op) const { return x * op.x + y * op.y; }
  double operator%(Point op) const { return x * op.y - y * op.x; }
  double length2() { return x * x + y * y; }
  double length() { return sqrt(length2()); }
};
Point nextPoint() {
  double x = nextDouble();
  double y = nextDouble();
  return Point(x, y);
}
class EdgeSet {
  vector<set<int> > m_set;

 public:
  EdgeSet() : m_set(501000) {}
  void add(int x, int y) {
    if (x > y) {
      swap(x, y);
    }
    m_set[x].insert(y);
  }
  bool check(int x, int y) {
    if (x > y) {
      swap(x, y);
    }
    return m_set[x].find(y) != m_set[x].end();
  }
};
int main() {
  int n = nextInt();
  int m = nextInt();
  EdgeSet missedEdges;
  for (int i = 0; i < m; ++i) {
    int x = nextInt() - 1;
    int y = nextInt() - 1;
    missedEdges.add(x, y);
  }
  vector<bool> used(n, false);
  vector<int> unused;
  for (int i = 0; i < n; ++i) {
    unused.push_back(i);
  }
  int resSize = 0;
  vector<int> res(n, -1);
  for (int i = 0; i < n; ++i) {
    if (!used[i]) {
      ++resSize;
      queue<int> q;
      q.push(i);
      used[i] = true;
      res[i] = resSize;
      while (!q.empty()) {
        int at = q.front();
        q.pop();
        for (int j = 0; j < unused.size(); ++j) {
          int to = unused[j];
          int x = at;
          int y = to;
          if (x > y) {
            swap(x, y);
          }
          if (!missedEdges.check(x, y)) {
            used[to] = true;
            res[to] = resSize;
            q.push(to);
          }
        }
        int newSize = 0;
        for (int j = 0; j < unused.size(); ++j) {
          int x = unused[j];
          if (!used[x]) {
            unused[newSize++] = x;
          }
        }
        unused.resize(newSize);
      }
    }
  }
  vector<vector<int> > ans(resSize);
  for (int i = 0; i < n; ++i) {
    ans[res[i] - 1].push_back(i);
  }
  printf("%d\n", ans.size());
  for (int i = 0; i < ans.size(); ++i) {
    printf("%d", ans[i].size());
    for (int j = 0; j < ans[i].size(); ++j) {
      printf(" %d", ans[i][j] + 1);
    }
    printf("\n");
  }
  return 0;
}
