CodeEff/ECCO huggingface dataset:
# Original solution
#キューとdictionaryを利用したBFS
from collections import deque

n = int(eval(input()))

ab = [list(map(int,input().split())) for i in range(n-1)]

ver = [[] for i in range(n)]

for i in range(n-1):
    a,b = ab[i][0],ab[i][1]
    ver[a-1].append(b-1)
    ver[b-1].append(a-1)

#print(ver)

color = [dict() for i in range(n)]
q = deque()
i = 1
for v in ver[0]:
    color[0][v] = i
    color[v][0] = i
    q.append((0,v))
    i += 1

#print(q)

while q:
    f,t = q.popleft()
    i = 1
    for v in ver[t]:
        if v == f:
            continue
        if i == color[f][t]:
            i += 1
        color[t][v] = i
        color[v][t] = i
        q.append((t,v))
        i += 1

#print(color)
#辞書のリストで辺の色を管理している
k = 0
for i in range(n):
    k = max(k,len(ver[i]))
print(k)
for i in range(n-1):
    a,b = ab[i][0],ab[i][1]
    print((color[a-1][b-1]))


# Optimized solution
#d3と同一解法
n=int(eval(input()))
import sys
#再帰関数の再帰回数を変更
sys.setrecursionlimit(10**6)
s=[[] for _ in range(n)]

for i in range(n-1):
    a,b=list(map(int,input().split()))
    s[a-1].append((b-1,i))
    s[b-1].append((a-1,i))

l=[0]*(n-1)

def dfs(node,pre_col,par):
    col=1
    for nei,i in s[node]:
        if nei==par:
            continue
        if col==pre_col:
            col+=1
        l[i]=col
        dfs(nei,col,node)
        col+=1
dfs(0,-1,-1)
print((max(l)))
for i in l:
    print(i)
# Original solution
#d3と同一解法
n=int(eval(input()))
import sys
#再帰関数の再帰回数を変更
sys.setrecursionlimit(10**6)
s=[[] for _ in range(n)]

for i in range(n-1):
    a,b=list(map(int,input().split()))
    s[a-1].append((b-1,i))
    s[b-1].append((a-1,i))

l=[0]*(n-1)

def dfs(node,pre_col,par):
    col=1
    for nei,i in s[node]:
        if nei==par:
            continue
        if col==pre_col:
            col+=1
        l[i]=col
        dfs(nei,col,node)
        col+=1
dfs(0,-1,-1)
print((max(l)))
for i in l:
    print(i)


# Optimized solution
import sys
sys.setrecursionlimit(500000)
N = int(eval(input()))
E = [[] for _ in range(N+1)]
for i in range(N-1):
    a, b = list(map(int, input().split()))
    E[a].append((b, i))
    E[b].append((a, i))
K = max(len(e) for e in E)
print(K)
Ans = [-1] * (N-1)
def dfs(v=1, p=0, p_col=-1):
    col = 1
    for u, idx in E[v]:
        if u!=p: #木構造の逆向きの矢印を除くための条件
            if col == p_col:
                col += 1
            Ans[idx] = col
            #print(p_col)
            dfs(u, v, col) #u;調べる頂点 v;直前に調べた辺で、調べる頂点と結ばれている頂点　col;直前に調べた辺の色番号
            col += 1 #最深部まで調べたら デフォルトの色=最後に調べた辺の色+1とする
            #最深部に繋がった辺の色+1してやれば、次の辺の色は必ず条件を満たしてくれる

dfs()
print(("\n".join(map(str, Ans))))
# Original solution
# coding: utf-8
import sys
#from operator import itemgetter
sysread = sys.stdin.buffer.readline
read = sys.stdin.buffer.read
from heapq import heappop, heappush
from collections import defaultdict
sys.setrecursionlimit(10**7)
import math
#from itertools import product, accumulate, combinations, product
#import bisect
#import numpy as np
#from copy import deepcopy
#from collections import deque
#from decimal import Decimal
#from numba import jit

INF = 1 << 50
EPS = 1e-8
mod = 10 ** 9 + 7

def mapline(t = int):
    return list(map(t, sysread().split()))
def mapread(t = int):
    return list(map(t, read().split()))

def dfs(c, to, cols, max_counts, pre_col = 0):
    colors = set()
    colors.add(pre_col)
    for idx, n in to[c]:
        if cols[idx]:continue
        num = 1
        for i in range(num, max_counts+1):
            if not i in colors:
                num = i
                cols[idx] = i
                colors.add(i)
                dfs(n, to, cols, max_counts, i)
                break


