#include <bits/extc++.h>

char readchar() {
  static char buf[1 << 18], *ptr = buf, *end = buf;
  if (ptr == end) ptr = buf, end = buf + fread(buf, 1, 1 << 18, stdin);
  return *ptr++;
}
void writechar(char c) {
  static char buf[1 << 18], *ptr = buf;
  if (ptr == std::end(buf) or c == '\0')
    fwrite(buf, 1, ptr - buf, stdout), ptr = buf;
  *ptr++ = c;
}
__attribute__((destructor)) void destructor() { writechar('\0'); }
template <class T = int>
T getint() {
  char c{};
  while (c < '-') c = readchar();
  bool neg = c == '-';
  T res = neg ? 0 : c - '0';
  while ((c = readchar()) >= '0') res = res * 10 + (c - '0');
  return neg ? -res : res;
}
template <class T>
void putint(T a, char delim = '\n') {
  if (a < 0) writechar('-'), a = -a;
  char buf[sizeof(T) * 3], *ptr = buf;
  do
    *ptr++ = '0' + a % 10;
  while (a /= 10);
  while (ptr-- > buf) writechar(*ptr);
  writechar(delim);
}
#define cin void(0)
#define cout void(0)

struct graph {
  struct edge {
    int src, dst;
    int operator-(int v) const { return src ^ dst ^ v; }
  };

  int n, m;
  std::vector<edge> edges;
  std::vector<std::vector<std::pair<int, int>>> adj;
  std::function<bool(int)> ignore;

  graph(int _n = 0) : n(_n), m(0), adj(n), ignore([](int) { return false; }) {}

  int add(const edge& e, bool directed) {
    assert(0 <= e.src), assert(e.src < n);
    assert(0 <= e.dst), assert(e.dst < n);
    edges.push_back(e);
    adj[e.src].emplace_back(m, e.dst);
    if (not directed) adj[e.dst].emplace_back(m, e.src);
    return m++;
  }
};

struct scc_result {
  std::vector<int> comp_id;
  std::vector<std::vector<int>> components;
  graph dag;

  scc_result(int n) : comp_id(n, -1) {}
};
scc_result find_scc(const graph& g) {
  scc_result res(g.n);
  std::vector<int> in(g.n, -1), min_in(g.n);
  std::stack<int, std::vector<int>> stk;
  int cnt = 0, t = 0;
  auto dfs = [&](auto&& self, int v) -> void {
    in[v] = min_in[v] = t++;
    stk.push(v);
    for (auto [id, u] : g.adj[v]) {
      if (g.ignore(id)) continue;
      if (in[u] == -1) {
        self(self, u);
        min_in[v] = std::min(min_in[v], min_in[u]);
      } else if (res.comp_id[u] == -1) {
        min_in[v] = std::min(min_in[v], in[u]);
      }
    }
    if (min_in[v] == in[v]) {
      while (true) {
        int u = stk.top();
        stk.pop();
        res.comp_id[u] = cnt;
        if (u == v) break;
      }
      ++cnt;
    }
  };
  for (int v = 0; v < g.n; ++v)
    if (in[v] == -1) dfs(dfs, v);
  res.components.resize(cnt);
  for (int v = 0; v < g.n; ++v) {
    res.comp_id[v] = cnt - res.comp_id[v] - 1;
    res.components[res.comp_id[v]].push_back(v);
  }
  std::vector<std::pair<int, int>> es;
  for (int id = 0; id < g.m; ++id) {
    if (g.ignore(id)) continue;
    int src = res.comp_id[g.edges[id].src];
    int dst = res.comp_id[g.edges[id].dst];
    if (src == dst) continue;
    es.emplace_back(src, dst);
  }
  sort(begin(es), end(es));
  es.erase(unique(begin(es), end(es)), end(es));
  res.dag = graph(cnt);
  for (auto [src, dst] : es) res.dag.add({src, dst}, true);
  return res;
}

int main() {
  using namespace std;
  int n = getint();
  int m = getint();
  graph g(n);
  while (m--) g.add({getint(), getint()}, true);
  auto components = find_scc(g).components;
  putint(size(components));
  for (auto&& comp : components) {
    int sz = size(comp);
    putint(sz, ' ');
    for (int i = 0; i < sz; ++i) putint(comp[i], " \n"[i == sz - 1]);
  }
}


Measured memory_bytes: 92932