package main

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

func nextInt(scanner *bufio.Scanner) int {
	scanner.Scan()
	num, _ := strconv.Atoi(scanner.Text())
	return num
}

func scanIntArray() []int {
	sc := bufio.NewScanner(os.Stdin)
	sc.Split(bufio.ScanWords)
	n := nextInt(sc)
	result := []int{}
	for i := 0; i < n; i++ {
		result = append(result, nextInt(sc))
	}

	return result
}

type Input struct {
	id    int
	left  int
	right int
}

type Element struct {
	id      int
	parent  int
	sibling int
	degree  int
	depth   int
	height  int
	left    *Element
	right   *Element
}

var maxDepth int
var elements []Element

func main() {
	// assemble input
	sc := bufio.NewScanner(os.Stdin)
	sc.Split(bufio.ScanWords)
	n := nextInt(sc)
	inputs := []Input{}

	inputTable := NewHashTable()
	childTable := NewHashTable()

	for i := 0; i < n; i++ {
		id := nextInt(sc)
		left := nextInt(sc)
		right := nextInt(sc)
		input := Input{id, left, right}
		inputs = append(inputs, input)
		inputTable.Put(id, input)
		childTable.Put(input.left, true)
		childTable.Put(input.right, true)
	}

	// find root
	var rootInput Input
	for _, input := range inputs {
		_, exist := childTable.Find(input.id)
		if !exist {
			rootInput = input
			break
		}
	}

	// assemble tree
	leftElement := Element{id: rootInput.left}
	rightElement := Element{id: rootInput.right}
	rootElement := Element{id: rootInput.id, parent: -1, sibling: -1, depth: 0, left: &leftElement, right: &rightElement}

	assembleTree(&rootElement, inputTable)

	// print
	flat(rootElement)
	sort.Slice(elements, func(i, j int) bool {
		return elements[i].id < elements[j].id
	})

	for _, elem := range elements {
		printElement(elem)
	}
}

func printElement(element Element) {
	if element.id == -1 {
		return
	}
	degree := 0
	if element.left.id != -1 {
		degree++
	}
	if element.right.id != -1 {
		degree++
	}

	height := getMaxDepthLeaf(element, element.depth) - element.depth

	elementType := "root"
	if element.parent != -1 {
		if element.left.id != -1 || element.right.id != -1 {
			elementType = "internal node"
		} else {
			elementType = "leaf"
		}
	}

	fmt.Printf("node %v: parent = %v, sibling = %v, degree = %v, depth = %v, height = %v, %v\n",
		element.id, element.parent, element.sibling, degree, element.depth, height, elementType)

}

func getMaxDepthLeaf(element Element, maxDepth int) int {
	max := maxDepth
	if element.left.depth > max {
		max = element.left.depth
	}

	if element.right.depth > max {
		max = element.right.depth
	}

	if element.left.id != -1 {
		left := getMaxDepthLeaf(*element.left, max)
		if left > max {
			max = left
		}
	}

	if element.right.id != -1 {
		right := getMaxDepthLeaf(*element.right, max)
		if right > max {
			max = right
		}
	}

	return max
}

func flat(element Element) {
	elements = append(elements, element)
	if element.left != nil {
		flat(*element.left)
	}
	if element.right != nil {
		flat(*element.right)
	}
}

func assembleTree(element *Element, inputTable HashTable) {
	if element.depth > maxDepth {
		maxDepth = element.depth
	}

	// assemble left and children of left
	if element.left.id != -1 {
		leftInputOrg, _ := inputTable.Find(element.left.id)
		leftInput := leftInputOrg.(Input)
		leftElement := Element{id: element.left.id,
			left:    &Element{id: leftInput.left, sibling: leftInput.right},
			right:   &Element{id: leftInput.right, sibling: leftInput.left},
			depth:   element.depth + 1,
			parent:  element.id,
			sibling: element.right.id}
		element.left = &leftElement
		assembleTree(&leftElement, inputTable)
	}

	// assemble right and children of right
	if element.right.id != -1 {
		rightInputOrg, _ := inputTable.Find(element.right.id)
		rightInput := rightInputOrg.(Input)
		rightElement := Element{id: element.right.id,
			left:    &Element{id: rightInput.left, sibling: rightInput.right},
			right:   &Element{id: rightInput.right, sibling: rightInput.left},
			depth:   element.depth + 1,
			parent:  element.id,
			sibling: element.left.id}

		element.right = &rightElement
		assembleTree(&rightElement, inputTable)
	}
}

// ======= Hashtable =======

// HashTable is HashTables
type HashTable struct {
	hashtable []*element
	length    int
}

type element struct {
	key int
	val interface{}
}

// NewHashTable generate HashTable
func NewHashTable() HashTable {
	length := 1046527
	return HashTable{make([]*element, length), length}
}

// Put new value
func (h *HashTable) Put(key int, val interface{}) {
	new := element{key, val}
	hash := abs(key % h.length)

	index := 0
	for {
		// double hash
		if h.hashtable[((1+hash%(h.length-1))*index+hash)%h.length] == nil {
			h.hashtable[((1+hash%(h.length-1))*index+hash)%h.length] = &new
			break
		} else {
			index++
		}
	}
}

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

// Find new value
func (h *HashTable) Find(key int) (val interface{}, ok bool) {
	hash := abs(key % h.length)
	index := 0
	for {
		target := h.hashtable[((1+hash%(h.length-1))*index+hash)%h.length]
		if target == nil {
			return Input{}, false
		}

		if target.key == key {
			return h.hashtable[((1+hash%(h.length-1))*index+hash)%h.length].val, true
		}
		index++
	}
}



Measured memory_bytes: 2000