#include <bits/stdc++.h>
using namespace std;
const string nameFiles = "";
void error(vector<string>::iterator) {}
template <typename T, typename... Args>
void error(vector<string>::iterator cur_var, T a, Args... args) {
  cerr << cur_var->substr((*cur_var)[0] == ' ') << " = " << a << endl;
  error(++cur_var, args...);
}
vector<string> split(string const& str, char c) {
  vector<string> res;
  stringstream ss(str);
  string x;
  while (getline(ss, x, c)) res.emplace_back(x);
  return move(res);
}
string to_str(int x) {
  static char buff[64];
  sprintf(buff, "%d", x);
  return std::string(buff);
}
struct Ver {
  int to, id;
};
int n;
vector<vector<Ver>> g;
vector<vector<int>> res;
vector<bool> used;
void dfs(int x, int d = -1) {
  used[x] = true;
  int cur_d = -1;
  for (Ver& y : g[x]) {
    if (!used[y.to]) {
      ++cur_d;
      cur_d += cur_d == d;
      res[cur_d].push_back(y.id);
      dfs(y.to, cur_d);
    }
  }
}
int main() {
  if (!nameFiles.empty()) {
    freopen((nameFiles + ".in").c_str(), "r", stdin);
    freopen((nameFiles + ".out").c_str(), "w", stdout);
  }
  scanf("%d", &n);
  g.resize(n);
  used.resize(n, false);
  int max_d = 0;
  for (int i = 0, f, t; i < n - 1; ++i) {
    scanf("%d %d", &f, &t);
    f--, t--;
    g[f].push_back({t, i + 1});
    g[t].push_back({f, i + 1});
    max_d = max(max_d, (int)g[f].size());
    max_d = max(max_d, (int)g[t].size());
  }
  res.resize(max_d);
  dfs(0);
  printf("%d\n", max_d);
  for (int i = 0; i < max_d; ++i) {
    printf("%d ", (int)res[i].size());
    for (int n : res[i]) printf("%d ", n);
    printf("\n");
  }
  return 0;
}
