#include <bits/stdc++.h>
using namespace std;
struct Valence {
  int index;
  int valence;
  bool operator<(Valence const &b) const { return valence < b.valence; }
};
struct Edge {
  int from;
  int to;
};
struct EdgeId {
  int edge;
  int id;
  bool operator<(EdgeId const &b) const { return edge < b.edge; }
  bool operator==(EdgeId const &b) const { return edge == b.edge; }
};
std::stack<int> dfsStack;
Edge dfs(std::vector<bool> &used, int vertex,
         std::vector<std::vector<EdgeId>> &graph,
         std::array<Valence, 200001> &vertexValence) {
  dfsStack.push(vertex);
  int edgeFrom = -1;
  int maxValence = -1;
  int edgeTo = -1;
  while (!dfsStack.empty()) {
    vertex = dfsStack.top();
    dfsStack.pop();
    used[vertex] = true;
    if (vertexValence[vertex].valence > maxValence) {
      maxValence = vertexValence[vertex].valence;
      edgeFrom = vertex;
    }
    int maxValenceTo = -1;
    for (auto &u : graph[vertex]) {
      if (edgeFrom == vertex) {
        if (vertexValence[u.edge].valence > maxValenceTo) {
          maxValenceTo = vertexValence[u.edge].valence;
          edgeTo = u.edge;
        }
      }
      if (!used[u.edge]) {
        if (vertexValence[u.edge].valence > 1) {
          dfsStack.push(u.edge);
        } else {
          used[u.edge] = true;
        }
      }
    }
  }
  Edge res;
  res.from = edgeFrom;
  res.to = edgeTo;
  return res;
}
std::queue<int> bfsStarQueue;
void bfsStar(std::vector<bool> &used, int vertex,
             std::vector<std::vector<EdgeId>> &graph) {
  used[vertex] = true;
  for (auto &u : graph[vertex]) {
    used[u.edge] = true;
  }
}
struct Work {
  int vertexId;
  bool isWorking;
};
std::queue<Work> bfsDeleteQueue;
void bfsDelete(std::vector<bool> &used, int vertex,
               std::vector<std::vector<EdgeId>> &graph,
               std::array<Valence, 200001> &vertexValence,
               std::vector<std::vector<int>> &answers, int day) {
  Work firstWork;
  firstWork.isWorking = false;
  firstWork.vertexId = vertex;
  bfsDeleteQueue.push(firstWork);
  while (!bfsDeleteQueue.empty()) {
    Work top = bfsDeleteQueue.front();
    bfsDeleteQueue.pop();
    used[top.vertexId] = true;
    int maxValence = -1;
    EdgeId EdgeTo;
    EdgeTo.edge = -1;
    EdgeTo.id = -1;
    if (top.isWorking == false) {
      for (auto &u : graph[top.vertexId]) {
        if (!used[u.edge] && vertexValence[u.edge].valence > maxValence) {
          maxValence = vertexValence[u.edge].valence;
          EdgeTo.edge = u.edge;
          EdgeTo.id = u.id;
        }
      }
    }
    for (auto &u : graph[top.vertexId]) {
      if (!used[u.edge]) {
        if (u.edge != EdgeTo.edge) {
          Work newWork;
          newWork.isWorking = false;
          newWork.vertexId = u.edge;
          if (vertexValence[u.edge].valence > 1) {
            bfsDeleteQueue.push(newWork);
          } else {
            used[u.edge] = true;
          }
        } else {
          Work newWork;
          newWork.isWorking = true;
          newWork.vertexId = u.edge;
          if (vertexValence[u.edge].valence > 1) {
            bfsDeleteQueue.push(newWork);
          } else {
            used[u.edge] = true;
          }
        }
      }
    }
    if (top.isWorking == false && EdgeTo.edge != -1) {
      EdgeId Edgetop;
      Edgetop.edge = top.vertexId;
      graph[top.vertexId].erase(find(graph[top.vertexId].begin(),
                                     graph[top.vertexId].end(), (EdgeTo)));
      graph[EdgeTo.edge].erase(
          find(graph[EdgeTo.edge].begin(), graph[EdgeTo.edge].end(), Edgetop));
      vertexValence[top.vertexId].valence--;
      vertexValence[EdgeTo.edge].valence--;
      answers[day].push_back(EdgeTo.id);
    }
  }
}
int main(int argc, char *argv[]) {
  ios_base::sync_with_stdio(0);
  cin.tie(NULL);
  cout.tie(NULL);
  int vertexSize;
  int edgeSize;
  int day = 0;
  std::array<Valence, 200001> vertexValence;
  cin >> vertexSize;
  edgeSize = vertexSize - 1;
  std::vector<bool> used(vertexSize);
  std::vector<bool> star(vertexSize);
  std::vector<std::vector<EdgeId>> graph(vertexSize);
  std::vector<std::vector<int>> answers(vertexSize);
  std::vector<pair<int, int>> starVertexDay;
  starVertexDay.reserve(200001);
  for (int i = 0; i < vertexSize; i++) {
    vertexValence[i].valence = 0;
    vertexValence[i].index = i;
    used[i] = 0;
    answers[i].reserve(200);
  }
  for (int i = 0; i < edgeSize; i++) {
    int p1, p2;
    cin >> p1 >> p2;
    p1--;
    p2--;
    EdgeId first, second;
    first.edge = p1;
    first.id = i + 1;
    second.edge = p2;
    second.id = i + 1;
    graph[p1].push_back(second);
    graph[p2].push_back(first);
    vertexValence[p1].valence++;
    vertexValence[p2].valence++;
  }
  std::vector<bool> usedBFSDelete(vertexSize);
  bool loop = true;
  std::vector<int> go[2];
  int id = 0;
  go[0].resize(vertexSize);
  go[1].resize(vertexSize);
  int count[2];
  count[0] = vertexSize;
  for (int i = 0; i < count[0]; i++) {
    go[id][i] = i;
  }
  while (loop) {
    loop = false;
    count[1 - id] = 0;
    for (int i = 0; i < count[id]; i++) {
      if (!star[go[id][i]] && graph[go[id][i]].size() > 0) {
        used[go[id][i]] = false;
        go[1 - id][count[1 - id]++] = go[id][i];
        usedBFSDelete[go[id][i]] = false;
      }
    }
    id = 1 - id;
    for (int i = 0; i < count[id]; i++) {
      if (used[go[id][i]]) {
        continue;
      }
      loop = true;
      Edge res = dfs(used, go[id][i], graph, vertexValence);
      if (vertexValence[res.to].valence == 1) {
        bfsStar(star, res.from, graph);
        starVertexDay.push_back(std::pair<int, int>(day, res.from));
      } else {
        bfsDelete(usedBFSDelete, res.from, graph, vertexValence, answers, day);
      }
    }
    day++;
  }
  int all = day - 1;
  for (pair<int, int> &dayAndstar : starVertexDay) {
    int startDay = dayAndstar.first;
    int starId = dayAndstar.second;
    int endDay = startDay + vertexValence[starId].valence;
    all = max(all, endDay);
    auto StarTo = graph[starId].begin();
    for (int i = startDay; i < endDay; i++) {
      answers[i].push_back((*StarTo).id);
      ++StarTo;
    }
  }
  std::cout << all << "\n";
  for (int i = 0; i < all; i++) {
    std::cout << answers[i].size() << " ";
    for (int j = 0; j < answers[i].size(); j++) {
      std::cout << answers[i][j] << " ";
    }
    std::cout << "\n";
  }
  return 0;
}
