#pragma region kyopuro_templates
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<stdbool.h>
#include<assert.h>
#include<time.h>
#include<ctype.h>

typedef long long ll;
typedef long double ld;
#define rep(i,l,r)for(ll i=(l);i<(r);i++)
#define repp(i,l,r,k)for(ll i=(l);i<(r);i+=(k))
#define rrep(i,l,r)for(ll i=(l);i>=(r);i--)
#define INF (1LL<<62)
#define MOD1 1000000007
#define MOD2 998244353
#define MAX_N (1 << 20)
#define YES printf("Yes\n")
#define NO printf("No\n")
#define PN printf("\n")
#define charsize 100005 //10^5+5
#define PI 3.141592653589793238

void swap(ll *a, ll *b){ll c;c=*b;*b=*a;*a= c;}
void cin(ll *n){ scanf("%lld",&(*n)); }
ll max2(ll a,ll b){return a>=b?a:b;}
ll min2(ll a,ll b){return a>=b?b:a;}
ll min3(ll a, ll b, ll c){return (a<=b && a<=c) ? a : b<=c ? b : c;}
ll max3(ll a, ll b, ll c){return (a>=b && a>=c) ? a : b>=c ? b : c;}
ll minn(ll n, ll a[]){ll b=INF;rep(i,0,n) b=min2(b,a[i]);return b;}
ll maxn(ll n, ll a[]){ll b=-INF;rep(i,0,n) b=max2(b,a[i]);return b;}
ll POW(ll a, ll b){ll c=1;rep(i,0,b) c*=a;return c;}
double POW_d(double a, double b){double c=1;rep(i,0,b) c*=a;return c;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
ll mod_MOD1(ll n){n+= n<0?((-n)/MOD1+1)*MOD1:0; return n%=MOD1;}
ll mod_p(ll n ,ll p){n+= n<0?((-n)/p+1)*p:0; return n%=p;}
ll change_into_num(char s[] , ll len, ll p){ return !p ? 0 : POW(10,p-1)*(s[len-p]-'0') + change_into_num(s,len,p-1); }
ll digits(ll a, ll b){return a/b?1+digits(a/b,b):1;}
ll base(ll n, ll a, ll i){return i==1?n%a:base(n/a,a,i-1);}
ll is_inArr1(ll x, ll n){ return ( x<0 || x>=n ) ? 0 : 1 ; }
ll is_inArr2(ll y, ll x, ll h, ll w){ return ( y<0 || y>=h || x<0 || x>=w ) ? 0 : 1 ; }


void lr_lower( int *l, int *r, ll am, ll val , int type ){ (type<3) ? ( am < val ?  ( *l = (*l+*r)/2 ) : ( *r= (*l+*r)/2 ) ) : ( am <= val ? ( *l = (*l+*r)/2 ) : ( *r= (*l+*r)/2 ) ); }
void lr_upper( int *l, int *r, ll am, ll val , int type ){ (type<3) ? ( am <= val ?  ( *l = (*l+*r)/2 ) : ( *r= (*l+*r)/2 ) ) : ( am < val ? ( *l = (*l+*r)/2 ) : ( *r= (*l+*r)/2 ) ); }
int cmp_lower( ll a, ll b, int type ){ return (type==1) ? ( a==b ? 1 : 0 ) : (type==2) ? ( a>=b ? 1 : 0 ) : ( a>b ? 1 : 0 ) ; }
int cmp_upper( ll a, ll b, int type ){ return (type==1) ? ( a==b ? 1 : 0 ) : (type==2) ? ( a<=b ? 1 : 0 ) : ( a<b ? 1 : 0 ) ; }
// return smallest p  which meets  a[p]==val :1  >=:2   >:3
ll lower_bound( ll a[], int l, int r, ll val , int type ){  while(r-l>1) lr_lower(&l,&r,a[ (l+r)/2 ],val,type);  return cmp_lower(a[l],val,type) ? l : cmp_lower(a[r],val,type) ? r : -1;  }
// return biggest p  which meets   a[p]==val :1  <=:2   <:3
ll upper_bound( ll a[], int l, int r, ll val , int type ){  while(r-l>1) lr_upper(&l,&r,a[ (l+r)/2 ],val,type); return cmp_upper(a[r],val,type) ? r : cmp_upper(a[l],val,type) ? l : -1; }
// count i  which meets ai==x
ll count(ll a[], int l, int r, ll x){  int p = lower_bound(a,l,r,x,1);  return p==-1 ? 0 : upper_bound(a,p,r,x,1)-p+1; }

ll *factors[2] , fac_cnt=0 , is_factor_prepared=0;
ll factor_pre(){  rep(i,0,1){ if(is_factor_prepared++) return 0; }  ll tmp=(1e6)/2+1, fac_tmp[tmp];  rep(i,0,tmp){fac_tmp[i]=i?2*i+1:2;}  rep(i,1,tmp){if(fac_tmp[i]){  repp(j,3,tmp/(2*i+1)+1,2 ){  if( j*(2*i+1)<tmp ) fac_tmp[ (j*(2*i+1)-1)/2 ]=0;  }  }else continue;}  rep(i,0,tmp){if(fac_tmp[i]){  rep(j,0,2){ factors[j] = (ll *) realloc( factors[j] , sizeof(ll)*( fac_cnt +1 ) );  factors[j][j?fac_cnt++:fac_cnt]=j?0:fac_tmp[i];  }  } }  return 0;  }
ll factor(ll n, ll new_common_plus){ factor_pre();  rep(i,0,fac_cnt){ ll cnt=0; rep(j,0,1){ while( ( cnt+= n %factors[0][i]==0 ? 1 : 0 )  && (n/=factors[0][i]) %factors[0][i]==0 ) continue; } factors[1][i]= new_common_plus==1 ? cnt :  new_common_plus==2 ? max2(factors[1][i],cnt) : factors[1][i]+cnt ;  if( factors[0][i]> n ) break; } return n; }
ll judge_prime(ll n){ factor_pre(); rep(i,0,fac_cnt){ if(n<factors[0][i]*factors[0][i] || n==factors[0][i]) break; else if(n%factors[0][i]==0) n/=n; }  return n==1?0:1; }

ll *mf_arr,*inv_arr,*finv_arr,is_minv_made=0,is_mf_made=0,num_of_inv=2*1e6+10;
ll makeinv(ll n , ll mod){  rep(i,0,1){if(is_minv_made++) return 0;}  inv_arr = (ll*) realloc(inv_arr, sizeof(ll)*2 );  finv_arr = (ll*) realloc(finv_arr, sizeof(ll)*2 );  inv_arr[1]=1;finv_arr[0]=finv_arr[1]=1;  rep(i,2,n+1){  inv_arr = (ll*) realloc(inv_arr, sizeof(ll)*(i+1) );  finv_arr = (ll*) realloc(finv_arr, sizeof(ll)*(i+1) );  inv_arr[i]= mod - inv_arr[mod%i] * (mod / i) % mod;  finv_arr[i] = finv_arr[i - 1] * inv_arr[i] % mod;  }  return 0; }
ll make_mf(ll n, ll mod){  rep(i,0,1){ if(is_mf_made++) return 0; }  mf_arr = (ll*) realloc(mf_arr, sizeof(ll)*2 );  ll x=1;  mf_arr[0]=mf_arr[1]=x;  rep(i,2,n+1){   x=x*i%mod;  mf_arr = (ll*) realloc(mf_arr, sizeof(ll)*(i+1) );  mf_arr[i]=x; }  return 0;  }
ll m_inv(ll x, ll mod, ll is_fac ){ makeinv(num_of_inv,mod);  return is_fac?finv_arr[x]:inv_arr[x]; }
ll m_f(ll x, ll mod){  make_mf(num_of_inv,mod);  return mf_arr[x];  }
ll mod_nck(ll n, ll k, ll mod){ return m_f(n,mod)*m_inv(k,mod,1)%mod*m_inv(n-k,mod,1)%mod; }
ll m_p(ll r,ll n,ll mod){  ll t=1,s=r;  while(n>0){ t = (n&1) ? t*s%mod : t;  s=s*s%mod; n>>=1; }  return r?t:0;  }
ll m_mul2(ll a, ll b, ll mod){ return a*b%mod; }
ll m_mul3(ll a, ll b, ll c, ll mod){ return m_mul2(a*b%mod,c,mod); }
ll m_mul4(ll a, ll b, ll c, ll d, ll mod){ return m_mul3(a*b%mod,c,d,mod); }
ll m_mul5(ll a, ll b, ll c, ll d, ll e, ll mod){ return m_mul4(a*b%mod,c,d,e,mod); }

int upll(const void*a, const void*b){return*(ll*)a<*(ll*)b?-1:*(ll*)a>*(ll*)b?1:0;}
int downll(const void*a, const void*b){return*(ll*)a<*(ll*)b?1:*(ll*)a>*(ll*)b?-1:0;}
int cmp_string( const void * a , const void * b ) {  return strcmp( (char *)a , (char *)b ); }  // qsort((void*)s,n,sizeof(s[0]),int_sort );
int cmp_char(const void * a, const void * b) { return *(char *)a - *(char *)b;}
void sortup(ll*a,int n){qsort(a,n,sizeof(ll),upll);}
void sortdown(ll*a,int n){qsort(a,n,sizeof(ll),downll);}
void sort_string(int n,int size,char s[][size]){ qsort( (void*)s , n , sizeof(s[0]) , cmp_string ); }
void sort_char(char *s){ qsort( (void *)s , strlen(s) , sizeof(char) , cmp_char ); }
ll unique_string(ll n ,ll size, char s[][size]){ ll ans=1; rep(i,1,n) if( strcmp(s[i],s[i-1]) ) ans++; return ans; }
ll unique_num(ll n , ll a[]){ ll ans=1; rep(i,1,n) if( a[i]!=a[i-1] ) ans++; return ans; }


typedef struct{ ll a , b;}fr;
int cmp1( const void *p, const void *q ) { return ((fr*)p) ->a - ((fr*)q)->a;}
int cmp2( const void *p, const void *q ) { return ((fr*)q) ->a - ((fr*)p)->a;}
void strsortup(fr*a,int n){qsort(a,n,sizeof(fr),cmp1);}
void strsortdown(fr*a,int n){qsort(a,n,sizeof(fr),cmp2);}

#pragma region AVL
/*---------------------------AVL start--------------------------------*/
//https://qiita.com/mikecat_mixc/items/e9f8248de2ae7f7a0a29
typedef struct node_AVL{  ll val; int diff; int cnt; struct node_AVL *child[2];  }AVL;
void AVL_inside_rotate(AVL **node, int is_right){   int l = is_right==false , r = is_right==true , sign = is_right ? 1 : -1;   if((*node)->child[l] != NULL){  AVL* left = (*node)->child[l];  int a= (*node)->diff * sign , b= left->diff * sign , na , nb;  (b>=0) ? (  na=a-1-b , nb= (a-b)? b-1 : a-2 ) : ( na=a-1, nb= a? b-1 : a+b-2 );   (*node)->diff = na * sign; left->diff = nb * sign;   /* rotate-> */ (*node)->child[l] = (*node)->child[l]->child[r]; left->child[r] = *node; *node = left;   }   }
int AVL_inside_update(AVL **node, ll data, int add) {
    if(*node == NULL){   add==2 ? (  *node = (AVL *) malloc(sizeof(AVL)), (*node)->val = data, (*node)->cnt = 1, (*node)->diff = 0, (*node)->child[0] = NULL, (*node)->child[1] = NULL  ) : 0;  return add==2 ? *node != NULL : 0; 
    }else{
        int l, delta, delta_sign; AVL *next_node;
        if(data == (*node)->val){  if(add==2){  (*node)->cnt++; return 0;  }else{   if( add && (*node)->cnt > 1 ){ (*node)->cnt--; return 0;  }else{  if((*node)->child[1] == NULL){  next_node = (*node)->child[0]; free(*node); *node = next_node; return -1;  }else if((*node)->child[0] == NULL){  next_node = (*node)->child[1]; free(*node); *node = next_node; return -1;  }else{  for(next_node = (*node)->child[0]; next_node->child[1] != NULL; next_node = next_node->child[1]);  (*node)->val = next_node->val; l=0; delta_sign=1; delta = AVL_inside_update(&(*node)->child[l], next_node->val, add);   }   }    }   }else{ l = data >= (*node)->val ? 1 : 0; delta_sign = data < (*node)->val ? 1 : -1; delta = AVL_inside_update(&(*node)->child[l], data, add); }
        if(delta != 0){
            int orig_diff = (*node)->diff;  int do_rotate = llabs((*node)->diff)>1 ?1:0 , rotate_l , diff_sign , rotate_right;   (*node)->diff += delta * delta_sign;
            if((*node)->diff > 1){  do_rotate = 1; rotate_l = 0; diff_sign = 1; rotate_right = 1;   }else if((*node)->diff < -1){ do_rotate = 1; rotate_l = 1; diff_sign = -1; rotate_right = 0; }
            while(do_rotate){
                int child_diff = (*node)->child[rotate_l]->diff;
                if((*node)->child[rotate_l]->diff * diff_sign < 0){ AVL_inside_rotate(&(*node)->child[rotate_l], !rotate_right); }
                AVL_inside_rotate(node, rotate_right); return delta < 0 && child_diff != 0 ? -1 : 0;
            }
            if(delta > 0 && orig_diff == 0){ return 1; }else if(delta < 0 && orig_diff != 0){ return -1; }else{ return 0; }
        }else{ return 0; }
    }
}

void AVL_inside_print(const AVL *node, int depth){  if(node != NULL){ AVL_inside_print(node->child[1], depth + 1); printf("%lld %d\n", node->val,node->cnt); AVL_inside_print(node->child[0], depth + 1);  } }
void AVL_inside_free(AVL *node){  if(node != NULL){  AVL_inside_free(node->child[0]);  AVL_inside_free(node->child[1]);  free(node);  }  }
ll AVL_inside_count(AVL *root, ll val){   AVL *node; node = root;   while(node){ if(val < node->val){ node = node->child[0]; }else if(val > node->val){ node = node->child[1]; }else{ return node->cnt; } }   return 0;   }
ll AVL_inside_minmax(AVL *root, int type){ while(root->child[type] !=NULL){ root= root->child[type]; } return root->val; }
#define AVL_MAX_SIZE 514511
ll AVL_main( int command , int AVL_num , ll val ){
    static bool AVL_is_init=false;
    static AVL *AVL_pointer[AVL_MAX_SIZE];
    static ll AVL_siz[AVL_MAX_SIZE];
    if(!AVL_is_init){ AVL_is_init=true; rep(i,0,AVL_MAX_SIZE){ *(AVL_pointer+i) = NULL; AVL_siz[i]=0; } }
    if(command==-1){ AVL_inside_print( AVL_pointer[AVL_num] ,0); }
    if(command==1){ AVL_inside_count(AVL_pointer[AVL_num],val) ? 1 : AVL_siz[AVL_num]++;  AVL_inside_update( &AVL_pointer[AVL_num] , val , 2 ); }
    if(command==2){ return AVL_inside_count(AVL_pointer[AVL_num],val); }
    if(command==3){ ( AVL_inside_count(AVL_pointer[AVL_num],val) > 1 ) ? 1 : AVL_siz[AVL_num]--;  AVL_inside_update( &AVL_pointer[AVL_num] , val , 1 ); }
    if(command==4){ AVL_siz[AVL_num]--; AVL_inside_update( &AVL_pointer[AVL_num] , val , 0 ); }
    if(command==5){ AVL_siz[AVL_num]=0; AVL_inside_free( AVL_pointer[AVL_num] ); AVL_pointer[AVL_num] = NULL; }
    if(command==6){ return AVL_siz[AVL_num]; }
    if(command==7){ return AVL_inside_minmax(AVL_pointer[AVL_num],1); }
    if(command==8){ return AVL_inside_minmax(AVL_pointer[AVL_num],0); }
    return 0;
}
void AVL_print(int AVL_num){ AVL_main(-1,AVL_num,0); }
void AVL_insert(int AVL_num, ll val){ AVL_main(1,AVL_num,val); }
ll AVL_count(int AVL_num, ll val){ return AVL_main(2,AVL_num,val); }
void AVL_erase(int AVL_num, ll val, int is_all){ if(is_all) AVL_main(4,AVL_num,val); else AVL_main(3,AVL_num,val); }
void AVL_clear(int AVL_num){ AVL_main(5,AVL_num,0); }
ll AVL_size(int AVL_num){ return AVL_main(6,AVL_num,0); }
ll AVL_max(int AVL_num){ return AVL_main(7,AVL_num,0); }
ll AVL_min(int AVL_num){ return AVL_main(8,AVL_num,0); }
/*
insert *
size *
clear *
erase *
count *
max *
min *
lower_bound
upper_bound
*/

/*---------------------------AVL start--------------------------------*/
#pragma endregion AVL

#pragma endregion kyopuro_templates


int ed_cnt[514315];
ll* gr[514315];
ll* ed_num[514315];
ll ans[514315];
// freeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee!!!!!!!!!!!!!!!

void pushGraph(ll v1, ll v2, ll weight, ll num , ll is_dir){
    gr[v1] = (ll*) realloc( gr[v1] , sizeof(ll)*(ed_cnt[v1]*2+2) );    
    gr[v1][ed_cnt[v1]*2] = v2;
    gr[v1][ed_cnt[v1]*2+1] = weight;
    ed_num[v1] = (ll*) realloc( ed_num[v1] , sizeof(ll)*(ed_cnt[v1]+1) );
    ed_num[v1][ed_cnt[v1]] = num;
    ed_cnt[v1]++;

    if(!is_dir){
        gr[v2] = (ll*) realloc( gr[v2] , sizeof(ll)*(ed_cnt[v2]*2+2) );
        gr[v2][ed_cnt[v2]*2] = v1;
        gr[v2][ed_cnt[v2]*2+1] = weight;
        ed_num[v2] = (ll*) realloc( ed_num[v2] , sizeof(ll)*(ed_cnt[v2]+1) );
        ed_num[v2][ed_cnt[v2]] = num;
        ed_cnt[v2]++;
    }
}

ll c[115115],cc;

void dfs(ll from, ll x, ll col){
    rep(i,0,ed_cnt[x]){
        ll to=gr[x][i*2];
        if(to==from) continue;
        // printf("%lld %lld\n",ed_num[x][i],col);
        c[ ed_num[x][i] ]= col;
        col++;
        if(col>cc) col=1;
        dfs(x,to,col);
    }
}









char s[1151154];
void solve(){
    // fgets(s,sizeof(s),stdin); 
    ll n;
    ll ans=0;
    cin(&n);
    // scanf("%s",s);
    // ll ;
    ll a,b;
    rep(i,0,n-1){
        cin(&a); a--;
        cin(&b); b--;
        pushGraph(a,b,1,i,0);
    }
    rep(i,0,n){
        ans=max2(ans,ed_cnt[i]);
    }
    cc=ans;
    dfs(-1,0,1);
    printf("%lld\n",ans);
    rep(i,0,n-1){
        printf("%lld\n",c[i]);
    }
}

int main(void){
    ll T=1;
    // cin(&T);
    rep(i,0,T){ solve(); }
    return 0;
}


/*
    while (ng + 1 < ok) {
        ll p = ng + (ok - ng) / 2;
        ll cnt = 0;
        rep(i,0,n){
            cnt += (a[i] + p - 1) / p - 1;
        }
        if (cnt <= k) ok = p; else ng = p;
    }
*/
// 10^18 2^60 3^38 5^26


Measured memory_bytes: 12984