CodeEff/ECCO huggingface dataset:
# Original solution
from collections import deque

N = int(eval(input()))
AB = [list(map(int, input().split())) for _ in range(N-1)]
con = [set() for _ in range(N+1)]
res = {}

for ab in AB:
    con[ab[0]].add(ab[1])
    con[ab[1]].add(ab[0])
    res[tuple(ab)] = 0

max_len = 0
for i, c in enumerate(con):
    if max_len <= len(c):
        max_len = len(c)
        max_ind = i

colors = [set() for i in range(N+1)]
all_colors = set([i for i in range(1, max_len+1)])
q = deque()
q.append(max_ind)
node_state = [0]*(N+1)

while q != deque():
    v = q.pop()
    node_state[v] = 1
    for next_v in con[v]:
        if node_state[next_v] == 0:
            q.appendleft(next_v)
        if v < next_v:
            va = v
            vb = next_v
        else:
            va = next_v
            vb = v
        if res[(va, vb)] == 0:
            color = list(all_colors.difference(colors[va].union(colors[vb])))[0]
            res[(va, vb)] = color
            colors[va].add(color)
            colors[vb].add(color)

print(max_len)
for i in range(N-1):
    print((res[tuple(AB[i])]))

# Optimized solution
N = int(eval(input()))
AB = [list(map(int, input().split())) for _ in range(N-1)]
sortedAB = sorted(AB)
con = {i: [] for i in range(1, N+1)}
color = [0] * (N + 1)
for a, b in sortedAB:
    con[a].append(b)

for i in range(1, N + 1):
    now_c = 1
    for c in con[i]:
        if color[i] == now_c:
            now_c += 1
        color[c] = now_c
        now_c += 1

print((max(color)))
for i in range(N-1):
    print((color[AB[i][1]]))

a = 0
# Original solution
import sys
sys.setrecursionlimit(1000000000)
input = sys.stdin.readline
n=int(eval(input()))
es=[[] for i in range(n)]
l=[list(map(int,input().split())) for i in range(n-1)]
for i in range(n-1):
   l[i][0]-=1
   l[i][1]-=1
   l[i][0],l[i][1]=min(l[i][0],l[i][1]),max(l[i][0],l[i][1])
   es[l[i][0]].append(l[i][1])
   es[l[i][1]].append(l[i][0])
dic={}
use=[1]*n
def dfs(v,k):
    cnt=0
    use[v]=0
    for i in es[v]:
        if use[i]:
            if cnt==k:
                cnt+=1
            dic[(min(v,i),max(v,i))]=cnt
            dfs(i,cnt)
            cnt+=1
dfs(0,-1)
ans=[0]*(n-1)
k=0
for i in range(n-1):
    ans[i]=dic[l[i][0],l[i][1]]+1
    k=max(k,ans[i])
print(k)
for i in ans:
    print(i)

# Optimized solution
import sys
sys.setrecursionlimit(1000000000)
input = sys.stdin.readline
n=int(eval(input()))
es=[[] for i in range(n)]
l=[list(map(int,input().split())) for i in range(n-1)]
for i in range(n-1):
   l[i][0]-=1
   l[i][1]-=1
   es[l[i][0]].append(l[i][1])
   es[l[i][1]].append(l[i][0])
dic={}
use=[1]*n
def dfs(v,k):
    cnt=0
    use[v]=0
    for i in es[v]:
        if use[i]:
            if cnt==k:
                cnt+=1
            dic[(min(v,i),max(v,i))]=cnt
            dfs(i,cnt)
            cnt+=1
dfs(0,-1)
ans=[0]*(n-1)
k=0
for i in range(n-1):
    ans[i]=dic[l[i][0],l[i][1]]+1
    k=max(k,ans[i])
print(k)
for i in ans:
    print(i)
# Original solution
from collections import deque
import copy

n = int(eval(input()))
Adj_dict = {x:[] for x in range(1,n+1)}
AB = []
for _ in range(n-1):
    a, b = list(map(int, input().split()))
    Adj_dict[a].append(b)
    Adj_dict[b].append(a)
    AB.append([a,b])

max_edges = 0
node_max_edges = 0
for key, value in list(Adj_dict.items()):
    edges = len(value)
    if edges >= max_edges:
        max_edges = edges
        node = key

dq = deque()
dq.append(node)

Visited = [False for _ in range(n+1)]
Visited[node] = True
Visited_to = [[] for _ in range(n+1)]

