CodeEff/ECCO huggingface dataset:
# Original solution


N = int(eval(input()))
E = []
A = [[-1 for j in range(N+1)] for i in range(N+1)]
edges = [[] for i in range(N+1)]

for i in range(N-1):
  a, b = list(map(int, input().split()))
  if i == 0:
    root = a
  E.append((a,b))
  edges[a].append(b)
  edges[b].append(a)

def dfs(u):
  visited = ["white"] * (N + 1)
  stack = [(u, -1, -1)]
  mcolor = -1

  while stack:
    u, p, c = stack.pop()
    visited[u] = "black"

    next = 1
    for v in edges[u]:
      if v != p and visited[v] != "black":
        if next == c:
          next += 1
        
        mcolor = max(mcolor, next)
        A[u][v] = next
        A[v][u] = next
        stack.append((v, u, next))
        next += 1
  
  return mcolor

print((dfs(root)))

for edge in E:
  a, b = edge
  print((A[a][b]))

# Optimized solution


N = int(eval(input()))
edges = [[] for i in range(N+1)]
A = [-1 for i in range(N-1)]

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

def dfs(u):
  visited = ["white"] * (N + 1)
  stack = [(u, -1, -1)]
  mcolor = -1

  while stack:
    u, p, c = stack.pop()
    visited[u] = "black"

    next = 1
    for (v, i) in edges[u]:
      if v != p and visited[v] != "black":
        if next == c:
          next += 1
        
        mcolor = max(mcolor, next)
        A[i] = next
        stack.append((v, u, next))
        next += 1
  
  return mcolor

print((dfs(root)))

for a in A:
  print(a)
# Original solution

N = int(eval(input()))
A = [[-1 for j in range(N+1)] for i in range(N+1)]
ans = [-1 for i in range(N-1)]
edges = [[] for i in range(N+1)]
 
for i in range(N-1):
  a, b = list(map(int, input().split()))
  if i == 0:
    root = a
  edges[a].append((b, i))
  edges[b].append((a,i))
 
def dfs(u):
  visited = ["white"] * (N + 1)
  stack = [(u, -1, -1)]
  mcolor = -1
 
  while stack:
    u, p, c = stack.pop()
    visited[u] = "black"
 
    next = 1
    for (v, i) in edges[u]:
      if v != p and visited[v] != "black":
        if next == c:
          next += 1
        
        mcolor = max(mcolor, next)
        A[u][v] = next
        A[v][u] = next
        stack.append((v, u, next))
        ans[i] = next
        next += 1
  
  return mcolor
 
print((dfs(root)))
 
for a in ans:
  print(a)

# Optimized solution

N = int(eval(input()))
EDGES = [[] for _ in range(N+1)]
P = [(set(), 1) for _ in range(N+1)]

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

ans = [None for i in range(N-1)]

def dfs(root):
  # from, parent, color
  stack = [(root, -1, -1)]
  visited = set()

  while stack:
    u, parent, color = stack.pop()
    visited.add(u)

    nextColor = 1

    for (v, index) in EDGES[u]:
      if v not in visited and v != parent:
        if nextColor == color:
          nextColor += 1
        stack.append((v, u, nextColor))
        ans[index] = nextColor
        nextColor += 1

dfs(root)

print((max(ans)))
for a in ans:
  print(a)
# Original solution
from collections import defaultdict

N = int(eval(input()))
P = [[] for _ in range(N)]
C = [set([]) for _ in range(N)]
T = set([])
D = defaultdict(int)

for _ in range(N-1):
  a, b = [int(x)-1 for x in input().split()]
  P[a].append(b)
  #P[b].append(a)
  D[(a, b)]

def bfs(s):
    d = [-1] * N
    d[s] = 0
    p_old = [s]
    M = 0
    while p_old:
      p_new = []
      for i in p_old:
        for j in P[i]:
          temp = T - C[i]
          if temp:
            v = temp.pop()
            D[(i, j)] = v
            C[i].add(v)
            C[j].add(v)
          else:
            M += 1
            T.add(M)
            D[(i, j)] = M
            C[i].add(M)
            C[j].add(M)
          d[j] = 0
          p_new.append(j)
      p_old = p_new
    return M

print((bfs(0)))

for x in list(D.values()):
  print(x)

# Optimized solution
N = int(eval(input()))
graph = [[] for _ in range(N+1)]
AB = []

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

root = 1
parent = [0] * (N+1)
order = []
stack = [root]

