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

N = int(eval(input()))
EhasV = [set() for x in range(N)]
EE = [0] * (N-1)
for i in range(N-1):
    a,b = list(map(int,input().split()))
    a -= 1
    b -= 1
    EE[i] = {a,b}
    EhasV[a].add(i)
    EhasV[b].add(i)

K = len(max(EhasV,key=len))
Vcolor = [set(range(1,K+1)) for x in range(N)]

Ecolor = [-1] * (N-1)

q = deque()
q.append(0)
i = 1
while i:
    v1 = q.pop()
    i -= 1
    for e in EhasV[v1]:
        if Ecolor[e] != -1:
            continue
        color = Vcolor[v1].pop()
        Ecolor[e] = color
        edgeside = EE[e]
        edgeside.discard(v1)
        v2 = edgeside.pop()
        Vcolor[v2].discard(color)
        q.append(v2)
        i += 1

print(K)
i = 0
while i < N - 1:
    print((Ecolor[i]))
    i += 1

# Optimized solution
from collections import deque

N = int(input())
EhasV = [set() for x in range(N)]
EhasVnums = [0] * N
EE = [0] * (N-1)
for i in range(N-1):
    a,b = map(int,input().split())
    a -= 1
    b -= 1
    EE[i] = {a,b}
    EhasV[a].add(i)
    EhasV[b].add(i)
    EhasVnums[a] += 1
    EhasVnums[b] += 1

K = len(max(EhasV,key=len))
Vcolor = [set(range(1,EhasVnums[x]+1)) for x in range(N)]
Ecolor = [-1] * (N-1)

q = deque()
q.append(0)
while q:
    v1 = q.pop()
    for e in EhasV[v1]:
        if Ecolor[e] != -1:
            continue
        color = Vcolor[v1].pop()
        Ecolor[e] = color
        edgeside = EE[e]
        edgeside.discard(v1)
        v2 = edgeside.pop()
        Vcolor[v2].discard(color)
        q.append(v2)

print(*([K]+Ecolor),sep='\n')
# Original solution
import sys
from collections import deque

n = int(eval(input()))
G = [[] for _ in range(n + 1)]
G_order = []
# a<bが保証されている、aを親、bを子とする
for i in range(n - 1):
    a, b = [int(x) - 1 for x in input().split()]
    G[a].append(b)
    G_order.append(b)

# どこでも良いが、ここでは0をrootとする
que = deque([0])

# 各頂点と「親」を結ぶ辺の色
# 頂点0をrootとするのでC[0]=0で確定, 他を調べる
colors = [0] * n

while que:
    # prt = 親
    # 幅優先探索
    prt = que.popleft()
    color = 0

    # cld = 子
    for cld in G[prt]:
        color += 1
        # 「今考えている頂点とその親を結ぶ辺の色」と同じ色は使えない
        if color == colors[prt]:
            color += 1
        colors[cld] = color
        que.append(cld)

# それぞれの頂点とその親を結ぶ辺の色
# print(colors)

# 必要な最小の色数
print((max(colors)))

# 辺の番号順に色を出力
for i in G_order:
    print((colors[i]))


# Optimized solution
from collections import deque

N = int(eval(input()))
# 有向グラフと見る、G[親] = [子1, 子2, ...]
G = [[] for _ in range(N + 1)]
# 子ノードを記録、これで辺の番号を管理
G_order = []
# a<bが保証されている、aを親、bを子とする
for i in range(N - 1):
    a, b = [int(x) - 1 for x in input().split()]
    G[a].append(b)
    G_order.append(b)

# どこでも良いが、ここでは0をrootとする
que = deque([0])

# 各頂点と「親」を結ぶ辺の色
# 頂点0をrootとするのでC[0]=0で確定(「無色」), 他を調べる
colors = [0] * N
# BFS
while que:
    # prt = 親
    # 幅優先探索
    prt = que.popleft()
    color = 0

    # cld = 子
    for cld in G[prt]:
        color += 1
        # 「今考えている頂点とその親を結ぶ辺の色」と同じ色は使えないので次の色にする
        if color == colors[prt]:
            color += 1
        colors[cld] = color
        que.append(cld)

# それぞれの頂点とその親を結ぶ辺の色
# print(colors)

# 必要な最小の色数
print((max(colors)))

# 辺の番号順に色を出力
for i in G_order:
    print((colors[i]))
