CodeEff/ECCO huggingface dataset:
# Original solution
n = int(eval(input()))
g = [[] for x in range(n+1)]
s = []
for _ in range(n-1):
    a,b = [int(x) for x in input().split()]
    g[a].append(b)
    g[b].append(a)
    s.append([a,b])

from collections import deque
color = [[-1]*(n+1) for x in range(n+1)]
index = []
q = deque()
q.append([1,0])
ans = 0
while q:
    num = 0
    p = q.popleft()
    for i in g[p[0]]:
        if color[p[0]][i]==-1:
            num += 1
            if p[1]==num:
                num += 1
            color[p[0]][i] = num
            color[i][p[0]] = num
            q.append([i,num])
            ans = max(ans,num)

print(ans)
for a,b in s:
    print((color[a][b]))
    

# Optimized solution
n = int(eval(input()))
g = [[] for _ in range(n)]
z = []
for _ in range(n-1):
    a,b = [int(x)-1 for x in input().split()]
    g[a].append(b)
    g[b].append(a)
    if a<b:
        z.append((a,b))
    else:
        z.append((b,a))

from collections import deque

parent = [0]*n
mc = 0
en = dict()

q = deque()
used = [0]*n
q.append(0)
used[0] = 1
while q:
    p = q.popleft()
    color = 0
    for i in g[p]:
        if used[i] != 1:
            color += 1
            used[i] = 1
            if color==parent[p]:
                color += 1
            if p<i:
                en[(p,i)]=color
            else:
                en[(i,p)]=color
            parent[i] = color
            q.append(i)
    mc = max(mc,color)

print(mc)
for i in z:
    print((en[i]))
# Original solution
from collections import deque
def readinput():
    n=int(eval(input()))
    nList=[]
    for _ in range(n+1):
        nList.append([])
    edges=[]
    for _ in range(n-1):
        a,b=list(map(int,input().split()))
        edges.append((a,b))
        nList[a].append(b)
        nList[b].append(a)
    return n,nList,edges

def bfs(s,nList):
    #print(nList)
    WHITE=0
    GRAY=1
    BLACK=2
    status=[WHITE]*(n+1)
    parent=[0]*(n+1)
    color=[]
    maxcolor=0
    for i in range(n+1):
        color.append([0]*(n+1))
    Q=deque([])
    Q.append(s)
    while(len(Q)>0):
        u=Q.popleft()
        usedcolor=set()
        usedcolor.add(color[u][parent[u]])
        for t in nList[u]:
            if status[t]==WHITE:
                status[t]=GRAY
                parent[t]=u
                for col in range(1,n):
                    if col in usedcolor:
                        continue
                    color[u][t]=col
                    color[t][u]=col
                    usedcolor.add(col)
                    maxcolor=max(maxcolor,col)
                    break
                Q.append(t)
        status[u]=BLACK
        #print(u,usedcolor)
    return color, maxcolor


def main(n,nList,edges):
    color, maxcolor=bfs(1,nList)
    print(maxcolor)
    for a,b in edges:
        print((color[a][b]))

if __name__=='__main__':
    n,nList,edges=readinput()
    main(n,nList,edges)


# Optimized solution
from collections import deque
def readinput():
    n=int(eval(input()))
    nList=[]
    for _ in range(n+1):
        nList.append([])
    edges=[]
    for _ in range(n-1):
        a,b=list(map(int,input().split()))
        edges.append((a,b))
        nList[a].append(b)
        nList[b].append(a)
    return n,nList,edges

def bfs(s,nList):
    #print(nList)
    WHITE=0
    GRAY=1
    BLACK=2
    status=[WHITE]*(n+1)
    parent=[0]*(n+1)
    color=[]
    maxcolor=0
    for i in range(n+1):
        color.append([0]*(n+1))
    Q=deque([])
    Q.append(s)
    while(len(Q)>0):
        u=Q.popleft()
        usedcolor=color[u][parent[u]]
        col=1
        for t in nList[u]:
            if status[t]==WHITE:
                status[t]=GRAY
                parent[t]=u
                if col==usedcolor:
                    col+=1
                color[u][t]=col
                color[t][u]=col
                maxcolor=max(maxcolor,col)
                Q.append(t)
                col+=1
        status[u]=BLACK
        #print(u,usedcolor)
    return color, maxcolor