def run():
    N = int(sysread())
    to = [[] for _ in range(N+1)]
    cols = [0] * (N-1)
    counts = [0 for i in range(N+1)]
    for i in range(N-1):
        a,b = mapline()
        to[a].append((i, b))
        to[b].append((i, a))
        counts[a] += 1
        counts[b] += 1

    max_counts = max(counts)
    print(max_counts)
    dfs(1, to, cols, max_counts)

    for c in cols:
        print(c)

    #print(a ^ b)
if __name__ == "__main__":
    run()


# Optimized solution
# coding: utf-8
import sys
#from operator import itemgetter
sysread = sys.stdin.buffer.readline
read = sys.stdin.buffer.read
from heapq import heappop, heappush
from collections import defaultdict
sys.setrecursionlimit(10**7)
import math
#from itertools import product, accumulate, combinations, product
#import bisect
#import numpy as np
#from copy import deepcopy
#from collections import deque
#from decimal import Decimal
#from numba import jit

INF = 1 << 50
EPS = 1e-8
mod = 10 ** 9 + 7

def mapline(t = int):
    return list(map(t, sysread().split()))
def mapread(t = int):
    return list(map(t, read().split()))

def dfs(c, to, cols, max_counts, pre_col = 0):
    colors = set()
    colors.add(pre_col)
    num = 1
    for idx, n in to[c]:
        if cols[idx]:continue
        for i in range(num, max_counts+1):
            if not i in colors:
                num = i
                cols[idx] = i
                colors.add(i)
                dfs(n, to, cols, max_counts, i)
                break


def run():
    N = int(sysread())
    to = [[] for _ in range(N+1)]
    cols = [0] * (N-1)
    counts = [0 for i in range(N+1)]
    for i in range(N-1):
        a,b = mapline()
        to[a].append((i, b))
        to[b].append((i, a))
        counts[a] += 1
        counts[b] += 1

    max_counts = max(counts)
    print(max_counts)
    dfs(1, to, cols, max_counts)

    for c in cols:
        print(c)

    #print(a ^ b)
if __name__ == "__main__":
    run()
# Original solution
from collections import deque


def solve(string):
    n, *ab = list(map(int, string.split()))
    next_ = [dict([]) for _ in range(n + 1)]
    queue = deque([1])
    for a, b in zip(*[iter(ab)] * 2):
        next_[a][b] = 0
        next_[b][a] = 0
    while len(queue) > 0:
        c = queue.popleft()
        _next = next_[c]
        use = set(range(1, len(list(_next.keys())) + 1)) - set(next_[c].values())
        for _n, u in zip((k for k, v in list(_next.items()) if v == 0), use):
            queue.append(_n)
            next_[c][_n] = u
            next_[_n][c] = u
    return str("{}\n{}".format(max([len(list(x.keys())) for x in next_]),
                               "\n".join(str(next_[a][b]) for a, b in zip(*[iter(ab)] * 2))))


if __name__ == '__main__':
    import sys
    print((solve(sys.stdin.read().strip())))


# Optimized solution
from collections import deque


def solve(string):
    n, *ab = list(map(int, string.split()))
    e = [[] for _ in range(n + 1)]
    q = deque([1])
    c = [0] * (n + 1)
    for a, b in zip(*[iter(ab)] * 2):
        e[a].append(b)
    while q:
        s = q.popleft()
        d = 0
        for t in e[s]:
            d += 1 + (d + 1 == c[s])
            c[t] = d
            q.append(t)
    return str("{}\n{}".format(max(c), "\n".join(str(c[b]) for _, b in zip(*[iter(ab)] * 2))))


if __name__ == '__main__':
    import sys
    print((solve(sys.stdin.read().strip())))
# Original solution
from collections import deque
N = int(input())
X = [list(map(int, input().split())) for _ in range(N - 1)]

graph = [[] for _ in range(N)]
tree = [[] for _ in range(N)]
for n, (i, j) in enumerate(X):
    graph[i - 1].append(j - 1)
    graph[j - 1].append(i - 1)
    
    tree[i - 1].append((n, j - 1))
    
K = max(len(x) for x in graph)
q = deque()
q.append((0, 0))
ans = [0] * (N - 1)

while len(q) > 0:
    # u: node number, c: color
    u, c = q.popleft()
    
    cnt = 1
    for i, (n, v) in enumerate(tree[u]):
        if cnt == c:
            cnt += 1

        ans[n] = cnt
        q.append((v, cnt))
        cnt += 1
        
