Language: C++

#include <bits/stdc++.h>
#define GET_REP(_1, _2, _3, NAME, ...) NAME
#define rep(...) GET_REP(__VA_ARGS__, irep, _rep)(__VA_ARGS__)
#define rep1(...) GET_REP(__VA_ARGS__, irep1, _rep1)(__VA_ARGS__)
#define _rep(i, n) irep (i, 0, n)
#define _rep1(i, n) irep1(i, 1, n)
#define irep(i, a, n) for (int i = a; i < (int)(n); ++i)
#define irep1(i, a, n) for (int i = a; i <= (int)(n); ++i)
#define rrep(i, n) for (int i = (int)(n) - 1; i >= 0; --i)
#define rrep1(i, n) for (int i = (int)(n); i >= 1; --i)
#define allrep(X, x) for (auto &&X : x)
#define all(x) begin(x), end(x)
#ifdef LOCAL
  #include "../../Lib/cout_container.hpp"
  #define debug(x) cout << #x " => " << (x) << endl
#else
  #define debug(x) 0
#endif
using lint = long long;
constexpr int MOD = (int)1e9 + 7;
constexpr double EPS = 1e-9;
using namespace std;
namespace { struct INIT { INIT() { cin.tie(0); ios::sync_with_stdio(false); cout << fixed << setprecision(15); } } INIT; }

template <> struct hash<pair<int, int>> {
  size_t operator()(const pair<int, int> &p) const {
    constexpr static unsigned s = CHAR_BIT * sizeof(size_t) / 2;
    return (size_t)p.first << s | p.second;
  }
};

using Weight = int;
struct Edge {
  int src, dst;
  Weight weight;
  Edge(void) {}
  Edge(int src, int dst) : src(src), dst(dst) {}
  Edge(int src, int dst, Weight weight) : src(src), dst(dst), weight(weight) {}
};
using Edges = vector<Edge>;
using Graph = vector<Edges>;

void edges_to_graph(Graph &graph, const Edges &edges, const int vertices, const bool directed = true) {
  graph.clear(), graph.resize(vertices);
  for (const auto &e : edges) graph[e.src].emplace_back(e);
  if (!directed) for (const auto &e : edges) graph[e.dst].emplace_back(Edge(e.dst, e.src, e.weight));
}

void dfs(Graph &g, int v, int p, int prev_col, unordered_map<pair<int, int>, int> &cmap) {
  int col = 0;
  for (const auto &e : g[v]) {
    if (e.dst == p) continue;
    ++col;
    if (col == prev_col) ++col;
    cmap[{ v, e.dst }] = col;
    dfs(g, e.dst, v, col, cmap);
  }
}

void bfs(Graph &g, unordered_map<pair<int, int>, int> &cmap) {
  queue<tuple<int, int, int>> que;
  que.push(make_tuple(0, -1, 0));
  while (!que.empty()) {
    int v = get<0>(que.front()), p = get<1>(que.front()), pc = get<2>(que.front());
    que.pop();
    int col = 1;
    for (const auto &e : g[v]) {
      if (e.dst == p) continue;
      if (col == pc) ++col;
      cmap[{ v, e.dst }] = cmap[{ e.dst, v }] = col;
      que.push(make_tuple(e.dst, v, col));
      ++col;
    }
  }
}

Graph graph;
int main(void) {
  int n;
  cin >> n;
  Edges edges(n - 1);
  rep (i, n - 1) {
    int a, b;
    cin >> a >> b;
    edges[i] = {--a, --b, 0};
  }
  edges_to_graph(graph, edges, n, false);
  int maxi = 0;
  rep (i, n) maxi = max(maxi, (int)graph[i].size());
  unordered_map<pair<int, int>, int> cmap;
  dfs(graph, 0, -1, 0, cmap);
  // bfs(graph, cmap);
  cout << maxi << "\n";
  rep (i, n - 1) cout << cmap[{ edges[i].src, edges[i].dst }] << "\n";
  return 0;
}

Compiler output:
a.cc:25:20: error: explicit specialization of 'template<class _Tp> struct std::hash' outside its namespace must use a nested-name-specifier [-fpermissive]
   25 | template <> struct hash<pair<int, int>> {
      |                    ^~~~~~~~~~~~~~~~~~~~