Go: package main

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

const (
	initialBufSize = 100000
	maxBufSize     = 1000000
)

var sc *bufio.Scanner

func initScanner(r io.Reader) *bufio.Scanner {
	buf := make([]byte, initialBufSize)

	sc := bufio.NewScanner(r)
	sc.Buffer(buf, maxBufSize)
	sc.Split(bufio.ScanWords) // bufio.ScanLines
	return sc
}

func main() {
	sc = initScanner(os.Stdin)
	resolve(parseProblem())
}

type graph struct {
	size  int
	edges [][]int
}

func parseProblem() *graph {
	n := scanInt(sc)
	g := &graph{
		size:  n,
		edges: make([][]int, n),
	}
	for i := 0; i < g.size; i++ {
		_ = scanInt(sc)
		k := scanInt(sc)
		g.edges[i] = make([]int, k)
		for j := 0; j < k; j++ {
			g.edges[i][j] = scanInt(sc) - 1
		}
	}
	return g
}

func resolve(g *graph) {
	ds := make([]int, g.size)
	fs := make([]int, g.size)
	time := 0
	for i := 0; i < len(ds); i++ {
		if ds[i] == 0 {
			time++
			time = _dfs(ds, fs, time, g, i)
		}
	}
	for i := 0; i < len(ds); i++ {
		fmt.Println(i+1, ds[i], fs[i])
	}
	return
}

func _dfs(ds, fs []int, time int, g *graph, idx int) int {
	ds[idx] = time
	for _, next := range g.edges[idx] {
		if ds[next] > 0 {
			continue
		}
		time++
		time = _dfs(ds, fs, time, g, next)
	}
	time++
	fs[idx] = time
	return time
}

// snip-scan-funcs
func scanInt(sc *bufio.Scanner) int {
	sc.Scan()
	i, _ := strconv.Atoi(sc.Text())
	return int(i)
}
func scanString(sc *bufio.Scanner) string {
	sc.Scan()
	return sc.Text()
}

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

import sys

UNVISITED, VISITED_IN_STACK, POPPED_OUT = 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(v_init):
    global time
    # init the first node of overall graph iterations(times >= 1)
    vertex_visit_stack.append(v_init)
    vertex_status_list[v_init] = VISITED_IN_STACK
    vertex_d_time[v_init] += time
    # init end
    while len(vertex_visit_stack) > 1:
        current_vertex = vertex_visit_stack[-1]
        next_vertex = get_next_vertex(node=current_vertex)
        # print(current_vertex, next_vertex, vertex_status_list, vertex_visit_stack)
        time += 1
        if next_vertex and vertex_status_list[next_vertex] is UNVISITED:
            # print('on', current_vertex, next_vertex)
            vertex_status_list[next_vertex] = VISITED_IN_STACK
            vertex_d_time[next_vertex] += time
            vertex_visit_stack.append(next_vertex)
        else:
            # other_vertex = get_next_vertex(current_vertex)
            # print('stuck', current_vertex, other_vertex)
            vertex_visit_stack.pop()
            vertex_status_list[current_vertex] = POPPED_OUT
            vertex_f_time[current_vertex] += time

    return None


def get_next_vertex(node):
    for j in range(vertex_num):
        if adj_matrix[int(node) - 1][j]:
            adj_matrix[int(node) - 1][j] = 0
            return j + 1


def dfs_start():
    global time
    for i in range(vertex_num):
        if vertex_status_list[i + 1] == UNVISITED:
            # print('round', i + 1)
            graph_dfs(v_init=i + 1)
            time += 1


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
    # config length -> (vertex_num + 1)
    vertex_visit_stack = [-1]
    vertex_status_list = [UNVISITED] * vertex_num
    vertex_status_list.insert(0, -1)
    vertex_d_time, vertex_f_time = ([0] * (vertex_num + 1) for _ in range(2))

    adj_matrix = generate_adj(vertex_info)

    time = 1
    dfs_start()

    for k in range(vertex_num):
        print(k + 1, vertex_d_time[k + 1], vertex_f_time[k + 1])

Python: from sys import stdin
input = stdin.readline

N = 100
WHITE = 0 # 未訪問
GRAY = 1 # 訪問したが、スタックに残っている
BLACK = 2 # 訪問完了済み

M = [[0]*N for _ in range(N)] # n*nの隣接行列の作成
color = [WHITE]*N  # colorの初期化
d = [0]*N # 最初の訪問時刻のタイムスタンプ
f = [0]*N # 完了時刻のタイムスタンプ