while stack:
    x = stack.pop()
    order.append(x)
    for y in graph[x]:
        if y == parent[x]:
            continue
        parent[y] = x
        stack.append(y)

color = [-1] * (N+1)
K = -1
for x in order:
    ng = color[x]
    c = 1
    for y in graph[x]:
        if y == parent[x]:
            continue
        if c == ng:
            c += 1
        K = max(c, K)
        color[y] = c
        c += 1

ans = []

for a, b in AB:
    if parent[a] == b:
        ans.append(color[a])
    else:
        ans.append(color[b])

print(K)
for i in ans:
  print(i)
# Original solution
import sys,collections
input = sys.stdin.readline

n = int(eval(input()))
l=[[]]
cnt = [0]*(n+1)
nn = []
for _ in range(n+1):
    l.append([])

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

m = max(list(map(len,l))) 

co = []
for i in range(n+1):
    co.append( set(range(1,m+1) ))

col = [0 for i in range(n+1)]
col[1] = 1

for i in range(1,n+1):
    for la in l[i]:
        if col[la] ==0:
            col[la] = co[i].pop()
            co[la].discard(col[la])
print(m)
for i in range(n-1):
    print((col[nn[i]]))


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

n = int(eval(input()))
l=[[]]
nn = []
for _ in range(n+1):
    l.append([])

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

ml = list(map(len,l)) 
m = max(ml)
co = []
for i in range(n+1):
    co.append( set(range(1,ml[i]+1) ))

col = [0]*(n+1)
col[1] = 1

for i in range(1,n+1):
    for la in l[i]:
        if col[la] ==0:
            col[la] = co[i].pop()
            co[la].discard(col[la])
print(m)
for i in range(n-1):
    print((col[nn[i]]))
# Original solution
from collections import deque

N = int(eval(input()))
tree = [[] for _ in range(N)]
ans = {}
tmp = []
for _ in range(N-1):
    a, b = [int(x)-1 for x in input().split()]
    tree[a].append(b)
    tree[b].append(a)
    ans[(a, b)] = 0
    tmp.append((a, b))  # 最後に出力する際に使う, 順番通りに出力する必要があるから。

# print(tree)
visited = [False]*N
colors = [-1]*N  # そのノードに上から刺さっている辺の色 (colors[根のノードのindex]は変わらない)
q = deque([0])  # 始まりのノード
visited[0] = True
while len(q):
    # vは数字, 親のノードのインデックス
    v = q.pop()
    color = 1

    for e in tree[v]:
        if visited[e]:  # 到達済みなら次のノードへ
            continue
        visited[e] = True
        if colors[v] == color:  # 親のノードに刺さっている辺の色が今から塗ろうとしている色と同じなら、変更する
            color += 1
        ans[(v, e)] = color
        colors[e] = color
        color += 1
        q.append(e)

print((max(colors)))
for a, b in tmp:
    print((ans[(a, b)]))


# Optimized solution
from collections import deque
N = int(eval(input()))
visited = [False]*N
tree = [[] for _ in range(N)]
tmp = []
for _ in range(N-1):
    a, b = [int(x)-1 for x in input().split()]
    tree[a].append(b)
    tree[b].append(a)
    tmp.append((a, b))  # 順番を保持するため

ans = {}  # 連想配列で保持する

q = deque([0])  # 開始のノード
colors = [-1]*N  # そのノードにささっている辺の色
visited[0] = True
while len(q):  # 幅優先探索を開始する
    v = q.pop()  # 部分木の親のノード
    color = 1
    for e in tree[v]:  # 子供に対して操作を行う
        if visited[e]:
            continue
        visited[e] = True
        if colors[v] == color:
            color += 1
        ans[(v, e)] = color
        colors[e] = color
        color += 1
        q.append(e)
print((max(colors)))
for a, b in tmp:
    print((ans[(a, b)]))
# Original solution
import sys
from collections import deque

input = sys.stdin.readline

def main():
    N = int(eval(input()))
    visited = [False] * N
    E = [deque() for i in range(N)]
    nums = [set() for i in range(N)] 
    ans = [None] * (N-1)
    
    for i in range(N-1):
        a, b = list(map(int, input().split()))
        E[a-1].append((b-1, i))
        E[b-1].append((a-1, i))
        
    ans_ = max([len(e) for e in E])
    G = set(i for i in range(ans_))
    
    q = deque([0])
    
    while q:
        v = q.popleft()
        
        if visited[v]: continue
    
        visited[v] = True
        
        use_nums = deque(list(G - nums[v]))
        for u, idx in E[v]:
            if visited[u]: continue
            
            n = use_nums.popleft()
            ans[idx] = str(n+1)
            nums[u].add(n)
            q.append(u)
            
    print(ans_)
    print(('\n'.join(ans)))

