#include <bits/stdc++.h>
using namespace std;
struct Point {
  double x, y;
  Point(double x = 0, double y = 0) : x(x), y(y) {}
  Point operator+(const Point& p) const { return Point(p.x + x, p.y + y); }
  Point operator-() const { return Point(-x, -y); }
  Point operator-(const Point& p) const { return *this + (-p); }
  double operator*(const Point& p) const { return x * p.x + y * p.y; }
  double operator%(const Point& p) const { return x * p.y - y * p.x; }
  double sqrLength() const { return (*this) * (*this); }
  double length() const { return sqrt(sqrLength()); }
  double distanceTo(const Point& p) const { return (p - *this).length(); }
  void read() { scanf("%lf%lf", &x, &y); }
};
bool hasBit(int mask, int bitIdx) { return (mask & (1 << bitIdx)) != 0; }
int setBit(int mask, int bitIdx) { return (mask | (1 << bitIdx)); }
void umax(int& curMax, int val) { curMax = max(curMax, val); }
struct Link {
  int to, id;
  Link(int to = 0, int id = 0) : to(to), id(id) {}
};
vector<vector<Link>> g;
vector<vector<int>> ans;
void dfs(int v, int p = -1, int parentLinkId = -1) {
  int linkId = 0;
  for (int i = 0; i < g[v].size(); ++i) {
    int to = g[v][i].to;
    if (to == p) continue;
    if (linkId == parentLinkId) ++linkId;
    ans[linkId].push_back(g[v][i].id);
    dfs(to, v, linkId);
    ++linkId;
  }
}
void solve() {
  int n;
  scanf("%d", &n);
  g.resize(n + 1);
  int maxDeg = 0;
  for (int i = 1; i < n; ++i) {
    int from, to;
    scanf("%d%d", &from, &to);
    g[from].push_back(Link(to, i));
    g[to].push_back(Link(from, i));
    umax(maxDeg, g[from].size());
    umax(maxDeg, g[to].size());
  }
  ans.resize(maxDeg);
  dfs(1);
  printf("%d\n", maxDeg);
  for (int i = 0; i < maxDeg; ++i) {
    printf("%d", ans[i].size());
    for (int j = 0; j < ans[i].size(); ++j) {
      printf(" %d", ans[i][j]);
    }
    printf("\n");
  }
}
int main(void) {
  int t;
  t = 1;
  while (t-- > 0) {
    solve();
  }
  return 0;
}
