#include <bits/stdc++.h>
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#pragma GCC target("tune=native")
using namespace std;
const int MAX_N = 100005;
int n;
vector<pair<int, int>> g[MAX_N];
bool used[MAX_N];
vector<int> path;
int result[MAX_N];
pair<int, int> dfs(int u) {
  used[u] = true;
  pair<int, int> res = {0, u};
  for (auto pr : g[u]) {
    int v = pr.first;
    if (used[v]) continue;
    auto vRes = dfs(v);
    vRes.first++;
    res = max(res, vRes);
  }
  return res;
}
bool dfs2(int u, int t) {
  used[u] = true;
  if (u == t) {
    path.push_back(u);
    return true;
  }
  for (auto pr : g[u]) {
    int v = pr.first;
    if (used[v]) continue;
    if (dfs2(v, t)) {
      path.push_back(u);
      return true;
    }
  }
  return false;
}
int32_t main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  cin >> n;
  for (int i = 0; i < n - 1; i++) {
    int u, v;
    cin >> u >> v;
    u--;
    v--;
    g[u].emplace_back(v, i);
    g[v].emplace_back(u, i);
  }
  pair<int, int> res1 = dfs(0);
  int diamU = res1.second;
  memset(used, 0, sizeof(used));
  pair<int, int> res2 = dfs(diamU);
  int diamV = res2.second;
  memset(used, 0, sizeof(used));
  dfs2(diamU, diamV);
  int midInd = (int)path.size() / 2;
  int midU = path[midInd];
  memset(used, 0, sizeof(used));
  queue<int> q;
  used[midU] = true;
  q.push(midU);
  int currNum = 0;
  while (!q.empty()) {
    int u = q.front();
    q.pop();
    for (auto pr : g[u]) {
      int v = pr.first, ind = pr.second;
      if (used[v]) continue;
      used[v] = true;
      q.push(v);
      result[ind] = currNum++;
    }
  }
  for (int i = 0; i < n - 1; i++) cout << result[i] << '\n';
  return 0;
}