if __name__ == '__main__':
    main()

# Optimized solution
# -*- coding: utf-8 -*

import sys

input = sys.stdin.readline

def main():
    N = int(eval(input()))
    
    G = [[] for i in range(N)]
    ans = [None] * (N-1)
    
    for i in range(N-1):
        a, b = list(map(int, input().split()))
        a, b = a-1, b-1
        
        G[a].append((b, i))
        G[b].append((a, i))
        
    q = [(0, -1)]
    
    visited = [False] * N
    cur = 0
    
    while q and cur < N:
        v, c = q.pop(0)
    
        if visited[v]: continue
        visited[v] = True
        cur += 1
        
        k = 0
        for u, idx in G[v]:
            if visited[u]: continue
            if c == k: k += 1
            
            ans[idx] = k
            q.append((u, k))
            k += 1
            
    print((max(ans)+1))
    for a in ans: print((a+1))
     
if __name__ == '__main__':
    main()
# Original solution
n = int(eval(input()))
ikeru = [[] for _ in range(n)]
for i in range(n-1):
	a, b = list(map(int, input().split()))
	ikeru[a-1].append((b-1, i))

settansaku = set([])
setmada = {0}
listmada = [(0, None)]  #left: Vertex, right: Color
kouho = 1
num = [0 for _ in range(n-1)]

while kouho != 0:
	for i, cnt in listmada[:]:
		colors = {cnt}
		settansaku.add(i)
		setmada.remove(i)
		listmada.remove((i, cnt))
		kouho -= 1
		for k, j in ikeru[i]:
			if not k in setmada:
				if not k in settansaku:
					setmada.add(k)
					c = 0
					while True:
						if c not in colors:
							listmada.append((k, c))
							colors.add(c)
							num[j] = c
							break
						c += 1
					kouho += 1

print((max(num)+1))
print(("\n".join([str(i+1) for i in num])))

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

settansaku = set([])
setmada = {0}
listmada = [(0, None)]  #left: Vertex, right: Color
kouho = 1
num = [0 for _ in range(n-1)]

while kouho != 0:
	for i, cnt in listmada[:]:
		colors = {cnt}
		settansaku.add(i)
		setmada.remove(i)
		listmada.remove((i, cnt))
		kouho -= 1
		c = 0
		for k, j in ikeru[i]:
			if not k in setmada:
				if not k in settansaku:
					setmada.add(k)
					while True:
						if c not in colors:
							listmada.append((k, c))
							colors.add(c)
							num[j] = c
							break
						c += 1
					kouho += 1

print((max(num)+1))
print(("\n".join([str(i+1) for i in num])))
# Original solution
from collections import deque

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


def bfs():
    q = deque()
    q.append((0, 0))

    while len(q):
        v, pc = q.popleft()
        color = 1

        for e in edge[v]:
            if color == pc:
                color += 1

            if ec[e[1]] == 0:
                ec[e[1]] = color
                q.append((e[0], color))
                color += 1


bfs()
print((max(ec)))
for c in ec:
    print(c)


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


def dfs(v, c):
    nc = 0
    k = 0
    for nv, idx in edge[v]:
        if status[nv] == 0:
            nc = nc + 1 + ((nc + 1) == c)
            color[idx] = nc
            status[nv] = 1
            k = max(k, dfs(nv, nc))
    return max(nc, k)


N = int(eval(input()))
edge = [[] for _ in range(N)]
for idx, line in enumerate(sys.stdin.readlines()):
    a, b = [int(x) - 1 for x in line.split()]
    edge[a].append((b, idx))
    edge[b].append((a, idx))

status = [0] * N
color = [0] * (N - 1)
status[0] = 1
K = dfs(0, 0)

print(K)
for c in color:
    print(c)
# Original solution
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
import sys
sys.setrecursionlimit(10**8)

n = int(eval(input()))
edge = [[] for i in range(n)]

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

k = max(len(e) for e in edge)
print(k)

ans = [-1]*(n-1)

def dfs(v=0, p=-1, to_p_col = -1):
    col = 1
    for u, idx in edge[v]:
        if u != p:
            if col == to_p_col:
                col += 1
            ans[idx] = col
            dfs(u, v, col)
            col += 1
dfs()
print(('\n'.join(map(str,ans))))
# Original solution
# -*- coding: utf-8 -*-
"""
D - Coloring Edges on Tree
https://atcoder.jp/contests/abc146/tasks/abc146_d

"""
import sys