Colors = [x for x in range(1, max_edges+1)]
Colors_list = [[x for x in range(1, max_edges+1)] for x in range(n+1)]
Edge_colors = [[-1 for _ in range(n+1)] for _ in range(n+1)]

# print(Colors_list)

while dq:
    # Colors_copy = copy.deepcopy(Colors)    
    node = dq.popleft()
    Next_nodes = Adj_dict[node]

    # for v in Visited_from:
    #     Colors_copy.remove(Edge_colors[node][v])

    for next_node in Next_nodes:
        if Visited[next_node] == True:
            continue
        dq.append(next_node)
        Visited_to[next_node].append(node)
        Visited[next_node] = True

        use_color = Colors_list[node][0]
        Colors_list[node].remove(use_color)
        Colors_list[next_node].remove(use_color)

        Edge_colors[node][next_node] = use_color
        Edge_colors[next_node][node] = use_color

 #       del Colors_copy[0]

print(max_edges)
for ab in AB:
    print((Edge_colors[ab[0]][ab[1]]))

# Optimized solution
from collections import deque

n = int(eval(input()))
Adj_dict = {x:[] for x in range(1,n+1)}
AB_dict = {}
AB = []
for _ in range(n-1):
    a, b = list(map(int, input().split()))
    Adj_dict[a].append(b)
    Adj_dict[b].append(a)
    AB.append([a,b])
    AB_dict.update({str(a)+'_'+str(b):0})

max_edges = 0
node_max_edges = 0
for key, value in list(Adj_dict.items()):
    edges = len(value)
    if edges >= max_edges:
        max_edges = edges
        node = key

dq = deque()
dq.append(1)

Visited = [False for _ in range(n+1)]
Visited[1] = True
Colors = [0 for _ in range(n+1)]

while dq:
    c = 1
    node = dq.popleft()
    Next_nodes = Adj_dict[node]

    for next_node in Next_nodes:
        if Visited[next_node] == True:
            continue
        dq.append(next_node)
        Visited[next_node] = True

        if c == Colors[node]:
            c += 1
        Colors[next_node] = c
        c += 1
        if node < next_node:
            AB_dict[str(node)+'_'+str(next_node)] = Colors[next_node]
        else:
            AB_dict[str(next_node)+'_'+str(node)] = Colors[next_node]

print(max_edges)
for ab in AB:
    a = ab[0]
    b = ab[1]
    print((AB_dict[str(a)+'_'+str(b)]))
# print(AB_dict)
# Original solution
import queue
n = int(eval(input()))

#ab = [[]*(n)]
ab = [[] for _ in range(n+1)]
#print(ab)

li = []

for i in range(n-1):
    a,b = list(map(int,input().split()))
    ab[a].append(b)
    ab[b].append(a)
    li.append([a,b])
    
ab_color = [[0 for _ in range(n+1)] for _ in range(n+1)]

#print(li)

q = queue.Queue()
check = [0] * (n+1)
#check[1] == 1
check_color = [0] * (n+1)

q.put(1)
color_num = 1
#mae_color = 0

while not q.empty():
    tmp_color = 0
    tmp = q.get()
    #print(tmp)
    #tmp_color = mae_color
    mae_color = check_color[tmp]
    for i in range(len(ab[tmp])):
        if check[ab[tmp][i]] == 1:
            #print(i,tmp)
            continue
        else:
            #print(mae_color,tmp_color,tmp,i)
            tmp_color += 1
            q.put(ab[tmp][i])
            if tmp_color == mae_color:
                tmp_color += 1
            check_color[ab[tmp][i]] = tmp_color
            ab_color[ab[tmp][i]][tmp] = tmp_color
            ab_color[tmp][ab[tmp][i]] = tmp_color
            check[tmp] = 1
            if color_num < tmp_color:
                color_num = tmp_color
            #color_num = max(color_num,tmp_color)
            #print(check,i)

print(color_num)
for i in range(len(li)):
    print((ab_color[li[i][0]][li[i][1]]))

# Optimized solution
import queue
n = int(eval(input()))


#ab = [[]*(n)]
ab = [[] for _ in range(n+1)]
#print(ab)

li = []

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

#ab_color = [[None for _ in range(n+1)] for _ in range(n+1)]
ans = [0] * (n-1)

q = queue.Queue()
check = [0] * (n+1)
#check[1] == 1
check_color = [0] * (n+1)

q.put(1)
color_num = 1
#mae_color = 0

