Go: package main

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

const N = 100

const (
	WHITE = iota
	GRAY
	BLACK
)

type Graph struct {
	M               [N][N]int
	color, d, f, nt [N]int
	tt              int
}

func (g *Graph) next(u, n int) int {
	for v := g.nt[u]; v < n; v++ {
		g.nt[u] = v + 1
		if g.M[u][v] != 0 {
			return v
		}
	}
	return -1
}

func (g *Graph) dfsVisit(r, n int) {
	var S []int
	S = append([]int{r}, S...)
	g.color[r] = GRAY
	g.tt++
	g.d[r] = g.tt

	for len(S) != 0 {
		u := S[0]
		v := g.next(u, n)
		if v == -1 {
			S = S[1:]
			g.color[u] = BLACK
			g.tt++
			g.f[u] = g.tt
			continue
		}

		if g.color[v] != WHITE {
			continue
		}

		g.color[v] = GRAY
		g.tt++
		g.d[v] = g.tt
		S = append([]int{v}, S...)
	}
}

func (g *Graph) dfs(n int) string {
	for i := 0; i < n; i++ {
		g.color[i] = WHITE
	}
	g.tt = 0

	for u := 0; u < n; u++ {
		if g.color[u] == WHITE {
			g.dfsVisit(u, n)
		}
	}

	var out bytes.Buffer
	for i := 0; i < n; i++ {
		out.WriteString(fmt.Sprintf("%d %d %d\n", i+1, g.d[i], g.f[i]))
	}

	return strings.TrimRight(out.String(), "\n")
}

func answer(reader io.Reader) string {
	sc := bufio.NewScanner(reader)
	sc.Split(bufio.ScanWords)

	sc.Scan()
	n, _ := strconv.Atoi(sc.Text())

	var g Graph
	for i := 0; i < n; i++ {
		sc.Scan()
		u, _ := strconv.Atoi(sc.Text())
		sc.Scan()
		k, _ := strconv.Atoi(sc.Text())
		u--
		for j := 0; j < k; j++ {
			sc.Scan()
			v, _ := strconv.Atoi(sc.Text())
			v--
			g.M[u][v] = 1
		}
	}

	return g.dfs(n)
}

func main() {
	fmt.Println(answer(os.Stdin))
}

Python: n = int(input())

A = [[0] * n for _ in range(n)]

for _ in range(n):
    u, k, *v = list(map(int, input().split()))
    for j in v:
        A[u-1][j-1] = 1

# for row in A:
#     print(' '.join(list(map(str,row))))

t = 0
d = [None] * n
f = [None] * n

def dfs_recursive(u):
    global t
    t += 1
    d[u] = t
    for v in range(n):
        if A[u][v] == 1 and d[v] is None:
            dfs_recursive(v)
    t += 1
    f[u] = t

def dfs_stack(root):
    global t
    stack = []
    stack.append(root)
    while stack:

        # 一番最後の要素をなめる
        u = stack[-1]

        # 未訪問の場合は訪問済みにする
        if d[u] is None:
            t += 1
            d[u] = t

        # 次の訪問先を探す
        has_next_node = False
        for v in range(n):
            if A[u][v] == 1 and d[v] is None:
                stack.append(v)
                has_next_node = True
                break

        # 次の訪問先がなければ訪問終了
        if not has_next_node:
            t += 1
            # スタックから取り出す
            stack.pop()

            # 時刻を記録
            f[u] = t
            
for i in range(n):
    if d[i] is None:
        dfs_recursive(i)
        # dfs_stack(i)

for i in range(n):
    print(i+1, d[i], f[i])

Python: N = input()
color = [0] * N
d = [0] * N
f = [0] * N
nt = [0] * N
m = [[0] * N for i in range(N)]
S = []
tt = 0

def next(u):
    global nt
    w = nt[u]
    for v in range(w, N):
        nt[u] = v + 1
        if( m[u][v] ):
            return v
    return -1

def dfs_visit(r):
    global tt 
    S.append(r)
    color[r] = 1
    tt += 1
    d[r] = tt

    while( len(S) != 0 ):
        u = S[-1]

        v = next(u)
        if ( v != -1 ):
            if ( color[v] == 0 ):
                color[v] = 1
                tt += 1
                d[v] = tt
                S.append(v)
        else:
            S.pop()
            color[u] = 2
            tt += 1
            f[u] = tt
        
def dfs():
    global color
    for u in range(N):
        if( color[u] == 0 ):
            dfs_visit(u)