from collections import OrderedDict, deque

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

    k = max(len(g) for g in G)
    colors = [set(range(1, k+1)) for _ in range(N+1)]
    q = deque([1])
    visited = set([1])
    while q:
        cn = q.popleft()
        for nn in G[cn]:
            if nn not in visited:
                visited.add(nn)
                q.append(nn)
                c = min(colors[cn])
                colors[cn].discard(c)
                colors[nn].discard(c)
                if (cn, nn) in res:
                    res[(cn, nn)] = c
                if (nn, cn) in res:
                    res[(nn, cn)] = c
    print(k)
    for v in list(res.values()):
        print(v)


if __name__ == '__main__':
    main(sys.argv[1:])


# Optimized solution
# -*- coding: utf-8 -*-
"""
D - Coloring Edges on Tree
https://atcoder.jp/contests/abc146/tasks/abc146_d

"""
import sys


from collections import OrderedDict, deque

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

    k = max(len(g) for g in G)
    colors = [0 for _ in range(N+1)]
    q = deque([1])
    visited = set([1])
    while q:
        cn = q.popleft()
        color = 1
        for nn in G[cn]:
            if nn not in visited:
                if color == colors[cn]:
                    color += 1
                visited.add(nn)
                q.append(nn)
                c = color
                colors[nn] = color
                color += 1
                if (cn, nn) in res:
                    res[(cn, nn)] = c
                if (nn, cn) in res:
                    res[(nn, cn)] = c
    print(k)
    for v in list(res.values()):
        print(v)


if __name__ == '__main__':
    main(sys.argv[1:])
# Original solution
"""Coloring Edges on Tree
https://atcoder.jp/contests/abc146/tasks/abc146_d
"""
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10 ** 5 + 1)

class Node:
    def __init__(self, num):
        self.num = num
        self.edge = set()
        self.edge_color = set()


def dfs(node, p):
    used_color = node.edge_color
    for e in node.edge:
        if e != p:
            # 子のノードを取得
            child = tree[e]
            child_used_color = child.edge_color

            # このnodeと子のノードでまだ使っていない色を特定
            unused_colors = colors - (used_color | child_used_color)
            if len(unused_colors) == 0:
                color_num = max(colors) + 1
                colors.add(color_num)
            else:
                color_num = min(unused_colors)

            # このノードと、子のノードに使用ずみの色をマーク
            node.edge_color.add(color_num)
            child.edge_color.add(color_num)

            # 答えを記録
            if a < b:
                ans['{0} {1}'.format(node.num, child.num)] = color_num
            else:
                ans['{0} {1}'.format(child.num, node.num)] = color_num

            # 掘る
            dfs(child, node.num)


N = int(eval(input()))
ans = {}
colors = {1}

# treeの初期化
tree = [Node(i) for i in range(0, N + 1)]
edges = []
for i in range(N - 1):
    a, b = list(map(int, input().split()))
    tree[a].edge.add(b)
    tree[b].edge.add(a)
    if a < b:
        edges.append('{0} {1}'.format(a, b))
    else:
        edges.append('{0} {1}'.format(b, a))

dfs(tree[1], -1)

# print("edges:{}".format(edges))
print((len(colors)))
# print(ans)
for edge in edges:
    # print(edge)
    print((str(ans.get(edge))))


# Optimized solution
"""Coloring Edges on Tree
https://atcoder.jp/contests/abc146/tasks/abc146_d
"""
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10 ** 5 + 1)

class Node:
    def __init__(self, num):
        self.num = num
        self.edge = set()
        self.edge_color = set()


def dfs(node, c = -1 , p = -1):
    k = 1    
    for e in node.edge:
        if e == p:
            continue
        if k == c:
            k += 1
        # 子のノードを取得
        child = tree[e]

        # 答えを記録
        if a < b:
            ans['{0} {1}'.format(node.num, child.num)] = k
        else:
            ans['{0} {1}'.format(child.num, node.num)] = k
        k += 1

        # 掘る
        dfs(child,k - 1, node.num)


N = int(eval(input()))
ans = {}
# colors = {1}

# treeの初期化
tree = [Node(i) for i in range(0, N + 1)]
edges = []
for i in range(N - 1):
    a, b = list(map(int, input().split()))
    tree[a].edge.add(b)
    tree[b].edge.add(a)
    if a < b:
        edges.append('{0} {1}'.format(a, b))
    else:
        edges.append('{0} {1}'.format(b, a))