def main(n,nList,edges):
    color, maxcolor=bfs(1,nList)
    print(maxcolor)
    for a,b in edges:
        print((color[a][b]))

if __name__=='__main__':
    n,nList,edges=readinput()
    main(n,nList,edges)
# Original solution
from collections import deque
def readinput():
    n=int(eval(input()))
    nList=[]
    for _ in range(n+1):
        nList.append([])
    edges=[]
    for _ in range(n-1):
        a,b=list(map(int,input().split()))
        edges.append((a,b))
        nList[a].append(b)
        nList[b].append(a)
    return n,nList,edges

def bfs(s,nList):
    #print(nList)
    WHITE=0
    GRAY=1
    BLACK=2
    status=[WHITE]*(n+1)
    parent=[0]*(n+1)
    color=[]
    maxcolor=0
    for i in range(n+1):
        color.append([0]*(n+1))
    Q=deque([])
    Q.append(s)
    while(len(Q)>0):
        u=Q.popleft()
        usedcolor=color[u][parent[u]]
        col=1
        for t in nList[u]:
            if status[t]==WHITE:
                status[t]=GRAY
                parent[t]=u
                if col==usedcolor:
                    col+=1
                color[u][t]=col
                color[t][u]=col
                maxcolor=max(maxcolor,col)
                Q.append(t)
                col+=1
        status[u]=BLACK
        #print(u,usedcolor)
    return color, maxcolor


def main(n,nList,edges):
    color, maxcolor=bfs(1,nList)
    print(maxcolor)
    for a,b in edges:
        print((color[a][b]))

if __name__=='__main__':
    n,nList,edges=readinput()
    main(n,nList,edges)


# Optimized solution
from collections import deque
def readinput():
    n=int(eval(input()))
    nList=[]
    for _ in range(n+1):
        nList.append([])
    edges=[]
    for _ in range(n-1):
        a,b=list(map(int,input().split()))
        edges.append((a,b))
        nList[a].append(b)
        #nList[b].append(a)
    return n,nList,edges

def bfs(s,nList):
    #print(nList)
    WHITE=0
    GRAY=1
    BLACK=2
    status=[WHITE]*(n+1)
    parent=[0]*(n+1)
    color=[0]*(n+1)
    maxcolor=0
    Q=deque([])
    Q.append(s)
    while(len(Q)>0):
        u=Q.popleft()
        usedcolor=color[u]
        col=1
        for t in nList[u]:
            if status[t]==WHITE:
                status[t]=GRAY
                parent[t]=u
                if col==usedcolor:
                    col+=1
                color[t]=col
                Q.append(t)
                col+=1
        maxcolor=max(maxcolor,col-1)
        status[u]=BLACK
        #print(u,usedcolor)
    return color, maxcolor


def main(n,nList,edges):
    color, maxcolor=bfs(1,nList)
    print(maxcolor)
    for a,b in edges:
        print((color[b]))

if __name__=='__main__':
    n,nList,edges=readinput()
    main(n,nList,edges)
# Original solution
import sys
input = sys.stdin.buffer.readline
N=int(eval(input()))
val=[list(map(int, input().split())) for i in range(N-1)]

arr=[set() for i in range(N)]
col=[set() for i in range(N)]
colarr=[0]*(N-1)
alen=[0]*N
coldict={}
for i in range(N-1):
    a=val[i][0]-1
    b=val[i][1]-1
    arr[a].add(b)
    arr[b].add(a)
    coldict[(a,b)]=i
colmax=0
flag=0
for i in range(N):
    alen[i]=len(arr[i])
    if len(arr[i])>colmax:
        colmax=len(arr[i])
        flag=i
colall=set(range(1,colmax+1))
coltemp=set(colall)
arrtemp=set(arr[flag])
for f in arrtemp:
    p=coltemp.pop()
    if flag<f:
        colarr[coldict[(flag,f)]]=p
    else:
        colarr[coldict[(f,flag)]]=p
    
    col[f].add(p)
    arr[f].remove(flag)