# Original solution
from collections import deque


N = int(eval(input()))
edges = [[] for _ in range(N)]
colors = [[-1 for _ in range(N)] for _ in range(N)]
visited = [False] * N
q = deque()

def bfs():
    max_cnt = 0
    while q:
        u = q.popleft()
        cnt = 1
        visited[u] = True
        for v in edges[u]:
            if visited[v]:
                continue
            if colors[u][v] != -1:
                continue

            while cnt in colors[u]:
                cnt += 1

            colors[u][v] = cnt
            colors[v][u] = cnt
            q.append(v)
        max_cnt = max(max_cnt, cnt)
    return max_cnt


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

q.append(0)
max_cnt = bfs()
print(max_cnt)
for a, b in AB:
    print((colors[a][b]))


# Optimized solution
import sys

sys.setrecursionlimit(10 ** 7)

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

ans = [0] * (n - 1)


def col(now, color):
    c = 1
    for (b, j) in A[now]:
        if c == color:
            c += 1
        ans[j] = c
        col(b, c)
        c += 1


col(0, 0)
print((max(ans)))
for a in ans:
    print(a)
# Original solution
import sys
sys.setrecursionlimit(10**9)

N = int(eval(input()))
adjL = [[] for _ in range(N)]
edges = []
for _ in range(N-1):
    A, B = list(map(int, input().split()))
    A, B = A-1, B-1
    adjL[A].append(B)
    adjL[B].append(A)
    edges.append((A, B))

colors = dict()
def dfs(vNow, vPar, color):
    c = 1
    for v2 in adjL[vNow]:
        if v2 == vPar: continue
        if c == color:
            c += 1
        A, B = vNow, v2
        if A > B:
            A, B = B, A
        colors[(A, B)] = c
        dfs(v2, vNow, c)
        c += 1

dfs(0, -1, 0)
#print(colors)

anss = []
for A, B in edges:
    anss.append(colors[(A, B)])

print((max(colors.values())))
print(('\n'.join(map(str, anss))))


# Optimized solution
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**9)

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

    def dfs(vNow, vPar, clrPar):
        clr = 1
        for v2, i in adjL[vNow]:
            if v2 == vPar: continue
            if clr == clrPar:
                clr += 1
            anss[i] = clr
            dfs(v2, vNow, clr)
            clr += 1

    anss = [0] * (N-1)
    dfs(0, -1, 0)

    print((max(anss)))
    print(('\n'.join(map(str, anss))))


solve()
# Original solution
def main():
    from collections import deque
    import sys
    readline = sys.stdin.buffer.readline
    read = sys.stdin.buffer.read
    N = int(readline())
    R = [[int(i) for i in r.split()] for r in read().rstrip().split(b'\n')]
    G = [[] for _ in range(N)]
    edge = {}
    ans_key = []
    for a, b in R:
        G[a-1].append(b-1)
        G[b-1].append(a-1)
        edge[(a-1, b-1)] = -1
        ans_key.append((a-1, b-1))
    max_g = max(len(g) for g in G)

    def bfs(s, max_g):
        dist = [-1 for _ in range(N)]
        color = [{i+1 for i in range(max_g)} for _ in range(N)]
        que = deque()
        que.append(s)
        dist[s] = 0
        par = [-1]*N
        while que:
            u = que.popleft()
            if par[u] != -1:
                if par[u] < u:
                    color[u].discard(edge[(par[u], u)])
                else:
                    color[u].discard(edge[(par[u], u)])
            for v in G[u]:
                if dist[v] != -1:
                    continue
                dist[v] = dist[u] + 1
                que.append(v)
                c = color[u].pop()
                par[v] = u
                if u < v:
                    edge[(u, v)] = c
                else:
                    edge[(v, u)] = c
            if all(i != -1 for i in list(edge.values())):
                return
    bfs(0, max_g)
    print(max_g)
    for k in ans_key:
        print((edge[k]))


if __name__ == '__main__':
    main()


