Go: package main

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

func main() {
	scn := bufio.NewScanner(os.Stdin)
	scn.Split(bufio.ScanWords)
	nextInt := func() int { scn.Scan(); r, _ := strconv.Atoi(scn.Text()); return r }
	w := bufio.NewWriter(os.Stdout)

	n := nextInt()
	vecs := make([][]int, n)
	for i := 0; i < n; i++ {
		u := nextInt()
		k := nextInt()
		for j := 0; j < k; j++ {
			vecs[u-1] = append(vecs[u-1], nextInt()-1)
		}
	}

	ds := make([]int, n)
	fs := make([]int, n)
	founds := make([]bool, n)
	t := 0
	for i := range founds {
		if !founds[i] {
			t = dfs(vecs, ds, fs, founds, i, t)
		}
	}

	for i := 0; i < n; i++ {
		fmt.Fprintln(w, i+1, ds[i], fs[i])
	}

	w.Flush()
}

func dfs(vecs [][]int, ds, fs []int, founds []bool, i, t int) (time int) {
	t++
	ds[i] = t
	founds[i] = true
	for _, v := range vecs[i] {
		if !founds[v] {
			t = dfs(vecs, ds, fs, founds, v, t)
		}
	}
	t++
	fs[i] = t

	return t
}

Python: # ??????????????????????£?????????????deque??????????????????
from collections import deque


class Node:
    def __init__(self, no, childs):
        self.no = no
        self.childs = childs
        self.find_time = None
        self.finish_time = None
        self.visit = False


def get_node_index(nodes, no):
    for i in range(len(nodes)):
        if nodes[i].no == no:
            return i


def get_unvisited(visited, childs):

    if childs is None: return None

    for i in range(len(childs)):
        if childs[i] not in visited:
            return childs[i]


"""
Main??????????????????
"""
# Node??°?????????
N = int(input())

# Node??????????????????????????????
nodes = []

# Node??????????¨????
for i in range(N):
    j = list(map(int, input().split())) # ??\??????????§£
    no = j[0]                           # Node??????????????? [2 2 1 4] ->2?????????
    childNum = j[1]
    if childNum != 0:
        childs = j[2:]                  # ??????????´?????????? [2 2 1 4] ->[1,4]?????????
    else:
        childs = []                     # ??????????´?????????? [2 2 1 4] ->[1,4]?????????
    nodes.append(Node(no, childs))


# ??±???????????¢?´¢(DFS)?????????
total_time = 1   # ??¢?´¢??????
stack = deque() # ??¢?´¢???????´?????´?????????????
stack.appendleft(1)
no = get_node_index(nodes, stack[0])  # ?????¨??¢?´¢???????´???????
nodes[no].find_time = total_time
visited = []    # ??¢?´¢??????????´?????´??????????

while stack:
    no = get_node_index(nodes, stack[0])  # ?????¨??¢?´¢???????´???????
    total_time += 1  # ??¢?´¢??????+1
    visited.append(stack[0])              # ??¢?´¢??????????????????????´?
    # ?????¢?´¢???????´??????????
    unvisited = get_unvisited(visited, nodes[no].childs)
    if unvisited is not None:
        # ?????¢?´¢???????´??????????????????????????????¢?´¢????´????????????§??????????????????????????????????´???§????????´????????¢?´¢?????\?????????????????????
        if nodes[unvisited-1].visit is False:
            nodes[unvisited-1].visit = True
            stack.appendleft(unvisited)
            nodes[unvisited-1].find_time = total_time
    else:
        stack.popleft()
        nodes[no].finish_time = total_time



#??¨?????????
for i in range(N):
    print("{0} {1} {2}".format(nodes[i].no, nodes[i].find_time, nodes[i].finish_time))

Python: def visit(u):
    global visit_color, d, f, t
    color[u] = GRAY
    d[u] += t
    t += 1
    for v in range(n):
        if (M[u][v] == 0):
            continue
        if (color[v] == WHITE):
            visit(v)
    color[u] = BLACK
    f[u] = t
    t += 1

n = int(input())
M = [[False for i in range(n)] for i in range(n)]
for i in range(n):
    tmp = list(map(int, input().split()))
    for i in range(tmp[1]):
        M[tmp[0]-1][tmp[i+2]-1] = 1

WHITE = 0
GRAY = 1
BLACK = 2
color, d, f = [WHITE for i in range(n)]
t = 1
for u in range(n):
    if (color[u] == WHITE):
        visit(u)