while not q.empty():
    tmp_color = 0
    tmp = q.get()
    #print(tmp)
    #tmp_color = mae_color
    mae_color = check_color[tmp]
    for i in range(len(ab[tmp])):
        if check[ab[tmp][i][0]] == 1:
            #print(i,tmp)
            continue
        else:
            #print(mae_color,tmp_color,tmp,i)
            tmp_color += 1
            q.put(ab[tmp][i][0])
            if tmp_color == mae_color:
                tmp_color += 1
            check_color[ab[tmp][i][0]] = tmp_color
            ans[ab[tmp][i][1]] = tmp_color
            #ab_color[ab[tmp][i]][tmp] = tmp_color
            #ab_color[tmp][ab[tmp][i]] = tmp_color
            check[tmp] = 1
            if color_num < tmp_color:
                color_num = tmp_color
            #color_num = max(color_num,tmp_color)
            #print(check,i)

print(color_num)
for i in range(len(ans)):
    print((ans[i]))
# Original solution
if __name__ == "__main__":
    import sys
    from collections import deque
    input = sys.stdin.readline
    N = int(eval(input()))
    edges = [[] for _ in range(N)]
    for i in range(N-1):
        a,b = list(map(int,input().split()))
        a -= 1
        b -= 1
        edges[a].append((b,i))
        edges[b].append((a,i))

    color = [None]*(N-1)
    SIZE = 1
    q = deque([(0,None)])
    while q:
        v, prev_color = q.popleft()
        colors = list(range(1,SIZE+1))
        if prev_color:
            colors.remove(prev_color)
        for w, i in edges[v]:
            if not color[i]:
                if colors:
                    color[i] = colors.pop(0)
                else:
                    SIZE += 1
                    color[i] = SIZE
                q.append((w,color[i]))
    print(SIZE)
    for n in range(N-1):
        print((color[n]))

# Optimized solution
if __name__ == "__main__":
    import sys
    from collections import deque
    input = sys.stdin.readline
    N = int(eval(input()))
    edges = [[] for _ in range(N)]
    for i in range(N-1):
        a,b = list(map(int,input().split()))
        a -= 1
        b -= 1
        edges[a].append((b,i))
        edges[b].append((a,i))

    color = [None]*(N-1)
    SIZE = 1
    q = deque([(0,None)])
    while q:
        v, prev_color = q.popleft()
        c = 1
        for w, i in edges[v]:
            if not color[i]:
                if c == prev_color:
                    c += 1
                color[i] = c
                c += 1
                q.append((w,color[i]))
        SIZE = max(SIZE, c-1)
    print(SIZE)
    for n in range(N-1):
        print((color[n]))
# Original solution
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))

vc=[[] for _ in range(n)]
ec=[-1]*(n-1)
for p,ci in enumerate(g):
    for c, i in ci:
        color = 1
        while True:
            if color not in vc[p]:
                vc[p].append(color)
                vc[c].append(color)
                ec[i] = color
                break
            else:
                color += 1
        

print((max(ec)))
for i in range(n-1):
    print((ec[i]))


# Optimized solution
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))

vc=[0] * n
ec=[-1]*(n-1)
for p,ci in enumerate(g):
    color = 1
    for c, i in ci:
        if vc[p] == color:
            color += 1
        vc[c] = color
        ec[i] = color
        color += 1
        

print((max(ec)))
for i in range(n-1):
    print((ec[i]))
# Original solution
import sys
from heapq import heappop as p
sys.setrecursionlimit(9**9)
n=int(eval(input()))
T=[[] for _ in range(n)]
for i in range(n-1):
    a,b=list(map(int,input().split()))
    T[a-1].append([b-1,i])
C=[0]*(n-1)
def f(Q):
    R=[]
    for q in Q:
        H=list(range(1,n))
        for t in T[q[0]]:
            x=p(H)
            if x==q[1]:
                x=p(H)
            C[t[1]]=x
            if len(T[t[0]])!=0:
            	R.append([t[0],x])
    if len(R)!=0:
    	return f(R)
f([[0,0]])
print((max(C)))
for c in C:
    print(c)

# Optimized solution
import sys
sys.setrecursionlimit(9**9)
n=int(eval(input()))
T=[[] for _ in range(n)]
for i in range(n-1):
    a,b=list(map(int,input().split()))
    T[a-1].append([b-1,i])
C=[0]*(n-1)
def f(i,r):
    c=1
    for (x,y) in T[i]:
        c+=(c==r)
        C[y]=c
        f(x,c)
        c+=1
f(0,0)
print((max(C)))
for c in C:
    print(c)