dfs(tree[1], -1)

# print("edges:{}".format(edges))
# print(max(c))
# print(ans)
count = 0
for node in tree:
    count = max(count, len(node.edge))
print(count)
for edge in edges:
    # print(edge)
    print((str(ans.get(edge))))
# Original solution
import collections
N=int(eval(input()))
AB=[list(map(int,input().split())) for i in range(N-1)]
AB_C=[0 for i in range(N-1)]
D=collections.Counter([i[0] for i in AB]+[i[1] for i in AB]).most_common()
M=D[0][1]
print(M)




data=[set() for i in range(N+1)]
idxdata=set([i for i in range(N-1)])
d=0
while idxdata or d<=2:
    #print(idxdata)
    count_c=1
    delidx=set()
    for i in idxdata:
        a,b=AB[i]
        if a==D[d][0] or b==D[d][0]:
            while not(count_c not in data[a] and count_c not in data[b]):
                count_c+=1
            AB_C[i]=count_c
            data[a].add(count_c)
            data[b].add(count_c)
            delidx.add(i)
    d+=1
    idxdata=idxdata-delidx




for i in idxdata:
    a,b=AB[i]
    #print(a,b,"a,b")
    for m in range(1,M+1):
        if m not in data[a] and m not in data[b]:
            data[a].add(m)
            data[b].add(m)
            print(m)
            break


for i in AB_C:
    print(i)


# Optimized solution
from collections import deque
N=int(eval(input()))
AB=[list(map(int,input().split())) for i in range(N-1)]
P=[set() for i in range(N+1)]
C=[set() for i in range(N+1)]

for a,b in AB:
    P[a].add(b)
    P[b].add(a)
Cpath={}
stack=deque([1])
delset=set()
while stack:
    #print(C)
    #print(Cpath,"Cpath")
    a=stack[0]
    count=1
    for b in P[a]:
        #b=P[a][-1]
        while count in C[a]:
            count+=1
        C[a].add(count)
        C[b].add(count)
        Cpath[(a,b) if a<b else (b,a)]=count
        stack.append(b)
        #P[a].remove(b)
        P[b].remove(a)
    P[a].clear()
    stack.popleft()

print((max([Cpath[i] for i in Cpath])))
for a,b in AB:
    print((Cpath[(a,b)]))
# Original solution
from collections import deque


N = int(eval(input()))
B = []
L = []
for i in range(N-1):
    ta,tb = list(map(int,input().split()))
    B.append(ta)
    B.append(tb)
    L.append([ta,tb])
B =B[1::2]
E = [[] for _ in range(N + 1)]
for a, b in L:
    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)))
print(("\n".join(str(C[b]) for b in B)))


# Optimized solution
def main():

    from collections import deque


    N = int(eval(input()))
    B = []
    L = []
    for i in range(N-1):
        ta,tb = list(map(int,input().split()))
        B.append(ta)
        B.append(tb)
        L.append([ta,tb])
    B =B[1::2]
    E = [[] for _ in range(N + 1)]
    for a, b in L:
        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)))
    print(("\n".join(str(C[b]) for b in B)))
main()
# Original solution
n = int(eval(input()))
arr = []
for i in range(n-1):
    arr.append([int(s) for s in input().split(" ")])

mmk = [[0 for i in range(n+1)] for i in range(n+1)]

childNodeNums = [0 for i in range(n)]
childNodeStatus = [-1 for i in range(n)]
nodeLines = [0 for i in range(n - 1)]


def prepare(n, arr):
    s = [[] for i in range(n)]
    for ar in arr:
        s[ar[0] - 1].append(ar[1] - 1)
        s[ar[1] - 1].append(ar[0] - 1)
    return s


# x为记录入边的颜色
def dfs(currentNode, arr, x):
    childNodes = arr[currentNode]
    if len(childNodes) == 0:
        return

    childNodeNums[currentNode] = childNodeNums[currentNode] + len(arr[currentNode])
    childNodeStatus[currentNode] = 1

    kk = 0
    for i, childNodeIndex in enumerate(childNodes):

        if childNodeStatus[childNodeIndex] == -1:
            kk = kk + 1
            if x == kk:
                kk = kk + 1
            mmk[currentNode+1][childNodeIndex+1] = kk
            dfs(childNodeIndex, arr, kk)




data = prepare(n, arr)
dfs(0, data, -1)

print((max(childNodeNums)))

for ar in arr:
    a0 = ar[0]
    a1 = ar[1]
    print((mmk[a0][a1]))


# 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(100000)

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