# Optimized solution
def main():
    import sys
    readline = sys.stdin.buffer.readline
    read = sys.stdin.buffer.read
    N = int(readline())
    R = [[int(i) for i in r.split()] for r in read().rstrip().split(b'\n')]
    G = [[] for _ in range(N)]
    edge = {}
    ans_key = []
    for a, b in R:
        G[a-1].append(b-1)
        G[b-1].append(a-1)
        edge[(a-1, b-1)] = -1
        ans_key.append((a-1, b-1))
    max_g = max(len(g) for g in G)

    def dfs(max_g):
        todo = [0]
        seen = [False]*N
        seen[0] = True
        par = [-1]*N
        while todo:
            u = todo.pop()
            k = 0
            c = edge[(par[u], u)] if u != 0 else 0
            for v in G[u]:
                if seen[v]:
                    continue
                seen[v] = True
                todo.append(v)
                par[v] = u
                k += 1
                if k == c:
                    k += 1
                    if max_g < k:
                        k = 1
                if u < v:
                    edge[(u, v)] = k
                else:
                    edge[(v, u)] = k

    dfs(max_g)
    print(max_g)
    for k in ans_key:
        print((edge[k]))


if __name__ == '__main__':
    main()
# Original solution
def main():
    N = int(eval(input()))
    G = [[] for _ in range(N)]
    edge = [-1] * (N-1)
    for i in range(N-1):
        a, b = (int(i)-1 for i in input().split())
        G[a].append((b, i))
        G[b].append((a, i))

    max_deg = max(len(G[i]) for i in range(N))

    from collections import deque

    def bfs(s):
        que = deque([])
        par = [-1]*N
        que.append(s)
        while que:
            pos = que.popleft()
            c = -1
            k = 1
            for (v, i) in G[pos]:
                if par[pos] == v:
                    c = edge[i]
            for (v, i) in G[pos]:
                if par[pos] == v:
                    continue
                if k == c:
                    k += 1
                par[v] = pos
                edge[i] = k
                k += 1
                que.append(v)

    bfs(0)

    print(max_deg)
    for i in range(N-1):
        print((edge[i]))


if __name__ == '__main__':
    main()


# Optimized solution
def main():
    N = int(eval(input()))
    G = [[] for _ in range(N)]
    edge = [-1] * (N-1)
    for i in range(N-1):
        a, b = (int(i)-1 for i in input().split())
        G[a].append(b*N + i)
        G[b].append(a*N + i)

    max_deg = max(len(G[i]) for i in range(N))

    from collections import deque

    def bfs(s):
        que = deque([])
        par = [-1]*N
        que.append(s)
        while que:
            pos = que.popleft()
            c = -1
            k = 1
            for vi in G[pos]:
                v, i = divmod(vi, N)
                if par[pos] == v:
                    c = edge[i]
            for vi in G[pos]:
                v, i = divmod(vi, N)
                if par[pos] == v:
                    continue
                if k == c:
                    k += 1
                par[v] = pos
                edge[i] = k
                k += 1
                que.append(v)

    bfs(0)

    print(max_deg)
    for i in range(N-1):
        print((edge[i]))


if __name__ == '__main__':
    main()
# Original solution
N = int(eval(input()))
a,b = [],[]
for _ in range(N-1):
	at,bt = list(map(int,input().split()))
	a.append(at)
	b.append(bt)

E = [[] for _ in range(N+1)]

for i in range(N-1):
	E[a[i]].append(b[i])
	E[b[i]].append(a[i])

q = [[1,-1,0]]

ans = [[0 for _ in range(N+1)] for _ in range(N+1)]
cnt = 0
while q:
	cp, root, r_col = q.pop(0)
	
	i = 1
	for np in E[cp]:
		if np == root:
			continue
		if i == r_col:
			i += 1
		q.append([np,cp,i])
		ans[cp][np] = i
		ans[np][cp] = i
		cnt = max(cnt, i)
		i += 1

print(cnt)
for i in range(N-1):
	print((ans[a[i]][b[i]]))




# Optimized solution
N = int(eval(input()))
E = sorted([list(map(int, input().split())) + [i] for i in range(N-1)], key = lambda x:x[1])
E.sort()
ans = [0 for _ in range(N-1)]
flg = [0 for _ in range(N+1)]

t = 0
cnt = 0
ans_a = 0
for i in range(N-1):
	a,b,ind = E[i]
	if t != a:
		cnt = 1
		t = a
	if flg[a] == cnt:
		cnt += 1
	ans[ind] = cnt
	flg[b] = cnt
	ans_a = max(ans_a, cnt)
	cnt += 1



print(ans_a)
for a in ans:
	print(a)
# Original solution
from collections import deque
n = int(input())
graph = [[] for _ in range(n)]
edge = []
for i in range(n-1):
    a, b = map(lambda x:int(x)-1, input().split())
    edge.append({a,b})
    graph[a].append(b)
    graph[b].append(a)