# Original solution
from collections import deque

def bfs(idx,k):
  q = deque()
  visited[idx] = True
  q.append(idx)
  color = 0
  while q:
    r = q.pop()
    ver = set(graph[r].keys())
    col = [i for i in range(k) if i not in set(graph[r].values())]
    i = 0
    for n in ver:
      if not visited[n]:
        graph[r][n] = col[i]
        graph[n][r] = col[i]
        i = (i+1)%len(col)

        visited[n] = True
        q.append(n)

        
N = int(eval(input()))
graph = {}
visited = [False]*(N+1)
for i in range(N+1):
  graph[i] = {}
ab = []
for i in range(N-1):
  a,b = list(map(int,input().split()))
  ab.append((a,b))
  graph[a][b] = -1
  graph[b][a] = -1
  
k = max([len(graph[i]) for i in range(1,N+1)])

bfs(1,k)
print(k)
for a,b in ab:
  print((graph[a][b]+1))

  


  


# Optimized solution
from collections import deque

def bfs(idx,k,colored):
  q = deque()
  visited[idx] = True
  q.append(idx)
  while q:
    r = q.pop()
    color = 0
    for n in list(graph[r].keys()):
      if not visited[n]:
        if color == colored[r]: color+=1
        colored[n] = color
        graph[r][n] = color
        graph[n][r] = color
        color += 1

        visited[n] = True
        q.append(n)

        
N = int(eval(input()))
graph = {}
colored = [-1]*(N+1)
visited = [False]*(N+1)
for i in range(N+1):
  graph[i] = {}
ab = []
for i in range(N-1):
  a,b = list(map(int,input().split()))
  ab.append((a,b))
  graph[a][b] = -1
  graph[b][a] = -1
  
k = max([len(graph[i]) for i in range(1,N+1)])

bfs(1,k,colored)
print(k)
for a,b in ab:
  print((graph[a][b]+1))
# Original solution
from collections import deque
 
n = int(eval(input()))
node_list = []
nodes = [[] for _ in range(n)]
edges = dict()
for _ in range(n - 1):
	a, b = list(map(int, input().split()))
	node_list.append((a - 1, b - 1))
	nodes[a - 1].append(b - 1)
	nodes[b - 1].append(a - 1)
	edges[(a - 1, b - 1)] = 0
 
used_colors = [[] for _ in range(n)]
used = [False] * n
que = deque()
que.append(0)
while len(que) > 0:
	ni = que.pop()
	for node in nodes[ni]:
		[a, b] = sorted([ni, node])
		if edges[(a, b)] == 0:
			for color in range(1, n):
				if not color in used_colors[a] and not used_colors[b]:
					break
			edges[(a, b)] = color
			used_colors[a].append(color)
			used_colors[b].append(color)
		if not used[node]:
			que.append(node)
 
	used[ni] = True
 
print((max(edges.values())))
for node in node_list:
	print((edges[node]))

# Optimized solution
from collections import deque

n = int(eval(input()))
nodes = [[] for _ in range(n)]
node_list = []
for _ in range(n - 1):
	a, b = list(map(int, input().split()))
	nodes[a - 1].append(b - 1)
	node_list.append(b - 1)
 
que = deque([0])
ans = [0] * n
while len(que) > 0:
	ni = que.pop()
	color = 1
	for node in nodes[ni]:
		if color == ans[ni]:
			color += 1
		ans[node] = color
		color += 1
		que.append(node)
 
print((max(ans)))
for node in node_list:
	print((ans[node]))
# Original solution
N = int(eval(input()))
A,B = [0]*(N-1),[0]*(N-1)
for i in range(N-1):
    array = list(map(int,input().split()))
    A[i] = array[0]
    B[i] = array[1]
from collections import defaultdict as ddict
children = ddict(list)
for a,b in zip(A,B):
    children[a].append(b)
ans = ddict(int)
for child in sorted(children.keys()):
    used = [False]*100000
    used[ans[child]-1] = True
    for j in sorted(children[child]):
        temp = used.index(False)+1
        ans[j] = temp
        used[temp-1] = True
ans2 = [ans[b] for b in B]
print((max(ans2)))
for a in ans2:
    print(a)


# Optimized solution
N = int(eval(input()))
AB = [[]]*(N-1)
for i in range(N-1):
    AB[i] = list(map(int,input().split()))
from collections import defaultdict as ddict
from collections import deque
tree = ddict(list)
B = [0]*(N-1)
for i,ab in enumerate(AB):
    tree[ab[0]].append(ab[1])
    B[i] = ab[1]