que=[set() for i in range(N)]
que[0]=que[0] | arr[flag]

for i in range(N-1):
    for t in que[i]:
        arrtemp=arr[t]
        if len(arrtemp)>0:
            C=set(range(1,alen[t]+1))
            coltemp=C^(C&col[t])
            que[i+1]=que[i+1] | arrtemp
            for f in arrtemp:
                p=coltemp.pop()
                col[f].add(p)
                arr[f].remove(t)
                if t<f:
                    colarr[coldict[(t,f)]]=p
                else:
                    colarr[coldict[(f,t)]]=p
print(colmax)
for i in range(N-1):
    print((colarr[i]))

# Optimized solution
import sys
input = sys.stdin.buffer.readline
N=int(eval(input()))
val=[list(map(int, input().split())) for i in range(N-1)]

arr=[set() for i in range(N)]
col=[set() for i in range(N)]
colarr=[0]*(N-1)
coldict={}
for i in range(N-1):
    a=val[i][0]-1
    b=val[i][1]-1
    arr[a].add(b)
    arr[b].add(a)
    coldict[(a,b)]=i
colmax=0
flag=0
for i in range(N):
    if len(arr[i])>colmax:
        colmax=len(arr[i])
        flag=i
colall=set(range(1,colmax+1))
coltemp=1
arrtemp=set(arr[flag])
for f in arrtemp:
    p=coltemp
    coltemp+=1
    if flag<f:
        colarr[coldict[(flag,f)]]=p
    else:
        colarr[coldict[(f,flag)]]=p
    col[f].add(p)
    arr[f].remove(flag)
que=[set() for i in range(N)]
que[0]=que[0] | arr[flag]

for i in range(N-1):
    for t in que[i]:
        arrtemp=arr[t]
        if len(arrtemp)>0:
            coltemp=1
            que[i+1] |= arrtemp
            for f in arrtemp:
                while(1):
                    if coltemp not in col[t]:
                        break
                    coltemp+=1
                p=coltemp
                coltemp+=1
                col[f].add(p)
                arr[f].remove(t)
                if t<f:
                    colarr[coldict[(t,f)]]=p
                else:
                    colarr[coldict[(f,t)]]=p
print(colmax)
for i in range(N-1):
    print((colarr[i]))
# Original solution
from collections import deque
n = int(eval(input()))
tree = [[] for _ in range(n)]
edge = []
color = [set() for _ in range(n)]
ans = dict()
for i in range(n-1):
    a,b = list(map(int,input().split()))
    edge.append([a,b])
    tree[a-1].append(b)
    tree[b-1].append(a)

work_q = deque([])
visited = set()
work_q.append(1)
visited.add(1)
while work_q:
    here = work_q.popleft()
    for i in tree[here-1]:
        col = 1
        if i not in visited:
            work_q.append(i)
            visited.add(i)
            while col in color[here-1]:
                col += 1
            color[here-1].add(col)
            color[i-1].add(col)
            ans[(here-1,i-1)] = col
            col += 1

print((max(ans.values())))
for i in range(n-1):
    print((ans[edge[i][0]-1,edge[i][1]-1]))


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

n = int(input())
edge = [[] for _ in range(n+1)]
for i in range(n-1):
    a, b = map(int,input().split())
    edge[a].append((b, i))
    edge[b].append((a, i))
colors = 0
for i, line in enumerate(edge):
    colors = max(colors, len(line))
print(colors)
work_q = deque()
work_q.append((1, -1, -1))
color = [-1] * (n - 1)

while work_q:
    here, prev, col = work_q.popleft()
    cnt = 1
    for to, ind in edge[here]:
        if to == prev:
            continue
        if cnt == col:
            cnt += 1
        color[ind] = cnt
        work_q.append((to, here, cnt))
        cnt += 1
print(*color, sep="\n")
# Original solution
import sys

sr = lambda: sys.stdin.readline().rstrip()
ir = lambda: int(sr())
lr = lambda: list(map(int, sr().split()))

N = ir()
AB = [lr() for _ in range(N-1)] # 0-indexed
edges = [[] for _ in range(N+1)] # 1-indexed
for a, b in AB:
    edges[a].append(b)
    edges[b].append(a)

