#include <bits/stdc++.h>
using namespace std;
using namespace std;
void enumerateSubmasks(int m) {
  for (int s = m;; s = (s - 1) & m) {
    if (s == 0) {
      break;
    }
  }
}
int mpow(int a, int b, int m) {
  if (b == 0) return 1;
  int x = mpow(a, b / 2, m);
  x = (x * x) % m;
  if (b % 2) {
    x = (x * a) % m;
  }
  return x;
}
void update(int s, int e, int qs, int qe, vector<int> &seg, vector<int> &lazy,
            int index, int value) {
  if (lazy[index] != -1) {
    seg[index] = max(seg[index], lazy[index]);
    if (s != e) {
      if (lazy[2 * index] == -1)
        lazy[2 * index] = lazy[index];
      else
        lazy[2 * index] = max(lazy[2 * index], lazy[index]);
      if (lazy[2 * index + 1] == -1)
        lazy[2 * index + 1] = lazy[index];
      else
        lazy[2 * index + 1] = max(lazy[2 * index + 1], lazy[index]);
    }
    lazy[index] = -1;
  }
  if (qs > e || qe < s) return;
  if (s >= qs && e <= qe) {
    seg[index] = max(seg[index], value);
    if (s != e) {
      if (lazy[2 * index] == -1)
        lazy[2 * index] = value;
      else
        lazy[2 * index] = max(lazy[2 * index], value);
      if (lazy[2 * index + 1] == -1)
        lazy[2 * index + 1] = value;
      else
        lazy[2 * index + 1] = max(lazy[2 * index + 1], value);
    }
    return;
  }
  int mid = (s + e) / 2;
  update(s, mid, qs, qe, seg, lazy, 2 * index, value);
  update(mid + 1, e, qs, qe, seg, lazy, 2 * index + 1, value);
}
int query(int s, int e, int qs, int qe, vector<int> &seg, vector<int> &lazy,
          int index) {
  if (lazy[index] != -1) {
    seg[index] = max(seg[index], lazy[index]);
    if (s != e) {
      if (lazy[2 * index] == -1)
        lazy[2 * index] = lazy[index];
      else
        lazy[2 * index] = max(lazy[2 * index], lazy[index]);
      if (lazy[2 * index + 1] == -1)
        lazy[2 * index + 1] = lazy[index];
      else
        lazy[2 * index + 1] = max(lazy[2 * index + 1], lazy[index]);
    }
    lazy[index] = -1;
  }
  if (qs > e || qe < s) return LLONG_MIN;
  if (s >= qs && e <= qe) {
    return seg[index];
  }
  int mid = (s + e) / 2;
  int a = query(s, mid, qs, qe, seg, lazy, 2 * index);
  int b = query(mid + 1, e, qs, qe, seg, lazy, 2 * index + 1);
  return max(a, b);
}
void printBinaryString(int n) {
  vector<int> temp;
  while (n) {
    if (n & 1)
      temp.push_back(1);
    else
      temp.push_back(0);
    n = n >> 1;
  }
  reverse(temp.begin(), temp.end());
  for (auto node : temp) cout << node << " ";
  cout << endl;
}
void readVector(vector<int> &a) {
  int n = a.size();
  for (int i = 0; i < n; ++i) cin >> a[i];
}
vector<vector<int>> adj(100002);
vector<int> par(100002);
void dfs(int node, int parent) {
  par[node] = parent;
  for (auto child : adj[node]) {
    if (child == parent) continue;
    dfs(child, node);
  }
}
int32_t main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  int n;
  cin >> n;
  vector<pair<int, int>> graph;
  for (int i = 0; i < n - 1; ++i) {
    int u, v;
    cin >> u >> v;
    adj[u].push_back(v);
    adj[v].push_back(u);
    graph.push_back({u, v});
  }
  dfs(1, 1);
  cout << n - 1 << endl;
  for (int i = 2; i <= n; i++) {
    cout << 2 << " " << i << " " << par[i] << "\n";
  }
  int oneCousin = *adj[1].begin();
  for (auto node : adj[1]) {
    if (node == oneCousin) continue;
    graph.push_back({oneCousin, node});
  }
  for (auto node : graph)
    if (node.first != 1 && node.second != 1)
      cout << node.first - 1 << " " << node.second - 1 << "\n";
}