def dfs_visit(u): # uの訪問処理
    global tt
    color[u] = GRAY
    tt += 1
    d[u] = tt # 最初の訪問
    for v in range(n):
        if M[u][v] == 0:
            continue
        if color[v] == WHITE: # 深さがあれば再帰的に処理をする
            dfs_visit(v)
    color[u] = BLACK # uに関する全ての深さを探索しきった処理
    tt += 1
    f[u] = tt # 訪問の完了

def dfs():
    global tt
    tt = 0

    for u in range(n):
        if color[u] == WHITE: # 未訪問のuを始点にする
            dfs_visit(u)
    for u in range(n): # 最終的な表示処理
        print(str(u+1) + ' ' + str(d[u]) + ' ' + str(f[u]))

n = int(input())
for _ in range(n): # 隣接行列の作成
    u, k, *vv = input().split()
    u = int(u)-1  # 0オリジンにする
    k = int(k)    # kは使わない
    for v in vv:
        v = int(v)-1
        M[u][v] = 1
dfs()

Python: def dfs(v, k):
    if ans[v][1] == 0:
        ans[v][1] = k
    else:
        return k - 1
    for i in d[v]:
        k = dfs(i, k + 1)
    k += 1
    if ans[v][2] == 0:
        ans[v][2] = k
    return k


G = int(input())
vlst = [list(map(int, input().split())) for _ in range(G)]
d = [[] for _ in range(G)]
for i in range(G):
    for j in range(vlst[i][1]):
        d[i].append(vlst[i][2 + j] - 1)
ans = [[_, 0, 0] for _ in range(G)]
k = 1
for i in range(G):
    k = dfs(i, k) + 1
for i in ans:
    print(i[0] + 1, i[1], i[2])

Python: from collections import defaultdict


n = int(input())
rel = defaultdict(set)

times = {}
for _ in range(n):
    rl = list(map(int, input().split()))
    p, ts = rl[0], rl[2:]
    rel[p] = sorted(ts, reverse=True)
    times[p] = {'first': 0, 'last': 0}

t = 0

for f in range(1, len(rel)+1):
    if times[f]['last']:
        continue
    stack = [f]
    while stack:
        u = stack[-1]
        if times[u]['first']:
            if not times[u]['last']:
                t += 1
                times[u]['last'] = t
            stack.pop()
            continue
        t += 1
        times[u]['first'] = t
        for v in rel[u]:
            if not times[v]['first']:
                stack.append(v)

for k in sorted(times):
    print(k, times[k]['first'], times[k]['last'])

Python: import sys
sys.setrecursionlimit(10000000)
MOD = 10 ** 9 + 7
INF = 10 ** 15

G = [[] for _ in range(105)]
begin = [-1] * 105
end = [-1] * 105

t = 1
def dfs(v):
    global t
    begin[v] = t
    t += 1
    for e in G[v]:
        if begin[e] < 0:
            dfs(e)
    end[v] = t
    t += 1

def main():
    N = int(input())
    for i in range(N):
        A = list(map(int,input().split()))
        for a in A[2:]:
            G[i].append(a - 1)
    
    for i in range(N):
        if begin[i] < 0:
            dfs(i)
    for i in range(N):
        print(i + 1,begin[i],end[i])
if __name__ == '__main__':
    main()

Python: 
#kadai11b Depth First Search

n=int(input())
t=1
a=[[0 for i in range(n)]for j in range(n)]
t1=[0 for i in range(n)]
t2=[0 for i in range(n)]
s=[]
c=[]
s.append(0)
t1[0]=t
t+=1
for i in range(n):
    p=[int(x) for x in input().split()]
    for j in range(n):
        if j+1 in p[2:]:
            a[i][j]=1

i=0
while len(c)!=n:
    if 1 not in a[i][0:]:
        if i not in c:
            t2[i]=t
            t+=1
            c.append(i)
            del s[-1]
            if len(s)>0:
                i=s[-1]
    for j in range(n):
        if a[i][j]==1:
            a[i][j]=0
            if j not in c:
                s.append(j)
                i=j
                t1[i]=t
                t+=1
            break

for i in range(n):
    print(i+1,t1[i],t2[i])

"""実行結果
6
1 2 2 3
2 2 3 4
3 1 5
4 1 6
5 1 6
6 0
1 1 12
2 2 11
3 3 8
4 9 10
5 4 7
6 5 6
"""