package main

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

const (
	MaxNodes = 100000
)

type id int

type nodeData struct {
	id id
	childIds []id
}

var idToNodeData map[id]nodeData

// left-child, right-sibling representation (with parent and type)
type node struct {
	id id
	typ string
	depth int
	parent *node
	left *node
	right *node
}

func (node node) String() string {
	var parent id
	childIds := idToNodeData[node.id].childIds
	childIdsStr := make([]string, len(idToNodeData[node.id].childIds))

	if node.parent == nil {
		parent = -1
	} else {
		parent = node.parent.id
	}
	for i, v := range childIds {
		childIdsStr[i] = strconv.Itoa(int(v))
	}

	str := fmt.Sprintf("node %d: parent = %d, depth = %d, %s, %s",
		node.id,
		parent,
		node.depth,
		node.typ,
		"[" + strings.Join(childIdsStr, ", ") + "]",
	) + "\n"
	if node.left != nil {
		str = str + node.left.String()
	}
	if node.right != nil {
		str = str + node.right.String()
	}
	return str
}

func (node node) collectNodeInfo(nodeInfo []string) {
	var parent id
	childIds := idToNodeData[node.id].childIds
	childIdsStr := make([]string, len(idToNodeData[node.id].childIds))

	if node.parent == nil {
		parent = -1
	} else {
		parent = node.parent.id
	}
	for i, v := range childIds {
		childIdsStr[i] = strconv.Itoa(int(v))
	}

	nodeInfo[node.id] = fmt.Sprintf("node %d: parent = %d, depth = %d, %s, %s",
		node.id,
		parent,
		node.depth,
		node.typ,
		"[" + strings.Join(childIdsStr, ", ") + "]",
	)
	if node.left != nil {
		node.left.collectNodeInfo(nodeInfo)
	}
	if node.right != nil {
		node.right.collectNodeInfo(nodeInfo)
	}
}

func printTree(root *node) {
	nodeInfo := make([]string, MaxNodes)
	root.collectNodeInfo(nodeInfo)
	for _, v := range nodeInfo {
		if v != "" {
			fmt.Println(v)
		}
	}
}

func findRoot(firstId id) id {
	id := firstId
	for {
		currentId := id
		loop1: for i, nd := range idToNodeData {
			for _, v := range nd.childIds {
				if id == v {
					id = i
					break loop1
				}
			}
		}
		if currentId == id {
			return id
		}
	}
}

func createRootedTree(rootId id) *node {
	rootData := idToNodeData[rootId]
	root := &node{
		id: rootId,
		typ: "root",
		depth: 0,
		parent: nil,
		left: nil,
		right: nil,
	}

	childNum := len(rootData.childIds)
	var prevChild *node
	for i := 0; i < childNum; i++ {
		child := createTree(rootData.childIds[i], 1)
		child.parent = root
		if i == 0 {
			root.left = child
		}
		if prevChild != nil {
			prevChild.right = child
		}
		prevChild = child
	}
	return root
}

func createTree(rootId id, depth int) *node {
	var typ string
	rootData := idToNodeData[rootId]
	if len(rootData.childIds) == 0 {
		typ = "leaf"
	} else {
		typ = "internal node"
	}
	root := &node{
		id: rootId,
		typ: typ,
		depth: depth,
		parent: nil,
		left: nil,
		right: nil,
	}

	childNum := len(rootData.childIds)
	var prevChild *node
	for i := 0; i < childNum; i++ {
		child := createTree(rootData.childIds[i], depth + 1)
		child.parent = root
		if i == 0 {
			root.left = child
		}
		if prevChild != nil {
			prevChild.right = child
		}
		prevChild = child
	}
	return root
}

func main() {
	sc := bufio.NewScanner(os.Stdin)
	sc.Split(bufio.ScanWords)

	n, err := nextInt(sc)
	if err != nil {
		panic(err)
	}

	var firstId id
	idToNodeData = make(map[id]nodeData)
	for i := 0; i < n; i++ {
		nodeId, err := nextInt(sc)
		if err != nil {
			panic(err)
		}
		if i == 0 {
			firstId = id(nodeId)
		}
		childNum, err := nextInt(sc)
		if err != nil {
			panic(err)
		}
		childIds := make([]id, childNum)
		for j := 0; j < childNum; j++ {
			child, err := nextInt(sc)
			if err != nil {
				panic(err)
			}
			childIds[j] = id(child)
		}
		idToNodeData[id(nodeId)] = nodeData{id: id(nodeId), childIds: childIds}
	}

	rootId := findRoot(firstId)
	tree := createRootedTree(rootId)
	printTree(tree)
}

func nextText(sc *bufio.Scanner) string {
	sc.Scan()
	return sc.Text()
}

func nextInt(sc *bufio.Scanner) (int, error) {
	return strconv.Atoi(nextText(sc))
}


Measured memory_bytes: 82908