k = max(len(i) for i in graph)

que = deque()
seen = [False]*n
ans = [0]*(n-1)
que.append((0, -1))
while len(que)>0:
    node, p_color = que.popleft()
    seen[node] = True
    color = 1
    for i in graph[node]:
        if seen[i]:
            continue
        if color==p_color:
            color += 1
        ans[edge.index({node,i})] = color
        que.append((i, color))
        color += 1
print(k)
[print(i) for i in ans]


# Optimized solution
import sys
n = int(input())
sys.setrecursionlimit(2*n)
graph = [[] for _ in range(n)]
for i in range(n-1):
    a, b = map(lambda x:int(x)-1, input().split())
    graph[a].append((b, i))
    graph[b].append((a, i))

def DFS(node, p_node=-1, p_color=-1):
    color = 1
    for c_node, edge in graph[node]:
        if c_node==p_node:
            continue
        if color==p_color:
            color += 1
        ans[edge] = color
        DFS(c_node, node, color)
        color += 1
ans = [0]*(n-1)
DFS(0)
k = max(len(i) for i in graph)
print(k)
[print(i) for i in ans]
# Original solution

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))

v_color = [0] * N
e_color = [0] * (N-1)
K = 1
for a, children in enumerate(G):
    c = 1
    for b, i in children:
        if c == v_color[a]:
            c += 1
        v_color[b] = c
        e_color[i] = c
        K = max(K, c)
        c += 1

print(K)
print(('\n'.join(map(str, e_color))))


# Optimized solution
def main():
    n = int(eval(input()))
    # G = [[0] * (n-1) for i in range(2)]
    cnt = [0] * n
    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))
        cnt[a-1] += 1
        cnt[b-1] += 1


    # for i in range(n-1):
    #     a,b = map(int, input().split())
    #     G[0][i] = a-1
    #     G[1][i] = b-1
    #     cnt[a-1] += 1
    #     cnt[b-1] += 1
    num = 0
    # print(G)
    print((max(cnt)))

    tmp_clr = [0] * (n-1)
    tmp_edge = [0] * n

    # print(G)
    for frm, child in enumerate(G):
        clr = 1
        for j, to  in enumerate(child):

            if tmp_edge[frm] == clr :
                clr += 1
            tmp_clr[to[1]] = clr
            # tmp_edge[frm] = clr
            tmp_edge[to[0]] = clr
            clr+=1
    # print(tmp_edge)
    # print(tmp_clr)
    print(('\n'.join(map(str, tmp_clr))))

if __name__=='__main__':
    main()
# Original solution
# 深さ優先探索
from sys import setrecursionlimit


def genid(a, b):
    if b < a:
        a, b = b, a
    return a * 100000 + b


N = int(eval(input()))
ab = [list(map(int, input().split())) for _ in range(N - 1)]

edges = [[] for _ in range(N)]
for a, b in ab:
    edges[a - 1].append(b - 1)
    edges[b - 1].append(a - 1)

colors = {}
q = [(0, -1, -1)]
while q:
    currentNode, usedColor, parentNode = q.pop()
    color = 1
    for childNode in edges[currentNode]:
        if childNode == parentNode:
            continue
        if color == usedColor:
            color += 1
        colors[genid(currentNode, childNode)] = color
        q.append((childNode, color, currentNode))
        color += 1

print((max(len(e) for e in edges)))
for a, b in ab:
    print((colors[genid(a - 1, b - 1)]))


# Optimized solution
# 深さ優先探索
from sys import setrecursionlimit


def genid(a, b):
    if b < a:
        a, b = b, a
    return a * 100000 + b


def paint(currentNode, usedColor, parentNode, edges, colors):
    color = 1
    for childNode in edges[currentNode]:
        if childNode == parentNode:
            continue
        if color == usedColor:
            color += 1
        colors[genid(currentNode, childNode)] = color
        paint(childNode, color, currentNode, edges, colors)
        color += 1


setrecursionlimit(10 ** 6)

N = int(eval(input()))
ab = [list(map(int, input().split())) for _ in range(N - 1)]

edges = [[] for _ in range(N)]
for a, b in ab:
    edges[a - 1].append(b - 1)
    edges[b - 1].append(a - 1)