print(K)
print(*ans, sep="\n")


# Optimized solution
from collections import deque
N = int(input())
X = [list(map(int, input().split())) for _ in range(N - 1)]

tree = [[] for _ in range(N)]
for n, (i, j) in enumerate(X):
    tree[i - 1].append((n, j - 1))

q = deque()
q.append((0, 0))
ans = [0] * (N - 1)

while len(q) > 0:
    # u: node number, c: color
    u, c = q.popleft()
    
    cnt = 1
    for i, (n, v) in enumerate(tree[u]):
        if cnt == c:
            cnt += 1

        ans[n] = cnt
        q.append((v, cnt))
        cnt += 1
        
print(max(ans))
print(*ans, sep="\n")
# Original solution
from collections import defaultdict
N = int(input())
tree = [[] for i in range(N)]  # 入力で与えられる木: [[to, 辺のindex],]
degrees = defaultdict(int)  # 各頂点の次数を記録

for i in range(N - 1):
    a, b = map(int, input().split())
    a, b = a - 1, b - 1
    tree[a].append([b, i])
    tree[b].append([a, i])
    degrees[a] += 1
    degrees[b] += 1


# 最大次数色使えば必ず塗り分けられる
ans_K = max(degrees.values())
ans_c = [-1] * (N - 1)


# [現在見ている頂点, 直前を何色で塗ったか]
stack = [[0, -1]]
visited = [False] * N
while stack:
    fr, pre_color = stack.pop()
    visited[fr] = True
    painting = 1  # これから何色で塗ろうとするか

    for to, index in tree[fr]:
        if visited[to]:
            continue

        if painting == pre_color:
            painting += 1

        ans_c[index] = painting
        stack.append([to, painting])

        # 塗ったら違う色に変える
        painting += 1


print(ans_K)
print(*ans_c, sep='\n')


# Optimized solution
N = int(input())
T = [[] for i in range(N)]
for i in range(N - 1):
    a, b = map(int, input().split())
    a, b = a - 1, b - 1

    # 辺のindexを持っておく
    T[a].append([b, i])
    T[b].append([a, i])


stack = [[0, 0]]  # [次の頂点番号, 親に続く辺の色]
visited = [0] * N
colors = [0] * (N - 1)
while stack:
    n, parent_color = stack.pop()
    visited[n] = 1
    color = 1

    for to, i in T[n]:
        if visited[to]:
            continue

        if color == parent_color:
            color += 1

        colors[i] = color
        stack.append([to, color])

        color += 1


print(len(set(colors)))
print(*colors, sep='\n')
# Original solution
import sys
input = sys.stdin.readline


def main():
    N = int(eval(input()))
    G = [[] for _ in range(N)]
    for i in range(N-1):
        a, b = list(map(int, input().split()))
        G[a-1].append((b-1, i))
        G[b-1].append((a-1, i))

    V = [[-1, -1] for _ in range(N)]  # 頂点の[親, 親への辺の色]
    ans = [-1]*(N-1)
    import collections
    Q = collections.deque()
    Q.append(0)
    while Q:
        i = Q.popleft()
        color = 0
        for c, ei in G[i]:
            if c == V[i][0]:
                continue
            V[c][0] = i
            color += 1
            if color == V[i][1]:
                color += 1
            V[c][1] = ans[ei] = color
            Q.append(c)
    print((max(ans)))
    print(('\n'.join(map(str, ans))))


if __name__ == '__main__':
    main()


# Optimized solution
import sys
input = sys.stdin.readline


def main():
    N = int(eval(input()))
    G = [[] for _ in range(N)]
    for i in range(N-1):
        a, b = list(map(int, input().split()))
        G[a-1].append((b-1, i))
        G[b-1].append((a-1, i))

    V = [[-1, -1] for _ in range(N)]  # 頂点の[親, 親への辺の色]
    ans = [-1]*(N-1)
    stack = [0]  # dfsになるはず（キューだとbfs）
    while stack:
        i = stack.pop()
        color = 0
        for c, ei in G[i]:
            if c == V[i][0]:
                continue
            V[c][0] = i
            color += 1
            if color == V[i][1]:
                color += 1
            V[c][1] = ans[ei] = color
            stack.append(c)
    print((max(ans)))
    print(('\n'.join(map(str, ans))))


if __name__ == '__main__':
    main()
# Original solution
from collections import deque
from copy import deepcopy