for u in range(n):
    print(str(u+1), str(d[u]), str(f[u]), sep = " ")

Python: from collections import deque
N=int(input())
color=["w"]*(N+1)
start=[None]*(N+1)
finish=[0]*(N+1)
rinsetu=[[] for i in range(N+1)]
for i in range(1,N+1):
    a=list(map(int,input().split()))
    a=a[2:]
    rinsetu[i]=a
def dfs(i,t):
    if color[i]=="w":
        t+=1
        start[i]=t
        color[i]="g"
        for j in rinsetu[i]:
            t=dfs(j,t)
        t+=1
        finish[i]=t
        return t
    else:return t
t=dfs(1,0)
while(None in start[1:]):
    a=start[1:].index(None)
    t=dfs(a+1,t)

for i in range(1,N+1):
    print("%d %d %d" %(i,start[i],finish[i]))

Python: from enum import Enum, auto

class Color(Enum):
    WHITE = auto() # 未訪問の頂点
    GRAY = auto() # 訪問済みだが, 全ての接点の調査は済んでいない状態の接点
    BLACK = auto() # 訪問, 調査済みの接点

n = int(input())
d = [0 for i in range(n)]
f = [0 for i in range(n)]

colors = [] # 頂点の訪問状態
A = [[0 for j in range(n)] for i in range(n)] # 隣接行列
# stack = [] ## スタックによる実装では頂点の保持が必要 => 再帰によって実装

# 隣接行列の初期化
for i in range(n):
    arr = list(map(int, input().split(' ')))
    u, k, v = arr[0], arr[1], arr[2:]
    for j in range(k):
        A[u-1][v[j]-1] = 1

time = 0
def dfs_init():
    global colors
    colors = [Color.WHITE for i in range(n)]
    dfs(0)

def dfs(u):
    global time
    colors[u] = Color.GRAY
    time += 1
    d[u] = time
    for v in range(n):
        if A[u][v] == 1 and colors[v] == Color.WHITE:
            dfs(v)
    colors[u] = Color.BLACK
    time += 1
    f[u] = time

dfs_init()

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

Python: #!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys

WHITE, GRAY, BLACK = 0, 1, 2


def generate_adj(v_info):
    for v_detail in v_info:
        v_adj_list = v_detail[2:]
        assert len(v_adj_list) == int(v_detail[1])
        for each in v_adj_list:
            init_adj_matrix[int(v_detail[0]) - 1][int(each) - 1] = 1
    return init_adj_matrix


def graph_dfs(start_node_index):
    # init the first node
    v_index = int(start_node_index)
    vertex_visit_stack.append(v_index)
    vertex_color_list[v_index] = GRAY
    time = 1
    vertex_d_time[v_index] += time
    # init end
    while len(vertex_visit_stack) > 1:
        current_vertex = vertex_visit_stack[-1]
        try:
            next_vertex = adj_matrix[current_vertex - 1].index(1) + 1
        except ValueError:
            # print('err')
            vertex_visit_stack.pop()
            vertex_color_list[current_vertex] = BLACK
            time += 1
            vertex_f_time[current_vertex] += time
        else:
            if vertex_color_list[next_vertex] == WHITE:
                # print('w2g', current_vertex, next_vertex, vertex_color_list[next_vertex])
                vertex_color_list[next_vertex] = GRAY
                time += 1
                vertex_d_time[next_vertex] += time
                vertex_visit_stack.append(next_vertex)
                # node A to B only visit once
                adj_matrix[current_vertex - 1][next_vertex - 1] = 0
            else:
                time += 1
                vertex_f_time[current_vertex] += time
                vertex_visit_stack.pop()
    return None


if __name__ == '__main__':
    _input = sys.stdin.readlines()
    vertex_num = int(_input[0])
    vertex_info = list(map(lambda x: x.split(), _input[1:]))
    init_adj_matrix = [[0] * vertex_num for _ in range(vertex_num)]
    # assert len(vertex_info) == vertex_num

    vertex_visit_stack = [-1]
    vertex_color_list = [WHITE] * (vertex_num + 1)
    vertex_d_time, vertex_f_time = [0] * (vertex_num + 1), [0] * (vertex_num + 1)
    adj_matrix = generate_adj(vertex_info)

    graph_dfs(start_node_index=1)
    for i in range(vertex_num):
        print(i + 1, vertex_d_time[i + 1], vertex_f_time[i + 1])