colors = {}
paint(0, -1, -1, edges, colors)

print((max(len(e) for e in edges)))
for a, b in ab:
    print((colors[genid(a - 1, b - 1)]))
# Original solution
# coding: utf-8
# Your code here!
import sys
sys.setrecursionlimit(10**9)

N = int(eval(input()))

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

for i in range(N-1):
    a,b = list(map(int,input().split()))
    graph[a-1].append((b,i))
    graph[b-1].append((a,i))
    
ans = [0]*(N-1)
ten_col =[[] for i in range(N)]

def dfs(start,now):
    new_col = 1
    for (future,i) in graph[now-1]:
        if future == start:
            pass
        else:
            if new_col in ten_col[now-1]:
                new_col += 1
            ten_col[now-1].append(new_col)
            ten_col[future-1].append(new_col)
            ans[i] = new_col
            new_col += 1

            dfs(now,future)
            
dfs(-1,1)
print((max(ans)))
for i in ans:
    print(i)

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

N = int(eval(input()))

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

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

def dfs(past,now,edge_col):
    new_col = 1
    for (future,i) in graph[now-1]:
        if future == past:
            pass
        else:
            if new_col == edge_col:
                new_col += 1
            ans[i] = new_col
            dfs(now,future,new_col)
            new_col += 1
            
dfs(-1,1,-1)

print((max(ans)))
for i in ans:
    print(i)
# Original solution
# Problem D - Coloring Edges on Tree

from collections import deque

# input
N = int(eval(input()))
node_list = {} # 隣接リストの作成
color_count_list = [0]*(N+1)
ans_list = []
for i in range(N-1):
    a, b = list(map(int, input().split()))
    if a in node_list:
        node_list[a].append(b)
    else:
        node_list[a] = [b]
    color_count_list[a] += 1
    color_count_list[b] += 1
    ans_list.append([a, b])

# initialization
color_list = [[0]*(N+1) for i in range(N+1)]
color_max_count = max(color_count_list)

# bfs search
visit_queue = deque([[-1, 1]]) # [[既に使った色], 遷移ノード]
while len(visit_queue)>0:
    p = visit_queue.popleft()

    used_color = p[0]
    if p[1] in node_list:
        nodes = node_list[p[1]]
        nodes_len = len(nodes)
        color_num = 1
        if nodes_len>=1:
            coloring_count = 0
            while coloring_count<nodes_len:
                if color_num==used_color:
                    color_num += 1
                    continue
                color_list[p[1]][nodes[coloring_count]] = color_num
                color_list[nodes[coloring_count]][p[1]] = color_num
                # queue insert
                visit_queue.append([color_num, nodes[coloring_count]])
                # color update
                coloring_count += 1
                color_num += 1

# output
print(color_max_count)
for a in ans_list:
    print((color_list[a[0]][a[1]]))


# Optimized solution
from collections import deque

n=int(eval(input()))
G=[[]for _ in range(n)]
L=[]
ans=[0]*n
for i in range(n-1):
   a,b=list(map(int,input().split()))
   G[a-1].append(b-1)
   L.append(b-1)

que=deque([0])
while que:
   s=que.pop()
   color=1
   for ni in G[s]:
      if ans[s]==color:
         color+=1
      ans[ni]=color
      color+=1
      que.append(ni)
print((max(ans)))
for i in L:
   print((ans[i]))
# Original solution
#!/usr/bin/env python3
import sys
sys.setrecursionlimit(10**9)
input = sys.stdin.readline

n = int(eval(input()))
edge = [[] for _ in [0]*n]
for i in range(~-n):
    a, b = list(map(int, input().split()))
    a -= 1;b -= 1
    edge[a] += [[b, i]]
ans = [0] * ~-n

def dfs(now, color):
    count = 1
    for to, i in edge[now]:
        # 親の色と同じとき
        if count == color:
            count += 1
        ans[i] = count
        dfs(to, count)
        count += 1

# 開始根は0番目に
dfs(0, 0)

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


# Optimized solution
import sys
sys.setrecursionlimit(10**9)
input = sys.stdin.readline

n = int(eval(input()))
edge = [[] for _ in [0]*n]
for i in range(~-n):
    a, b = list(map(int, input().split()))
    a -= 1;b -= 1
    edge[a] += [[b, i]]
ans = [0] * ~-n