N=int(eval(input()))
a=[0]*(N-1)
b=[0]*(N-1)
c=[set() for _ in range(N)]
d=[set() for _ in range(N)] # 隣接リスト
e=[-1 for _ in range(N)] #訪問ずみかどうか
g=[[ 0 for _ in range(N)] for _ in range(N)]

for i in range(N-1):
    a[i],b[i] = list(map(int,input().split()))
    d[a[i]-1].add(b[i]-1)
    d[b[i]-1].add(a[i]-1)
f=deepcopy(d)
#print(f)

#x=0としてBFSする
v=deque([0])
e[0]=0

maxi=0
while len(v)>0:
  k=v.popleft()
  maxi=max(maxi,len(d[k]))
  all=set(i+1 for i in range(len(d[k])))
  pos=deepcopy(all)
  pos -= c[k]
  for item in d[k]:
    if e[item]==-1:
      s=min(pos)
      c[k].add(s)
      c[item].add(s)
      pos.remove(s)
      e[item] = e[k]+1
      v.append(item)
      g[k][item]=s
      g[item][k]=s
      
print(maxi)
for i in range(N-1):
  print(( g[a[i]-1][b[i]-1] ))


# Optimized solution
from collections import deque
from copy import deepcopy

N=int(eval(input()))
a=[0]*(N-1)
b=[0]*(N-1)
c=[set() for _ in range(N)]
d=[set() for _ in range(N)] # 隣接リスト
e=[-1 for _ in range(N)] #訪問ずみかどうか
di=dict()

for i in range(N-1):
    a[i],b[i] = list(map(int,input().split()))
    d[a[i]-1].add(b[i]-1)
    d[b[i]-1].add(a[i]-1)
f=deepcopy(d)

v=deque([0])
e[0]=0

maxi=0
while len(v)>0:
  k=v.popleft()
  maxi=max(maxi,len(d[k]))
  all=set(i+1 for i in range(len(d[k])))
  pos=deepcopy(all)
  pos -= c[k]
  for item in d[k]:
    if e[item]==-1:
      s=min(pos)
      c[k].add(s)
      c[item].add(s)
      pos.remove(s)
      e[item] = e[k]+1
      v.append(item)
      st=str(k)+","+str(item)
      di[st] = s
      
print(maxi)
for i in range(N-1):
  t_str = str(a[i]-1)+","+str(b[i]-1)
  print((di[t_str]))
# Original solution
from collections import deque

n=int(eval(input()))
l=[list(map(int,input().split())) for i in range(n-1)]

tree=[[]for _ in range(n)]
for a,b in l:
  a-=1
  b-=1
  tree[a].append(b)
  tree[b].append(b)

ans_num=0
for i in tree:
  ans_num=max(ans_num,len(i))

dq=deque()
dq.append((0,0))

seen=set()
seen.add(0)

ans_dict={}
while dq:
  x,color=dq.popleft()

  i=0
  for nx in tree[x]:
    if nx in seen:
      continue

    i+=1
    if i==color:
      i+=1

    seen.add(nx)
    dq.append((nx,i)),
    ans_dict[x+1,nx+1]=i
    ans_dict[nx+1,x+1]=i

print(ans_num)
for i in l:
  print((ans_dict[tuple(i)]))

# Optimized solution
from collections import deque
from sys import stdin
nii=lambda:list(map(int,stdin.readline().split()))

n=int(eval(input()))
l=[list(nii()) for i in range(n-1)]

tree=[[]for _ in range(n)]
for a,b in l:
  a-=1
  b-=1
  tree[a].append(b)
  tree[b].append(b)

ans_num=0
for i in tree:
  ans_num=max(ans_num,len(i))

dq=deque()
dq.append((0,0))

seen=set()
seen.add(0)

ans_dict={}
while dq:
  x,color=dq.pop()

  i=0
  for nx in tree[x]:
    if nx in seen:
      continue

    i+=1
    if i==color:
      i+=1

    seen.add(nx)
    dq.append((nx,i)),
    ans_dict[x+1,nx+1]=i
    ans_dict[nx+1,x+1]=i

print(ans_num)
for i in l:
  print((ans_dict[tuple(i)]))
# Original solution
n=int(eval(input()))
ab=[]
p=[-1 for i in range(n+1)]
edge=[[0 for i in range(n+1)] for j in range(n+1)]
G=[[] for i in range(n+1)]
used=[0 for i in range(n+1)]
for i in range(n-1):
    ab.append(list(map(int,input().split())))
    G[ab[i][0]].append(ab[i][1])
    G[ab[i][1]].append(ab[i][0])

