Problem:
Score : 400 points

Problem Statement

Given is a tree G with N vertices.
The vertices are numbered 1 through N, and the i-th edge connects Vertex a_i and Vertex b_i.

Consider painting the edges in G with some number of colors.
We want to paint them so that, for each vertex, the colors of the edges incident to that vertex are all different.

Among the colorings satisfying the condition above, construct one that uses the minimum number of colors.

Constraints

2 \le N \le 10^5

1 \le a_i \lt b_i \le N

All values in input are integers.

The given graph is a tree.

Input

Input is given from Standard Input in the following format:

N
a_1 b_1
a_2 b_2
\vdots
a_{N-1} b_{N-1}

Output

Print N lines.

The first line should contain K, the number of colors used.

The (i+1)-th line (1 \le i \le N-1) should contain c_i, the integer representing the color of the i-th edge, where 1 \le c_i \le K must hold.

If there are multiple colorings with the minimum number of colors that satisfy the condition, printing any of them will be accepted.

Sample Input 1

3
1 2
2 3

Sample Output 1

2
1
2

Sample Input 2

8
1 2
2 3
2 4
2 5
4 7
5 6
6 8

Sample Output 2

4
1
2
3
4
1
1
2

Sample Input 3

6
1 2
1 3
1 4
1 5
1 6

Sample Output 3

5
1
2
3
4
5

Solution in Go (1.6) (judge verdict: Accepted)

package main

import (
	"bufio"
	"fmt"
	"math"
	"os"
	"sort"
	"strconv"
)

const (
	mod = int(1e9) + 7
)

// IO struct
// >>>>>>> functions for io
type IO struct {
	scanner *bufio.Scanner
	writer  *bufio.Writer
}

func newIO() *IO {
	return &IO{
		scanner: bufio.NewScanner(os.Stdin),
		writer:  bufio.NewWriter(os.Stdout),
	}
}

func (IO *IO) nextLine() string {
	IO.scanner.Scan()
	return IO.scanner.Text()
}

func (IO *IO) nextInt() int {
	i, e := strconv.Atoi(IO.nextLine())
	if e != nil {
		panic(e)
	}
	return i
}

func (IO *IO) nextInt64() int64 {
	a, _ := strconv.ParseInt(IO.nextLine(), 10, 64)
	return a
}

func (IO *IO) scanNums(len int) (nums []int) {
	var num int
	for i := 0; i < len; i++ {
		num = IO.nextInt()
		nums = append(nums, num)
	}
	return
}

func (IO *IO) printLn(a ...interface{}) {
	fmt.Fprintln(IO.writer, a...)
}

// <<<<<<< functions for io

// >>>>>>> functions for basic calculation
func min(nums ...int) int {
	if len(nums) == 0 {
		panic("funciton min() requires at least one argument.")
	}
	res := nums[0]
	for i := 0; i < len(nums); i++ {
		res = int(math.Min(float64(res), float64(nums[i])))
	}
	return res
}

func max(nums ...int) int {
	if len(nums) == 0 {
		panic("funciton max() requires at least one argument.")
	}
	res := nums[0]
	for i := 0; i < len(nums); i++ {
		res = int(math.Max(float64(res), float64(nums[i])))
	}
	return res
}

func abs(x int) int {
	if x < 0 {
		return -x
	}
	return x
}

// calc a^b
func powInt(a, b int) int {
	result := 1
	for i := 1; i <= b; i++ {
		result *= a
	}
	return result
}

func sumSlice(nums []int) int {
	sum := 0
	for _, n := range nums {
		sum += n
	}
	return sum
}

// <<<<<<< functions for basic calculation

// >>>>>>> functions for typical algorithm

func gcd(a, b int) int {
	for {
		a, b = b, a%b
		if b == 0 {
			break
		}
	}
	return a
}

func binarySearch(target int, list []int) int {
	left := 0
	right := len(list) - 1
	mid := (left + right) / 2

	for {
		if list[mid] < target {
			left = mid + 1
		} else {
			right = mid
		}
		mid = (left + right) / 2
		if left >= right {
			break
		}
	}
	return mid
}

// <<<<<<< functions for typical algorithm

// >>>>>>> functions for 2D array
type array2D [][]int

func (a array2D) Len() int {
	return len(a)
}

func (a array2D) Less(i, j int) bool {
	// return a[i][0] < a[j][0] // sort by 1st arg
	return a[i][1] < a[j][1] // sort by 2nd arg
}

func (a array2D) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}

func (a array2D) sort() {
	sort.Sort(a)
}

// <<<<<<< functions for 2D array

// >>>>>>> functions for prime numbers
type sieveEratos struct {
	max   int
	sieve []int
}

func newSieveEratos(n int) sieveEratos {
	s := sieveEratos{
		max:   n,
		sieve: make([]int, n+1),
	}
	s.createSieve()
	return s
}

func (s *sieveEratos) createSieve() {
	s.sieve[1] = 1
	for i := 2; i <= s.max; i++ {
		if s.sieve[i] > 0 {
			continue
		}
		s.sieve[i] = i
		for j := i * 2; j <= s.max; j += i {
			s.sieve[j] = i
		}
	}
}

func (s sieveEratos) isPrime(n int) bool {
	if n < 2 {
		return false
	}
	return s.sieve[n] == n
}

func (s sieveEratos) factorize(n int) map[int]int {
	factors := map[int]int{}
	for {
		f := s.sieve[n]
		factors[f]++
		if f == n {
			break
		}
		n = n / f
	}
	return factors
}

// <<<<<<< functions for prime numbers

// >>>>>>> functions for inverse element

// calc a^n mod
func modPow(a, n, mod int) int {
	res := 1
	for {
		if n&1 == 1 {
			res = res * a % mod
		}
		n = n >> 1
		a = a * a % mod
		if n == 0 {
			break
		}
	}
	return res
}

// calc a^-1 mod
func getInverseElement(a, mod int) int {
	return modPow(a, mod-2, mod)
}

// <<<<<<< functions for inverse element

var io = newIO()

func main() {
	io.scanner.Split(bufio.ScanWords)      // switch to separating by space
	io.scanner.Buffer([]byte{}, 100000007) // switch to read large size input
	defer io.writer.Flush()
	solve()
}

type edge struct {
	id int
	to int
}

var tree [][]edge //map of array of verteces
var ans []int

func dfs(node, parent, pColor int) {
	k := 1
	for _, edge := range tree[node] {
		if edge.to == parent {
			continue
		}
		if k == pColor {
			k++
		}
		ans[edge.id] = k
		dfs(edge.to, node, k)
		k++
	}
}

func solve() {
	N := io.nextInt()
	tree = make([][]edge, N)
	ans = make([]int, N-1)

	for i := range make([]int, N-1) {
		a := io.nextInt() - 1
		b := io.nextInt() - 1

		tree[a] = append(tree[a], edge{i, b})
		tree[b] = append(tree[b], edge{i, a})
	}

	root := 0
	rootEdges := 0
	for vertex, edges := range tree {
		if len(edges) > rootEdges {
			root = vertex
			rootEdges = len(edges)
		}
	}
	dfs(root, -1, -1)

	io.printLn(rootEdges)
	for _, color := range ans {
		io.printLn(color)
	}
	return
}