# 各エッジの色を格納する変数の初期化
# C[0]は使わない
C = [0]*N
# 幅優先探索用のcue
Q = deque([1])
while Q:
    q = Q.popleft()
    c = 0
    for w in tree[q]:
        # 色をインクリメントした際に親の色とかぶったら更に1を加算する
        # 他は単純なインクリメント
        c += 1 + int(C[q-1] == c+1)
        # エッジの色を格納
        C[w-1] = c
        # 子供をcueに追加
        Q.append(w)
print((max(C)))
for b in B:
    print((C[b-1]))
# Original solution
import sys
sys.setrecursionlimit(10**9)

N = int(input())

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

ans = [None]*(N-1)

# 引数：今回の基準頂点、前回の基準頂点と今回の頂点を結ぶ辺の色番号
def func(ver, color):
    # 色番号。まずは最低の番号から始める。もし今回と前回の基準頂点の色番号1の場合は後で色番号変更
    cnt = 1
    # for (基準頂点と繋がっている頂点, 辺の番号) in 基準頂点
    for (to, i) in G[ver]:
        # 既使用（前回の基準頂点と今回の頂点を結ぶ辺の色）と今回使う色番号が同じなら+1で色番号変更
        if cnt==color:
            cnt += 1
        # i番目の辺における色番号
        ans[i] = cnt
        # 今回の頂点と、今回の頂点と基準頂点の辺の色番号を入力し、今回の頂点を次の基準頂点にする
        func(to, cnt)
        # 今回の基準頂点と繋がる次の頂点の処理をするために色番号変更
        cnt += 1

func(0, 0)

print(max(ans))

print(*ans, sep="\n")


# Optimized solution
import sys
sys.setrecursionlimit(10**9)

N= int(eval(input()))

G = [[] for i in range(N)]

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

ans = [None]*(N-1)

def func(prt, col):
    cnt = 1
    for cld, org in G[prt]:
        if cnt==col:
            cnt += 1
        ans[org] = cnt
        func(cld, cnt)
        cnt += 1

func(0, 0)

print((max(ans)))
for i in range(N-1):
    print((ans[i]))
# Original solution
import copy

n=int(eval(input()))
org=[i for i in range(1,10**5)]
org_set=set(org)
edges=[]
colors=[]
for i in range(n-1):
    a,b=list(map(int,input().split(" ")))
    edges.append([a,b])
    colors.append([])
colors.append([])
colors.append([])

ans=[]
for i in edges:
    color_sum=set(colors[i[0]]+colors[i[1]])
    tmp_org=org_set.copy()
    for j in color_sum:
        tmp_org.remove(j)
    org_ls=list(tmp_org)
    colors[i[0]].append(org_ls[0])
    colors[i[1]].append(org_ls[0])
    ans.append(org_ls[0])

print((max(ans)))
for i in ans:
    print(i)


# Optimized solution
import copy

n=int(eval(input()))
org_set=set([i for i in range(1,10**5)])
edges=[]
relations={}
nodes=[]
for i in range(n-1):
    a,b=list(map(int,input().split(" ")))
    edges.append([a,b])
    relations.setdefault(a,[]).append(b)
    nodes.append([])
nodes.append([])
nodes.append([])

max_color=0
for start in range(1,n+1):
    targets=relations.get(start,[])
    color=1
    for target in targets:
        if color in nodes[start]:
            color+=1
        else:
            pass
        nodes[target].append(color)
        if color>=max_color:
            max_color=color
        color+=1

print(max_color)
for edge in edges:
    print((nodes[edge[1]][0]))
# Original solution
import copy

n=int(eval(input()))
org_set=set([i for i in range(1,10**5)])
edges=[]
relations={}
nodes=[]
for i in range(n-1):
    a,b=list(map(int,input().split(" ")))
    edges.append([a,b])
    relations.setdefault(a,[]).append(b)
    nodes.append([])
nodes.append([])
nodes.append([])

max_color=0
for start in range(1,n+1):
    targets=relations.get(start,[])
    color=1
    for target in targets:
        if color in nodes[start]:
            color+=1
        else:
            pass
        nodes[target].append(color)
        if color>=max_color:
            max_color=color
        color+=1

print(max_color)
for edge in edges:
    print((nodes[edge[1]][0]))

# Optimized solution
n=int(eval(input()))
edges=[]
relations={}
nodes=[0,0]
for i in range(n-1):
    a,b=list(map(int,input().split(" ")))
    edges.append([a,b])
    relations.setdefault(a,[]).append(b)
    nodes.append(0)