max_n=0

for i in range(n+1):
    tmp=len(G[i])
    if tmp>max_n:
        max_n=tmp
        top=i

queue=[]
queue.append(top)

while len(queue)>0:
    num=queue.pop(0)
    used[num]=1
    color=1
    for i in range(len(G[num])):
        if used[G[num][i]]==0:
            if p[num]==color:
                color+=1
                edge[num][G[num][i]]=color
                edge[G[num][i]][num]=color
                p[G[num][i]]=color
                queue.append(G[num][i])
            else:
                edge[num][G[num][i]]=color
                edge[G[num][i]][num]=color
                p[G[num][i]]=color
                queue.append(G[num][i])
            color+=1

print(max_n)
for i in range(n-1):

    print((edge[ab[i][0]][ab[i][1]]))

        




# Optimized solution
n=int(eval(input()))
ab=[]
p=[-1 for i in range(n+1)]
edge={}
G=[[] for i in range(n+1)]
used=[0 for i in range(n+1)]
for i in range(n-1):
    ab.append(list(map(int,input().split())))
    G[ab[i][0]].append(ab[i][1])
    G[ab[i][1]].append(ab[i][0])

max_n=0

for i in range(n+1):
    tmp=len(G[i])
    if tmp>max_n:
        max_n=tmp
        top=i

queue=[]
queue.append(top)

while len(queue)>0:
    num=queue.pop(0)
    used[num]=1
    color=1
    for i in range(len(G[num])):
        if used[G[num][i]]==0:
            if p[num]==color:
                color+=1
                edge["{},{}".format(num,G[num][i])]=color
                edge["{},{}".format(G[num][i],num)]=color
                p[G[num][i]]=color
                queue.append(G[num][i])
            else:
                edge["{},{}".format(num,G[num][i])]=color
                edge["{},{}".format(G[num][i],num)]=color
                p[G[num][i]]=color
                queue.append(G[num][i])
            color+=1

print(max_n)
for i in range(n-1):

    print((edge["{},{}".format(ab[i][0],ab[i][1])]))
# Original solution
import sys
input = sys.stdin.readline
from collections import Counter
from collections import deque


def main():
    N = int(eval(input()))
    C = []
    T = [[] for j in range(N + 1)]
    for i in range(N - 1):
        a, b = [int(x) for x in input().split()]
        T[a].append([b, i])
        T[b].append([a, i])
        C.append(a)
        C.append(b)
    
    c = Counter(C)
    print((c.most_common(1)[0][1]))

    q = deque()
    q.append([1, 0])


    visited = set()
    ans = [0] * N

    while q:
        i, color = q.popleft()
        visited.add(i)
        now_color = 0
        for v, j in T[i]:
            if not v in visited:
                now_color += 1
                if now_color == color:
                    now_color += 1
                q.append([v, now_color])
                ans[j] = now_color
    
    for i in range(N - 1):
        print((ans[i]))



    

    



if __name__ == '__main__':
    main()


# Optimized solution
import sys
input = sys.stdin.readline
from collections import deque


def main():
    N = int(eval(input()))
    C = []
    T = [[] for j in range(N + 1)]
    for i in range(N - 1):
        a, b = [int(x) for x in input().split()]
        T[a].append([b, i])
        T[b].append([a, i])
        C.append(a)
        C.append(b)
    

    q = deque()
    q.append([1, 0])

    visited = set()
    ans = [0] * N
    while q:
        i, color = q.popleft()
        visited.add(i)
        now_color = 0
        for v, j in T[i]:
            if not v in visited:
                now_color += 1
                if now_color == color:
                    now_color += 1
                q.append([v, now_color])
                ans[j] = now_color
    
    print((max(ans)))
    for i in range(N - 1):
        print((ans[i]))



    

    



if __name__ == '__main__':
    main()