def dfs(now, color):
    count = 1
    for to, i in edge[now]:
        # 親の色と同じとき
        if count == color:
            count += 1
        ans[i] = count
        dfs(to, count)
        count += 1

# 開始根は0番目に
dfs(0, 0)

print((max(ans)))
for p in ans:
    print(p)
# Original solution
# 色の最大は辺が一番多い頂点
# 各頂点が現在持ってる色を覚える -> 2次元配列 : color_num = [[]*N]
# 答えを出力するための部分 -> 2次元配列 : ans = [[] * N for _ in range(N)]
# 答えの出し方はN-1ループでa[i], b[i]をansにいれる

from collections import deque
N = int(eval(input()))
graph = [[] for _ in range(N)]
AB = [[0] * 2 for _ in range(N-1)]
for i in range(N-1):
    a, b = list(map(int, input().split()))
    a -= 1
    b -= 1
    graph[a].append(b)
    graph[b].append(a)
    AB[i][0], AB[i][1] = a, b

K = 0
for i in range(N-1):
    K = max(len(graph[i]), K)

# BFSのためのデータ構造
que = deque()
dist = [False] * N

# 初期条件
que.append(0)
color_num = [[0] * N for _ in range(N)]
dist[0] = True
# BFS開始
while que:
    v = que[0]
    que.popleft()
    tmp = 0
    for new_v in graph[v]:
        if dist[new_v]:
            continue
        # 新たな頂点 new_vについて距離情報を更新してキューを追加する
        dist[new_v] = True
        que.append(new_v)
        # 色を塗る
        for k in range(tmp+1, K+1):
            if k in color_num[v]:
                continue
            else:
                color_num[v][new_v] = k
                color_num[new_v][v] = k
                tmp = k
                break

# 答えの出力
print(K)
for i in range(N-1):
    print((color_num[AB[i][0]][AB[i][1]]))

# Optimized solution
# 色の最大は辺が一番多い頂点
# 各頂点が現在持ってる色を覚える -> 2次元配列 : color_num = [[]*N]
# 答えを出力するための部分 -> 2次元配列 : ans = [[] * N for _ in range(N)]
# 答えの出し方はN-1ループでa[i], b[i]をansにいれる

from collections import deque
N = int(eval(input()))
graph = {i:[] for i in range(N)}
AB = [[0] * 2 for _ in range(N-1)]
for i in range(N-1):
    a, b = list(map(int, input().split()))
    a -= 1
    b -= 1
    graph[a].append(b)
    graph[b].append(a)
    AB[i][0], AB[i][1] = a, b
    if i == 0:
        start = a

K = 0
for some in list(graph.values()):
    K = max(len(some), K)

# BFSのためのデータ構造
que = deque()
dist = [False] * N

# 初期条件
que.append(start)
color_num = {i:{} for i in range(N)}
dist[start] = True

# BFS開始
while que:
    v = que[0]
    que.popleft()
    tmp = 0
    for new_v in graph[v]:
        if dist[new_v]:
            continue
        # 新たな頂点 new_vについて距離情報を更新してキューを追加する
        dist[new_v] = True
        que.append(new_v)
        # 色を塗る
        for k in range(tmp+1, K+1):
            if k in list(color_num[v].values()):
                continue
            else:
                color_num[v][new_v] = k
                color_num[new_v][v] = k
                tmp = k
                break
# 答えの出力
print(K)
for i in range(N-1):
    print((color_num[AB[i][0]][AB[i][1]]))
# Original solution
import sys
input = sys.stdin.readline


n = int(eval(input()))
routes = []
ans = [[0]*n for i in range(n)]
edges = [[]for _ in range(n)]
used = [0]*n

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

sort_routes = sorted(routes)

for node in range(n):
    unanle = used[node]
    count = 1
    if count == unanle:
        count += 1
    for to in edges[node]:
        ans[node][to] = count
        used[to] = count
        count += 1
        if count == unanle:
            count += 1

print((max(used)))
for _from, to in routes:
    print((ans[_from][to]))

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


n = int(eval(input()))
routes = []
dic = [{}] * n
edges = [[]for _ in range(n)]
used = [0]*n

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

for node in range(n):
    unanle = used[node]
    count = 1
    if count == unanle:
        count += 1
    for to in edges[node]:
        dic[node][to] = count
        used[to] = count
        count += 1
        if count == unanle:
            count += 1

print((max(used)))
for _from, to in routes:
    print((dic[_from][to]))