if __name__ == '__main__':

    for i in range(N):
        v = map(int, raw_input().split())
        for j in v[2:]:
            m[i][j-1] = 1
    
    dfs()

    for i in range(N):
        print (i+1), d[i], f[i]

Python: class Node:

    def __init__(self):
        self.distime = 0
        self.fintime = 0

    def input_data(self, nodes):
        data = input().split()
        self.number = int(data[0])
        self.v = [nodes[int(x) - 1] for x in data[2:]]

    @property
    def status(self):
        return bool(self.distime) + bool(self.fintime)

class Stack:
    def __init__(self, size):
        self.size = size
        self.N = [None for _ in range(size)]
        self.top = 0

    def is_emtpy(self):
        return self.top == 0

    def is_full(self):
        return self.top == self.size

    def front(self):
        return self.N[self.top - 1]

    def push(self, x):
        if self.is_full():
            raise OverflowError
        self.N[self.top] = x
        self.top += 1

    def pop(self):
        if self.is_emtpy():
            raise IndexError
        self.top -= 1
        return self.N[self.top]


def visit(node: Node):
    global t
    stack.push(node)
    t += 1
    node.distime = t
    while not stack.is_emtpy():
        u: Node = stack.front()
        try:
            v = next(i for i in u.v if i.status == 0)
        except StopIteration:
            stack.pop()
            t += 1
            u.fintime = t
        else:
            if v.status == 0:
                stack.push(v)
                t += 1
                v.distime = t


n = int(input())
stack = Stack(n)
nodes = [Node() for _ in range(n)]
[node.input_data(nodes) for node in nodes]
t = 0
for node in nodes:
    if node.status == 0:
        visit(node)

nodes.sort(key=lambda i: i.number)
for node in nodes:
    print(f"{node.number} {node.distime} {node.fintime}")

Python: # https://onlinejudge.u-aizu.ac.jp/courses/lesson/1/ALDS1/11/ALDS1_11_B
# 本の解説通りかは知らない

# データの読み込み
N = int(input())
DG = {}
node_ls = []
is_visited = {}
# 有向グラフをディクトで管理することにする
for _ in range(N):
    tmp = input().split()
    node_id = tmp[0]
    node_ls.append(node_id)
    is_visited[node_id] = False
    adj_num = int(tmp[1])
    if adj_num != 0:
        DG[node_id] = tmp[2:]
    else:
        DG[node_id] = []

d = {}  # 最初に訪問したときの発見時刻を記録する
f = {}  # 隣接リストを調べ終えた完了時刻を記録する
t = 1


def dfs(node):  # 必要なものは何？ 現在のノード
    # 終了条件
    global t
    if is_visited[node]:
        return  # 何もせずに上の関数に抜ける

    is_visited[node] = True
    # 発見時刻の書き込み
    d[node] = t
    t += 1  # 時刻を一つ進める
    # 再帰探索
    for no in DG[node]:
        dfs(no)
    f[node] = t
    t += 1  # 関数を終了するときにも+1する


for node in node_ls:  # 孤立しているノードもあるためこうして対処
    dfs(node)

for node in node_ls:
    print(node, d[node], f[node])

Python: N = int(input())
L = [[] for i in range(N+1)]
d = [0] * (N+1)
f = [0] * (N+1)

time = 0

def dfs(key):
    global time
    time += 1
    d[key] = time
    for i in range(len(L[key])):
        if d[L[key][i]] == 0:
            dfs(L[key][i])
    time += 1
    f[key] = time
        

for i in range(N):
    Q = list(map(int, input().split()))
    L[Q[0]].extend(Q[2:])

for i in range(1,N+1):
    if d[i] == 0:
        dfs(i)
        #print("done")

for i in range(1,N+1):
    print(i, d[i], f[i])

Python: n = int(input())
graph = [[0 for i in range(n)] for j in range(n)]
d = [0] * n
f = [0] * n
g = [0] * n

time = 0

for i in range(n):
   a = list(map(int, input().split()))
   for j in range(0, a[1], 1):
       graph[a[0] - 1][a[2 + j] - 1] = 1

def search(i):
    global time
    time = time + 1
    d[i] = time
    g[i] = 1
    for j in range(n):
        if (graph[i][j] == 1) & (g[j] == 0):
            search(j)
    time = time + 1
    f[i] = time

for i in range(n):
    if g[i] == 0:
        search(i)
[print(i+1, d[i], f[i]) for i in range(n)]