# Original solution
def resolve():
    N = int(eval(input()))
    g = {}
    edges = []
    for _ in range(N-1):
        a, b = list(map(int, input().split()))
        g.setdefault(a-1, [])
        g[a-1].append(b-1)
        g.setdefault(b-1, [])
        g[b-1].append(a-1)
        edges.append((a-1, b-1))

    nodes = [(None, 0)]
    colors = [[None for _ in range(N)] for _ in range(N)]
    maxdeg = 0
    while nodes:
        prevcol, node = nodes.pop()
        maxdeg = max(maxdeg, len(g[node]))
        #print(colors)
        #print(prev, node, prevcol)
        #print(cols)
        idx = 0
        for col in range(1, len(g[node])+1):
            if col == prevcol:
                continue
            nxt = g[node][idx] 
            if colors[node][nxt] is not None:
                idx += 1
                if idx >= len(g[node]):
                    break
                nxt = g[node][idx]
            colors[node][nxt] = col
            colors[nxt][node] = col
            nodes.append((col, nxt))
            idx += 1
            if idx >= len(g[node]):
                break
            
    
    print(maxdeg)
    for src, dst in edges:
        print((colors[src][dst]))
            
            




if '__main__' == __name__:
    resolve()


# Optimized solution
def resolve():
    N = int(eval(input()))
    g = {}
    edges_to_idx = {}
    edges = []
    for i in range(N-1):
        a, b = list(map(int, input().split()))
        g.setdefault(a-1, [])
        g[a-1].append(b-1)
        g.setdefault(b-1, [])
        g[b-1].append(a-1)
        edges_to_idx.setdefault("{}-{}".format(a-1, b-1), i)
        edges_to_idx.setdefault("{}-{}".format(b-1, a-1), i)
        edges.append((a-1, b-1))

    nodes = [(None, 0)]
    colors = [None for _ in range(N-1)]
    maxdeg = 0
    while nodes:
        prevcol, node = nodes.pop()
        maxdeg = max(maxdeg, len(g[node]))
        idx = 0
        for col in range(1, len(g[node])+1):
            if col == prevcol:
                continue
            nxt = g[node][idx]
            coloridx = edges_to_idx["{}-{}".format(node, nxt)] 
            if colors[coloridx] is not None:
                idx += 1
                if idx >= len(g[node]):
                    break
                nxt = g[node][idx]
                coloridx = edges_to_idx["{}-{}".format(node, nxt)] 
            colors[coloridx] = col
            nodes.append((col, nxt))
            idx += 1
            if idx >= len(g[node]):
                break
            
    
    print(maxdeg)
    for col in colors:
        print(col)
            
            




if '__main__' == __name__:
    resolve()
# Original solution
def resolve():
    N = int(eval(input()))
    g = {}
    edges_to_idx = {}
    edges = []
    for i in range(N-1):
        a, b = list(map(int, input().split()))
        g.setdefault(a-1, [])
        g[a-1].append(b-1)
        g.setdefault(b-1, [])
        g[b-1].append(a-1)
        edges_to_idx.setdefault("{}-{}".format(a-1, b-1), i)
        edges_to_idx.setdefault("{}-{}".format(b-1, a-1), i)
        edges.append((a-1, b-1))

    nodes = [(None, 0)]
    colors = [None for _ in range(N-1)]
    maxdeg = 0
    while nodes:
        prevcol, node = nodes.pop()
        maxdeg = max(maxdeg, len(g[node]))
        idx = 0
        for col in range(1, len(g[node])+1):
            if col == prevcol:
                continue
            nxt = g[node][idx]
            coloridx = edges_to_idx["{}-{}".format(node, nxt)] 
            if colors[coloridx] is not None:
                idx += 1
                if idx >= len(g[node]):
                    break
                nxt = g[node][idx]
                coloridx = edges_to_idx["{}-{}".format(node, nxt)] 
            colors[coloridx] = col
            nodes.append((col, nxt))
            idx += 1
            if idx >= len(g[node]):
                break
            
    
    print(maxdeg)
    for col in colors:
        print(col)
            
            




if '__main__' == __name__:
    resolve()


# Optimized solution
def resolve():
    N = int(eval(input()))
    g = {}
    for i in range(N-1):
        a, b = list(map(int, input().split()))
        g.setdefault(a-1, [])
        g[a-1].append((b-1, i))
        g.setdefault(b-1, [])
        g[b-1].append((a-1, i))
        
    nodes = [(None, 0)]
    colors = [None for _ in range(N-1)]
    maxdeg = 0
    while nodes:
        prevcol, node = nodes.pop()
        maxdeg = max(maxdeg, len(g[node]))
        color = 1 if prevcol != 1 else 2
        for nxt, colidx in g[node]:
            if colors[colidx] is None:
                colors[colidx] = color
                nodes.append((color, nxt))
                color += 1 if prevcol != color+1 else 2

    print(maxdeg)
    for col in colors:
        print(col)
            



if '__main__' == __name__:
    resolve()