max_color=0
for start in range(1,n+1):
    targets=relations.get(start,[])
    color=1
    for target in targets:
        if color == nodes[start]:
            color+=1
        else:
            pass
        nodes[target]=color
        if color>=max_color:
            max_color=color
        color+=1

print(max_color)
for edge in edges:
    print((nodes[edge[1]]))
# Original solution
import sys
sys.setrecursionlimit(200000)
N = int(eval(input()))
ans = [0] * (N - 1)
AB = []
for i in range(N-1):
    a,b = list(map(int,input().split()))
    AB.append([a-1,b-1])
G = [list() for _ in range(N)]
for i in range(N-1):
    G[AB[i][1]].append([AB[i][0],i])
    G[AB[i][0]].append([AB[i][1],i])

def dfs(v,c = -1,p = -1):
    k = 1
    for i in range(len(G[v])):
        u = G[v][i][0];ei = G[v][i][1]
        if u == p:continue
        if k == c:
            k += 1
        ans[ei] = k
        k += 1
        dfs(u,ans[ei],v)
dfs(0)
mx = 0
for i in range(N):
    mx = max(mx,len(G[i]))
print(mx)
for i in range(N-1):
    print((ans[i]))

# Optimized solution
import sys
sys.setrecursionlimit(200000)
N = int(eval(input()))
ans = [0] * (N - 1)
G = [list() for _ in range(N)]

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

def dfs(v,c = -1,p = -1):
    k = 1
    for i in range(len(G[v])):
        u = G[v][i][0];ei = G[v][i][1]
        if u == p:continue
        if k == c:
            k += 1
        ans[ei] = k
        k += 1
        dfs(u,ans[ei],v)

dfs(0)
mx = 0

for i in range(N):
    mx = max(mx,len(G[i]))
print(mx)

for i in range(N-1):
    print((ans[i]))
# Original solution
# -*- coding: utf-8 -*-

from collections import deque

def main():
    input_buffer = """
    """
    #8
    #1 2
    #2 3
    #2 4
    #2 5
    #4 7
    #5 6
    #6 8
    
    INPUT = list(reversed(input_buffer.strip().splitlines()))
    if INPUT:
        n = int(INPUT.pop())
        edges = [0] * (n-1)
        for i in range(n-1):
            edges[i] = tuple(map(int, INPUT.pop().split()))
    else:
        n = int(eval(input()))
        edges = [0] * (n-1)
        for i in range(n-1):
            edges[i] = tuple(map(int, input().split()))
        
    
    adjacency_list = [[] for i in range(n+1)]
    for edge in edges:
        adjacency_list[edge[0]].append(edge[1])
        adjacency_list[edge[1]].append(edge[0])
    
    
    max_order = max(len(i) for i in adjacency_list)
    root = 0
    for i in range(0, n+1):
        if len(adjacency_list[i]) == max_order:
            root = i
                 
    
    node_history = set()
    edge_dict = dict()
    node_deque = deque()
    
    
    node_deque.append(root)
    while len(node_deque):
        current_node = node_deque.popleft()
        undef_edges = []
        kinds = {i for i in range(1, max_order + 1)}
        
        for a in adjacency_list[current_node]:
            if a not in node_history:
                node_history.add(a)
                node_deque.append(a)
                
            if current_node < a:
                temp_edge = (current_node, a)
            else:
                temp_edge = (a, current_node)    
            
            if temp_edge in list(edge_dict.keys()):
                kinds.remove(edge_dict[temp_edge])
            else:
                undef_edges.append(temp_edge)
                
        for undef_edge in undef_edges:
            kind = min(kinds)
            edge_dict[undef_edge] = kind
            kinds.remove(kind)
    
    
    print(max_order)
    for e in edges:
        print((edge_dict[e]))
    
if __name__ == "__main__":
    main()


# Optimized solution
from collections import deque

def main():
	N, *AB = list(map(int, open(0).read().split()))
	B = AB[1::2]

	E = [[] for _ in range(N + 1)]
	for a, b in zip(*[iter(AB)] * 2):
		E[a].append(b)

	Q = deque([1])
	C = [0] * (N + 1)
	while Q:
		v = Q.popleft()
		c = 0
		for u in E[v]:
			c += 1 + (c + 1 == C[v])
			C[u] = c
			Q.append(u)

	print((max(C)))
	for b in B:
		print((C[b]))

main()