← Home
package main

import (
	"bufio"
	"io"
	"os"
	"runtime"
	"sort"
)

type FastScanner struct {
	data []byte
	idx  int
	n    int
}

func (fs *FastScanner) NextInt() int {
	for fs.idx < fs.n {
		c := fs.data[fs.idx]
		if c >= '0' && c <= '9' {
			break
		}
		fs.idx++
	}
	val := 0
	for fs.idx < fs.n {
		c := fs.data[fs.idx]
		if c < '0' || c > '9' {
			break
		}
		val = val*10 + int(c-'0')
		fs.idx++
	}
	return val
}

func writeInt(w *bufio.Writer, x int) {
	if x == 0 {
		w.WriteByte('0')
		return
	}
	var buf [20]byte
	i := len(buf)
	for x > 0 {
		i--
		buf[i] = byte('0' + x%10)
		x /= 10
	}
	w.Write(buf[i:])
}

func main() {
	data, _ := io.ReadAll(bufio.NewReaderSize(os.Stdin, 1<<20))
	fs := FastScanner{data: data, n: len(data)}
	n := fs.NextInt()
	m := n - 1

	head := make([]int, n+1)
	for i := range head {
		head[i] = -1
	}
	to := make([]int, 2*m)
	next := make([]int, 2*m)
	ec := 0
	addEdge := func(a, b int) {
		to[ec] = b
		next[ec] = head[a]
		head[a] = ec
		ec++
	}

	for i := 0; i < m; i++ {
		a := fs.NextInt()
		b := fs.NextInt()
		addEdge(a, b)
		addEdge(b, a)
	}

	parent := make([]int, n+1)
	order := make([]int, n)
	stack := make([]int, n)
	sp := 0
	stack[sp] = 1
	sp++
	ol := 0
	for sp > 0 {
		v := stack[sp-1]
		sp--
		order[ol] = v
		ol++
		for e := head[v]; e != -1; e = next[e] {
			u := to[e]
			if u == parent[v] {
				continue
			}
			parent[u] = v
			stack[sp] = u
			sp++
		}
	}

	nodeType := make([]int, n+1)
	subSize := make([]int, n+1)

	terminal1 := make([]bool, n+2)
	repVertex := make([]int, n+2)
	typeSize := make([]int, n+2)
	terminal1[1] = true
	typeSize[1] = 1
	typesList := make([]int, 1, n)
	typesList[0] = 1

	trieMap1 := make(map[uint64]int, n)
	numTrie1 := 1
	tmp := make([]int, 0, 16)

	for i := n - 1; i >= 0; i-- {
		v := order[i]
		tmp = tmp[:0]
		sz := 1
		for e := head[v]; e != -1; e = next[e] {
			u := to[e]
			if parent[u] == v {
				tmp = append(tmp, nodeType[u])
				sz += subSize[u]
			}
		}
		if len(tmp) > 1 {
			sort.Ints(tmp)
		}
		cur := 1
		for _, lab := range tmp {
			key := (uint64(cur) << 32) | uint64(lab)
			nxt, ok := trieMap1[key]
			if !ok {
				numTrie1++
				nxt = numTrie1
				trieMap1[key] = nxt
			}
			cur = nxt
		}
		nodeType[v] = cur
		subSize[v] = sz
		if cur == 1 {
			if repVertex[1] == 0 {
				repVertex[1] = v
			}
		} else if !terminal1[cur] {
			terminal1[cur] = true
			repVertex[cur] = v
			typeSize[cur] = sz
			typesList = append(typesList, cur)
		} else if repVertex[cur] == 0 {
			repVertex[cur] = v
		}
	}

	sort.Slice(typesList, func(i, j int) bool {
		a, b := typesList[i], typesList[j]
		if typeSize[a] != typeSize[b] {
			return typeSize[a] < typeSize[b]
		}
		return a < b
	})

	typeCount := len(typesList)
	rankOfType := make([]int, numTrie1+1)
	rankWeight := make([]int, typeCount+1)
	rankToType := make([]int, typeCount+1)
	for i, t := range typesList {
		r := i + 1
		rankOfType[t] = r
		rankWeight[r] = typeSize[t]
		rankToType[r] = t
	}

	fs.data = nil
	data = nil
	trieMap1 = nil
	terminal1 = nil
	subSize = nil
	order = nil
	stack = nil
	typeSize = nil
	typesList = nil
	runtime.GC()

	trieParent2 := make([]int, n+2)
	inLabel2 := make([]int, n+2)
	dist2 := make([]int, n+2)
	terminal2 := make([]bool, n+2)
	head2 := make([]int, n+2)
	for i := range head2 {
		head2[i] = -1
	}
	edgeLabel2 := make([]int, n+1)
	edgeNext2 := make([]int, n+1)
	edgeCnt2 := 0
	trieMap2 := make(map[uint64]int, n)
	numTrie2 := 1
	tmp2 := make([]int, 0, 16)

	for v := 1; v <= n; v++ {
		tmp2 = tmp2[:0]
		for e := head[v]; e != -1; e = next[e] {
			u := to[e]
			if parent[u] == v {
				tmp2 = append(tmp2, rankOfType[nodeType[u]])
			}
		}
		if len(tmp2) > 1 {
			sort.Ints(tmp2)
		}
		cur := 1
		for _, lab := range tmp2 {
			key := (uint64(cur) << 32) | uint64(lab)
			nxt, ok := trieMap2[key]
			if !ok {
				numTrie2++
				nxt = numTrie2
				trieMap2[key] = nxt
				trieParent2[nxt] = cur
				inLabel2[nxt] = lab
				dist2[nxt] = dist2[cur] + rankWeight[lab]
				edgeLabel2[edgeCnt2] = lab
				edgeNext2[edgeCnt2] = head2[cur]
				head2[cur] = edgeCnt2
				edgeCnt2++
			}
			cur = nxt
		}
		terminal2[cur] = true
	}

	bestCost := n + 1
	bestNode := 1
	bestExtra := 0
	labbuf := make([]int, 0, 16)

	for u := 1; u <= numTrie2; u++ {
		if !terminal2[u] && dist2[u] < bestCost {
			bestCost = dist2[u]
			bestNode = u
			bestExtra = 0
		}
		labbuf = labbuf[:0]
		for e := head2[u]; e != -1; e = edgeNext2[e] {
			labbuf = append(labbuf, edgeLabel2[e])
		}
		if len(labbuf) > 1 {
			sort.Ints(labbuf)
		}
		expected := 1
		if u != 1 {
			expected = inLabel2[u]
		}
		for _, lab := range labbuf {
			if lab < expected {
				continue
			}
			if lab == expected {
				expected++
			} else {
				break
			}
		}
		if expected <= typeCount {
			cand := dist2[u] + rankWeight[expected]
			if cand < bestCost {
				bestCost = cand
				bestNode = u
				bestExtra = expected
			}
		}
	}

	out := bufio.NewWriterSize(os.Stdout, 1<<20)
	writeEdge := func(a, b int) {
		writeInt(out, a)
		out.WriteByte(' ')
		writeInt(out, b)
		out.WriteByte('\n')
	}

	if bestCost >= n {
		for v := 2; v <= n; v++ {
			writeEdge(parent[v], v)
		}
		out.Flush()
		return
	}

	seq := make([]int, 0, 16)
	x := bestNode
	for x != 1 {
		seq = append(seq, inLabel2[x])
		x = trieParent2[x]
	}
	for i, j := 0, len(seq)-1; i < j; i, j = i+1, j-1 {
		seq[i], seq[j] = seq[j], seq[i]
	}
	if bestExtra != 0 {
		seq = append(seq, bestExtra)
	}

	badNodes := 0
	for _, r := range seq {
		badNodes += rankWeight[r]
	}

	chainLen := n - 1 - badNodes
	for i := 1; i <= chainLen; i++ {
		writeEdge(i, i+1)
	}
	bottom := chainLen + 1
	curLabel := bottom

	stackOrig := make([]int, 0, 16)
	stackNew := make([]int, 0, 16)

	for _, r := range seq {
		t := rankToType[r]
		rep := repVertex[t]

		curLabel++
		rootNew := curLabel
		writeEdge(bottom, rootNew)

		stackOrig = stackOrig[:0]
		stackNew = stackNew[:0]
		stackOrig = append(stackOrig, rep)
		stackNew = append(stackNew, rootNew)

		for len(stackOrig) > 0 {
			o := stackOrig[len(stackOrig)-1]
			stackOrig = stackOrig[:len(stackOrig)-1]
			nn := stackNew[len(stackNew)-1]
			stackNew = stackNew[:len(stackNew)-1]

			for e := head[o]; e != -1; e = next[e] {
				c := to[e]
				if parent[c] == o {
					curLabel++
					cn := curLabel
					writeEdge(nn, cn)
					stackOrig = append(stackOrig, c)
					stackNew = append(stackNew, cn)
				}
			}
		}
	}

	out.Flush()
}