order = [] # 頂点１を根とした時、上からの頂点の順番
parent = [0] * (N+1) # 1-indexed
stack = [1]
while stack:
    x = stack.pop()
    order.append(x)
    for y in edges[x]:
        if parent[x] == y:
            continue
        parent[y] = x
        stack.append(y)

color = [-1] * (N+1) # 1-indexed 頂点iの親方向への辺の色
for o in order:
    ng = color[o]
    c = 1
    for z in edges[o]:
        if z == parent[o]:
            continue
        if c == ng:
            c += 1
        color[z] = c
        c += 1

answer = []
for i in range(N-1):
    a, b = AB[i]
    if a == parent[b]:
        answer.append(color[b])
    else:
        answer.append(color[a])

print((max(answer)))
print(('\n'.join(map(str, answer))))
# 12

# Optimized solution
import sys

sr = lambda: sys.stdin.readline().rstrip()
ir = lambda: int(sr())
lr = lambda: list(map(int, sr().split()))

N = ir()
AB = [lr() for _ in range(N-1)] # 0-indexed
edges = [[] for _ in range(N+1)] # 1-indexed
for a, b in AB:
    edges[a].append(b)
    edges[b].append(a)

order = [] # 頂点１を根とした時、上からの頂点の順番
parent = [0] * (N+1) # 1-indexed
stack = [1]
while stack:
    x = stack.pop()
    order.append(x)
    for y in edges[x]:
        if parent[x] == y:
            continue
        parent[y] = x
        stack.append(y)

color = [-1] * (N+1) # 1-indexed 頂点iの親方向への辺の色
for o in order:
    ng = color[o]
    c = 1
    for z in edges[o]:
        if z == parent[o]:
            continue
        if c == ng:
            c += 1
        color[z] = c
        c += 1

answer = []
append = answer.append
for i in range(N-1):
    a, b = AB[i]
    if a == parent[b]:
        append(color[b])
    else:
        append(color[a])

print((max(answer)))
print(('\n'.join(map(str, answer))))
# 12
# Original solution
import sys
from collections import defaultdict

sr = lambda: sys.stdin.readline().rstrip()
ir = lambda: int(sr())
lr = lambda: list(map(int, sr().split()))

N = ir()
AB = [lr() for _ in range(N-1)]
graph = [[] for _ in range(N+1)] # 1-indexed
for i in range(N-1):
    a, b = AB[i]
    AB[i] = tuple(sorted([a, b]))
    graph[a].append(b)
    graph[b].append(a)

AB_to_C = defaultdict(int)
root = 1
parent = [0] * (N+1)
stack = [root]
while stack:
    cur = stack.pop()
    used = 0
    if parent[cur] != 0:
        used = AB_to_C[tuple(sorted([cur, parent[cur]]))]
    color = 1
    for next in graph[cur]:
        if next == parent[cur]:
            continue
        parent[next] = cur
        while True:
            if color == used:
                color += 1
            else:
                AB_to_C[tuple(sorted([cur, next]))] = color
                color += 1
                break
        stack.append(next)

answer = [0] * (N-1)
for i in range(N-1):
    answer[i] = AB_to_C[AB[i]]

print(max(answer))
print(*answer, sep='\n')


# Optimized solution
import sys

sr = lambda: sys.stdin.readline().rstrip()
ir = lambda: int(sr())
lr = lambda: list(map(int, sr().split()))

N = ir()
graph = [[] for _ in range(N+1)]
AB = [lr() for _ in range(N-1)]
for a, b in AB:
    graph[a].append(b)
    graph[b].append(a)

root = 1
parent = [0] * (N+1)
order = []
stack = [(root, 0)]
color = [0] * (N+1)
# 頂点と、親方向の辺を対応させる
while stack:
    cur, ng = stack.pop()
    c = 1
    for next in graph[cur]:
        if next == parent[cur]:
            continue
        if c == ng:
            c += 1
        parent[next] = cur
        color[next] = c
        stack.append((next, c))
        c += 1

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

