#include<bits/extc++.h>
#ifndef __unix__
#define readchar _getchar_nolock
#define fread_unlocked _fread_nolock
#else
#define readchar getchar_unlocked
#endif
#ifdef _debug 
#define dout(i) cout << #i << ' ' << i << ' '
#else 
#include<bits/stdc++.h>
#define dout(i) 0&&0
#endif
#pragma GCC optimize("unroll-loops,no-stack-protector,O3")
#define priority_queue __gnu_pbds::priority_queue
#define unordered_map __gnu_pbds::gp_hash_table
#define rep(_n) for(int __i = _n;__i--;)
#define rep0(_i, _n) for(int _i = 0; (_i)<(_n) ;++_i)
#define rep1(_i, _n) for(int _i = 1; (_i)<=(_n) ;++_i)
#define yn(i) ((i)?"Yes" : "No")
#define eout(i) {cout << (i) << '\n';exit(0);}
#define rout(i) {return cout << (i) << '\n', 0;}
#define multi int _T;for(read(_T);_T--;)
using namespace std;
using ll = long long;using ull = unsigned long long;using ul = unsigned;using db = double;
using __gnu_pbds::null_type;
// inline char readchar(){static const size_t bufsize = 1 << 16; static size_t p = 0, end = 0; static char buf[bufsize]; if (p == end) end = fread_unlocked(buf, sizeof(char), bufsize, stdin), p = 0; return p == end ? EOF : buf[p++]; }
inline void read(char &a){static char p; while(isspace(p = readchar())); a = p; }
inline void read(char *a){static char p; while(isspace(p = readchar())); *a = p, ++a; while(isgraph(p = readchar()))*a = p, ++a;}
inline void read(string &a){static char p; while(isspace(p = readchar())); a = p; while(isgraph(p = readchar()))a.push_back(p);}
template<typename T> inline void read(T& a){static char p; static bool b;while (!isdigit(p = readchar()))b = p == '-'; a = p ^ '0'; while (isdigit(p = readchar())) a *= 10, a += p ^ '0'; if(b)a *= -1; }
template<typename T1, typename T2> inline void read(pair<T1, T2> &a){read(a.first), read(a.second);}
template<typename T> inline void read(T begin, const T &end){while(begin != end)read(*begin), ++begin;}
inline void R(){} template<class T1, class... T2> inline void R(T1 &h, T2 &... e){read(h), R(e...);}
template<typename T> inline void write(T begin, const T &end){while(begin != end)cout << *begin << " \n"[next(begin) == end], ++begin;}
template<typename T> using rbtree = __gnu_pbds::tree<T,__gnu_pbds::null_type,less<T>,__gnu_pbds::rb_tree_tag,__gnu_pbds::tree_order_statistics_node_update>;
template<typename T> inline ostream& operator << (ostream &ou, const vector<T> &a){for(auto it = a.begin();it != a.end();++it)ou << (it != a.begin() ? " " : "") << *it;return ou;}
template<typename T1, typename T2>inline istream& operator >> (istream &in, pair<T1, T2> &a){return in >> a.first >> a.second;}
template<typename T1, typename T2>inline ostream& operator << (ostream &ou, const pair<T1, T2> &b){return ou << b.first << ' ' << b.second;}
template<typename T> inline long long pow(long long v, long long t, const T &p){long long res = 1;for(;t;t >>= 1, v = v * v % p)if(t & 1)res = res * v % p;return res;}
const int maxn = 300010;
int n, cnt[maxn], res[maxn];
pair<int,int> alle[maxn];
vector<pair<int,int>> edge[maxn];
int usedcolorcnt = 0;
void dfs(int now, int last = -1, int lastc = -1){
    int c = 1;
    for(auto i : edge[now])if(i.first != last){
        if(c == lastc)++c;
        res[i.second] = c;
        dfs(i.first, now, c);
        ++c;
    }
    usedcolorcnt = max(usedcolorcnt, c-1);
}
signed main(){
    ios_base::sync_with_stdio(0), cin.tie(0);
    R(n);
    read(alle, alle+n-1);
    rep0(i, n-1){
        edge[alle[i].first].emplace_back(alle[i].second, i);
        swap(alle[i].first, alle[i].second);
        edge[alle[i].first].emplace_back(alle[i].second, i);
    }
    rep0(i, n-1)++cnt[alle[i].first], ++cnt[alle[i].second];
    dfs(1);
    cout << usedcolorcnt << '\n';
    rep0(i, n-1)cout << res[i] << '\n';
}

Measured memory_bytes: 14848