#include <bits/stdc++.h>
#define rep(i, n) REP(i, 0, n)
#define REP(i, l, r) for (int i = l; i < r; ++i)
#define int long long
#ifdef DEBUG
#define dout cout
#else
std::stringstream dout;
#endif
using namespace std;
typedef pair<int, int> P;
struct edge {
	int to, cost;
};
// other libs
int gcd(int a, int b) {
	if (a % b == 0)
		return b;
	else
		return gcd(b, a % b);
}
int lcm(int a, int b) {
	return a * b / gcd(a, b);
}

class dijkstra {
  private:
	int V;
	int d[100002];
	priority_queue<P, vector<P>, greater<>> que;

  public:
	dijkstra(int v, int s, vector<edge> G[]) {
		V = v;
		update(s, G);
	}

	void update(int s, vector<edge> G[]) {
		fill(d, d + V + 1, 100000000000ll);
		d[s] = 0;
		que.push(make_pair(0, s));
		while (!que.empty()) {
			P p = que.top();
			que.pop();
			int v = p.second;
			if (d[v] < p.first) continue;
			rep(i, G[v].size()) {
				edge e = G[v][i];
				if (d[e.to] > d[v] + e.cost) {
					d[e.to] = d[v] + e.cost;
					que.push(make_pair(d[e.to], e.to));
				}
			}
		}
	}

	int find(int e) {
		return d[e];
	}
};
template<typename T>
class Union_Find {
  private:
	vector<T> t, s;

  public:
	Union_Find(T max_length) {
		rep(i, max_length + 1) {
			t.push_back(i);
			s.push_back(1);
		}
	}

	void Union(T x, T y) {
		if (same(x, y)) return;
		T tx = Find(x), ty = Find(y);
		if (s[tx] < s[ty]) {
			s[ty] += s[tx];
			t[tx] = ty;
		}
		else if (s[tx] > s[ty]) {
			s[tx] += s[ty];
			t[ty] = tx;
		}
		else if (tx > ty) {
			t[tx] = ty;
			s[ty] += s[tx];
		}
		else {
			t[ty] = tx;
			s[tx] += s[ty];
		}
	}
	T Find(T n) {
		if (t[n] == n)
			return n;
		else
			return t[n] = Find(t[n]);
	}

	bool same(T x, T y) {
		return Find(x) == Find(y);
	}

	T get_Size(size_t a) {
		return s[a];
	}
};
bool ifPrime(int n) {
	if (n == 1) return false;
	for (int i = 2; i * i <= n; i++) {
		if (n % i == 0) return false;
	}
	return true;
}

set<int> prime_num_factor(int n) {
	if (n < 2) return set<int>();
	set<int> prime;
	prime.insert(2);
	for (int i = 3; i <= n; i++) {
		for (int it : prime) {
			if (it * it > i) {
				prime.insert(i);
				break;
			}
			if (i % it == 0) break;
		}
	}
	return prime;
}
vector<int> makeDivisors(int n) {
	vector<int> re;
	REP(i, 1, sqrt(n) + 1) {
		if (n % i == 0) {
			re.push_back(i);
			if (i != n / i) re.push_back(n / i);
		}
	}
	return re;
}
int modPow(int a, int n, int mod) {
	int ret = 1;
	while (n) {
		if (n & 1) ret = ret * a % mod;
		a = a * a % mod;
		n >>= 1;
	}
	return ret;
}
int comb(int n, int r) {
	if (n - r < r) r = n - r;
	if (r == 0) return 1;
	if (r == 1) return n;

	vector<int> num(r);
	vector<int> den(r);

	for (int k = 0; k < r; k++) {
		num[k] = n - r + k + 1;
		den[k] = k + 1;
	}

	for (int p = 2; p <= r; p++) {
		int pivot = den[p - 1];
		if (pivot > 1) {
			int offset = (n - r) % p;
			for (int k = p - 1; k < r; k += p) {
				num[k - offset] /= pivot;
				den[k] /= pivot;
			}
		}
	}

	int ret = 1;
	for (int k = 0; k < r; k++) {
		if (num[k] > 1) ret = ret * num[k] % 1000000007;
	}

	return ret;
}
struct Car {
	int speed, from, dist;
	bool operator<(const Car other) {
		return this->speed < other.speed;
	}
	bool operator>(const Car other) {
		return this->speed > other.speed;
	}
};
signed main(signed argc, char* argv[]) {
	cin.tie(nullptr);
	cout.tie(nullptr);
	ios::sync_with_stdio(false);
	int n;
	cin >> n;
	vector<vector<P>> G(n + 1);
	vector<int> cnt(n + 1, 0);
	rep(i, n - 1) {
		int a, b;
		cin >> a >> b;
		G[a].push_back({b, i});
		G[b].push_back({a, i});
		cnt[a]++;
		cnt[b]++;
	}
	int memo, mx = 0;
	rep(i, n) {
		mx = max(mx, cnt[i + 1]);
		if (cnt[i + 1] == 1) memo = i + 1;
	}
	cout << mx << endl;
	vector<int> ans(n - 1);
	vector<bool> m(n + 1,false);
	queue<P> que;
	que.push({memo, 0});
	while (!que.empty()) {
		P it = que.front();
		que.pop();
		int cnt2=1;
		m[it.first]=true;
		rep(i,G[it.first].size()){
		    if(m[G[it.first][i].first])continue;
		    if(cnt2==it.second)cnt2++;
		    que.push({G[it.first][i].first,cnt2});
		    ans[G[it.first][i].second]=cnt2;
		    cnt2++;
		}
	}
	rep(i, n-1) cout << ans[i] << endl;
}


Measured memory_bytes: 9728