print(max(answer))
print(*answer, sep='\n')
# 02
# Original solution
from functools import reduce
from operator import mul
N = int(eval(input()))
ab = [tuple(map(int, input().split())) for _ in range(N-1)]
E_n = {k: 0 for k in ab}
for i in range(1,N+1):
    items = {k:v for k,v in list(E_n.items()) if i in k}
    c = 1
    if items == {}: continue
    elif reduce(mul, list(items.values())) != 0: continue
    for k in list(items.keys()):
      if items[k] != 0: continue
      while True:
        if c not in list(items.values()):
          items[k] = c
          break
        else: c += 1
    E_n.update(items)
    #if reduce(mul, E_n.values()) != 0: break

print((len(set(E_n.values()))))
for k in ab: print((E_n[k]))


# Optimized solution
N = int(input())
edge = {}
tree = [[] for i in range(N)]
colors = [1]*(N-1)
c_p = [[] for i in range(N)]
for i in range(N-1):
    a,b = map(int,input().split())
    a,b = a-1,b-1
    tree[a].append(b)
    edge[(a,b)] = i

for i in range(N):
    c = 1
    for v_c in tree[i]:
      while c in c_p[i]: c+=1
      colors[edge[(i,v_c)]] = c
      c_p[v_c].append(c)
      c+=1

print(max(colors))
print(*colors, sep="\n")
# Original solution
from math import ceil,floor,factorial,gcd,sqrt,log2,cos,sin,tan,acos,asin,atan,degrees,radians,pi,inf
from itertools import accumulate,groupby,permutations,combinations,product,combinations_with_replacement
from collections import deque,defaultdict,Counter
from bisect import bisect_left,bisect_right
from operator import itemgetter
from heapq import heapify,heappop,heappush
from queue import Queue,LifoQueue,PriorityQueue
from copy import deepcopy
from time import time
from functools import reduce
import string
import sys
sys.setrecursionlimit(10 ** 7)
def input() : return sys.stdin.readline().strip()
def INT()   : return int(eval(input()))
def MAP()   : return list(map(int,input().split()))
def LIST()  : return list(MAP())

def bfs(k):
    c = [[0]*n for i in range(n)]
    dist = [-1]*n
    que = deque([0])
    dist[0] = 0
    v_prev = 0
    while que:
        v = que.popleft()
        d = dist[v]
        color = set(range(1, k+1))
        used = []
        for w in g[v]:
            if dist[w] > -1:
                used.append(c[v][w])
        color.difference_update(used)
        color = deque(color)
        for w in g[v]:
            if dist[w] > -1:
                continue
            c[v][w] = c[w][v] = color.popleft()
            dist[w] = d + 1            
            que.append(w)
    return c

n = INT()
a = [0]*(n-1)
b = [0]*(n-1)
g = [[] for i in range(n)]
for i in range(n-1):
    a[i], b[i] = MAP()
    a[i] -= 1
    b[i] -= 1
    g[a[i]].append(b[i])
    g[b[i]].append(a[i])
k = 0
for x in g:
    k = max(k, len(x))
print(k)
c = bfs(k)
for i in range(n-1):
    print((c[a[i]][b[i]]))

# Optimized solution
from math import ceil,floor,factorial,gcd,sqrt,log2,cos,sin,tan,acos,asin,atan,degrees,radians,pi,inf
from itertools import accumulate,groupby,permutations,combinations,product,combinations_with_replacement
from collections import deque,defaultdict,Counter
from bisect import bisect_left,bisect_right
from operator import itemgetter
from heapq import heapify,heappop,heappush
from queue import Queue,LifoQueue,PriorityQueue
from copy import deepcopy
from time import time
from functools import reduce
import string
import sys
sys.setrecursionlimit(10 ** 7)
def input() : return sys.stdin.readline().strip()
def INT()   : return int(eval(input()))
def MAP()   : return list(map(int,input().split()))
def MAP1()  : return [int(x)-1 for x in input().split()]
def LIST()  : return list(MAP())

