Go: package main

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

// I/O
type Scanner struct {
	sc *bufio.Scanner
}

func NewScanner() *Scanner {
	sc := bufio.NewScanner(os.Stdin)
	sc.Split(bufio.ScanWords)
	sc.Buffer(make([]byte, 1024), int(1e+9))
	return &Scanner{sc}
}

func (s *Scanner) nextStr() string {
	s.sc.Scan()
	return s.sc.Text()
}

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

func (s *Scanner) nextFloat() float64 {
	f, e := strconv.ParseFloat(s.nextStr(), 64)
	if e != nil {
		panic(e)
	}
	return f
}

func (s *Scanner) nextRuneSlice() []rune {
	return []rune(s.nextStr())
}

func (s *Scanner) nextIntSlice(n int) []int {
	res := make([]int, n)
	for i := 0; i < n; i++ {
		res[i] = s.nextInt()
	}
	return res
}

func (s *Scanner) nextFloatSlice(n int) []float64 {
	res := make([]float64, n)
	for i := 0; i < n; i++ {
		res[i] = s.nextFloat()
	}
	return res
}

// Arithmetic
func max(nums ...int) int {
	m := nums[0]
	for _, i := range nums {
		if m < i {
			m = i
		}
	}
	return m
}

func min(nums ...int) int {
	m := nums[0]
	for _, i := range nums {
		if m > i {
			m = i
		}
	}
	return m
}

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

func pow(x, y int) int {
	res := 1
	for i := 0; i < y; i++ {
		res *= x
	}
	return res
}

func ceil(a, b int) int {
	if a%b == 0 {
		return a / b
	} else {
		return a/b + 1
	}
}

// Sort
type RuneSlice []rune

func (a RuneSlice) Len() int           { return len(a) }
func (a RuneSlice) Less(i, j int) bool { return a[i] < a[j] }
func (a RuneSlice) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }

// Main
func main() {
	sc := NewScanner()
	wtr := bufio.NewWriter(os.Stdout)
	N := sc.nextInt()
	G := make([][]int, N)
	for i := 0; i < N; i++ {
		u, k := sc.nextInt()-1, sc.nextInt()
		for j := 0; j < k; j++ {
			G[u] = append(G[u], sc.nextInt()-1)
		}
	}
	ans := make([][2]int, N)
	time := 0
	found := make(map[int]bool)
	var dfs func(cur int)
	dfs = func(cur int) {
		time++
		ans[cur][0] = time
		found[cur] = true
		for i := 0; i < len(G[cur]); i++ {
			next := G[cur][i]
			if !found[next] {
				dfs(G[cur][i])
			}
		}
		time++
		ans[cur][1] = time
	}
	for i := 0; i < N; i++ {
		if !found[i] {
			dfs(i)
		}
	}

	for i := 0; i < N; i++ {
		fmt.Fprint(wtr, i+1)
		for j := 0; j < 2; j++ {
			fmt.Fprint(wtr, " ")
			fmt.Fprint(wtr, ans[i][j])
		}
		fmt.Fprintln(wtr)
	}
	wtr.Flush()
}

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)]

Python: import sys


def input():
    return sys.stdin.readline().rstrip()


def dfs(c, n, G, ans):
    count = c
    for i, flag in enumerate(G[n]):
        if flag == 1 and ans[i][0] == 0:
            count += 1
            ans[i][0] = i + 1
            ans[i][1] = count
            ans[i][2] = dfs(count, i, G, ans)
            count = ans[i][2]
    else:
        return count + 1


def main():
    n = int(input())
    G = [[0] * n for _ in range(n)]
    ans = [[0] * 3 for _ in range(n)]
    for i in range(n):
        u, k, *v = map(int, input().split())
        for j in range(k):
            G[u-1][v[j]-1] = 1

    count = 1
    for i in range(n):
        if ans[i][0] == 0:
            ans[i][0] = i + 1
            ans[i][1] = count
            ans[i][2] = dfs(count, i, G, ans)
            count = ans[i][2] + 1

    for i in range(n):
        print(*ans[i])


if __name__ == '__main__':
    main()

Python: from collections import deque

n = int(input())

g = [deque([]) *n for _ in range(n)]

for i in range(n):
    u, k, *V = list(map(int, input().split()))
    V.sort()
    for v in V:
        g[u-1].append(v-1)
        # g[v-1].append(u-1)

time = 0
arrive_time = [-1] * n
finish_time = [-1] * n
def dfs(v):
    global time
    time += 1
    stack = [v]
    arrive_time[v] = time
    while stack:
        v = stack[-1]
        if g[v]:
            w = g[v].popleft()
            if arrive_time[w] < 0:
                time += 1
                arrive_time[w] = time
                stack.append(w)
        else:
            time += 1
            finish_time[v] = time
            stack.pop()

    return [arrive_time, finish_time]

for i in range(n):
    if arrive_time[i] < 0:
        ans = dfs(i)

for j in range(n):
    temp = [j+1, ans[0][j], ans[1][j]]
    print(*temp)