def solve():
    n = INT()
    Q = [tuple(MAP1()) for _ in range(n-1)]

    deg = [0]*n
    adj = [[] for _ in range(n)]
    color = dict()

    for a, b in Q:
        deg[a] += 1
        deg[b] += 1
        adj[a].append(b)
        adj[b].append(a)

    def dfs(s, p):
        nouse = -1
        if p > -1:
            nouse = color[(min(s,p),max(s,p))]
        c = 1
        for t in adj[s]:
            if t == p:
                continue
            if c == nouse:
                c += 1
            color[(min(s,t),max(s,t))] = c
            dfs(t,s)
            c += 1
    
    dfs(1,-1)
    
    print((max(deg)))
    for a, b in Q:
        print((color[(a, b)]))

if __name__ == '__main__':
    solve()
# Original solution
from collections import deque

def main():
    N, *AB = list(map(int, open(0).read().split()))

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

    memo = {}
    for i, (a, b) in enumerate(zip(*[iter(AB)] * 2)):
        E[a].append(b)
        E[b].append(a)
        memo[(a, b)] = i
        memo[(b, a)] = i

    K = max(len(e) for e in E)

    A = [""] * (N - 1)

    cand = {i for i in range(1, K + 1)}

    visited = [False] * (N + 1)

    Q = deque([(-1, 1)])
    visited[1] = True
    while Q:
        c, v = Q.popleft()
        C = cand - {c}
        for u in E[v]:
            if visited[u]:
                continue
            visited[u] = True
            c = C.pop()
            Q.append((c, u))
            A[memo[(v, u)]] = str(c)

    print(K)
    print(("\n".join(A)))

main()


# Optimized solution
from collections import deque

def main():
    N, *AB = list(map(int, open(0).read().split()))

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

    memo = {}
    for i, (a, b) in enumerate(zip(*[iter(AB)] * 2)):
        E[a].add(b)
        E[b].add(a)
        memo[(a, b)] = i
        memo[(b, a)] = i

    K = max(len(e) for e in E)

    A = [""] * (N - 1)

    visited = [False] * (N + 1)

    Q = deque([(-1, 1)])
    visited[1] = True
    while Q:
        a, v = Q.popleft()
        c = 0
        for u in E[v]:
            E[u].remove(v)
            c += 1
            if c == a:
                c += 1
            Q.append((c, u))
            A[memo[(v, u)]] = str(c)
        E[v] = set()
    print(K)
    print(("\n".join(A)))

main()
# Original solution
from collections import deque

N, *AB = list(map(int, open(0).read().split()))

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

memo = {}
for i, (a, b) in enumerate(zip(*[iter(AB)] * 2)):
    E[a].append(b)
    E[b].append(a)
    memo[(a, b)] = i
    memo[(b, a)] = i

K = max(len(e) for e in E)

A = [0] * (N - 1)

cand = {i for i in range(1, K + 1)}

visited = [False] * (N + 1)

Q = deque([(-1, 1)])
visited[1] = True
while Q:
    p, v = Q.popleft()
    c = 0
    for u in E[v]:
        if visited[u]:
            continue
        visited[u] = True
        c += 1 + (c + 1 == p)
        Q.append((c, u))
        A[memo[(v, u)]] = c

print(K)
for a in A:
    print(a)


# Optimized solution
from collections import deque

def main():
    N, *AB = list(map(int, open(0).read().split()))

    E = [[] for _ in range(N + 1)]
    I = []
    for a, b in zip(*[iter(AB)] * 2):
        E[a].append(b)
        I.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 i in I:
        print((C[i]))

main()
# Original solution
from collections import deque

def main():
    N, *AB = list(map(int, open(0).read().split()))

    E = [[] for _ in range(N + 1)]
    I = []
    for a, b in zip(*[iter(AB)] * 2):
        E[a].append(b)
        I.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 i in I:
        print((C[i]))

main()

# Optimized solution
from collections import deque

def main():
    N, *AB = list(map(int, open(0).read().split()))

    E = [[] for _ in range(N + 1)]
    B = AB[1::2]
    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()
# Original solution
from collections import deque

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

    E = [[] for _ in range(N + 1)]
    for a, b in zip(A, B):
        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()

# Optimized solution
"""
challenge case

in:
3
1 3
2 3

out:
1
1
1
"""

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] += 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 += u,

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

main()