Go: package main

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

// repr state of visited node
// WHITE yet visit
// GEAY  visiting
// BLACK visited
const (
	WHITE int = iota
	GRAY
	BLACK
)

type dfsGraph struct {
	g      [][]int
	colors []int
	stime  []int // Start time of visiting node
	ftime  []int // Finish time of visiting node
}

var time int

func makeAdjList() [][]int {
	var n int
	fmt.Scanf("%d", &n)

	adj := make([][]int, n)
	for i := 0; i < n; i++ {
		adj[i] = make([]int, n)
	}

	sc := bufio.NewScanner(os.Stdin)
	for i := 0; i < n; i++ {
		sc.Scan()
		nodeInfo := strings.Split(sc.Text(), " ")
		outDegree, _ := strconv.Atoi(nodeInfo[1])

		if outDegree > 0 {
			for k := 0; k < outDegree; k++ {
				j, _ := strconv.Atoi(nodeInfo[k+2])
				j-- // convert 1 based to 0 based
				adj[i][j] = 1
			}
		}
	}

	return adj
}

func (dg dfsGraph) dfsVisit(u int) {
	// 頂点uを訪問中に設定
	dg.colors[u] = GRAY
	time++
	dg.stime[u] = time

	// uの隣接nodeを訪問
	for v := 0; v < len(dg.g); v++ {
		if dg.g[u][v] == 0 {
			continue // 辺がなければスキップ
		}

		// vが未訪問なら訪問
		if dg.colors[v] == WHITE {
			dg.dfsVisit(v)
		}
	}

	// 頂点uを訪問済みに設定
	dg.colors[u] = BLACK
	time++
	dg.ftime[u] = time
}

func (dg dfsGraph) dfs() {
	for i := 0; i < len(dg.g); i++ {
		if dg.colors[i] == WHITE {
			dg.dfsVisit(i)
		}
	}
}

func (dg dfsGraph) printDfsTime() {
	for i := 0; i < len(dg.g); i++ {
		fmt.Printf("%d %d %d\n", i+1, dg.stime[i], dg.ftime[i])
	}
}

func main() {
	adj := makeAdjList()
	colors := make([]int, len(adj))
	stime := make([]int, len(adj))
	ftime := make([]int, len(adj))
	graph := dfsGraph{adj, colors, stime, ftime}
	graph.dfs()
	graph.printDfsTime()
}

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

"""
input:
6
1 2 2 3
2 2 3 4
3 1 5
4 1 6
5 1 6
6 0

output:
1 1 12
2 2 11
3 3 8
4 9 10
5 4 7
6 5 6
"""
import sys

UNVISITED, VISITED_IN_STACK, POPPED_OUT = 0, 1, 2


def generate_adj_matrix(v_info):
    for v_detail in v_info:
        v_index, adj_num, *adj_list = map(int, v_detail)
        # assert len(adj_list) == adj_num
        init_adj_table[v_index].extend(sorted(adj_list, reverse=True))
    return init_adj_table


def graph_dfs(v_init):
    global time

    # init the first node of overall graph iterations(times >= 1)
    stack.append(v_init)
    color[v_init] = VISITED_IN_STACK
    d_time[v_init] += time
    # init end

    while stack:
        current = stack[-1]
        v_table = adj_table[current]
        # if adj is None, current's adj(s) have been all visited
        adj = v_table.pop() if v_table else None

        if adj:
            if color[adj] is UNVISITED:
                color[adj] = VISITED_IN_STACK
                time += 1
                d_time[adj] += time
                stack.append(adj)
        else:
            stack.pop()
            color[current] = POPPED_OUT
            time += 1
            f_time[current] += time

    return None


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


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

    # config length = (vertex_num + 1)
    stack = []
    color = [UNVISITED] * (vertices_num + 1)
    d_time, f_time = ([0] * (vertices_num + 1) for _ in range(2))

    adj_table = generate_adj_matrix(vertices_info)
    # timing start from 1
    time = 1
    dfs_start()

    for index, v in enumerate(zip(d_time[1:], f_time[1:]), 1):
        print(index, *v)

Python: n=int(input())
adj=[]
for i in range(n):
	a=list(map(int,input().split()))
	for j in range(2,len(a)):
		a[j]-=1
	adj.append(a[2:])
visit_time1=[0]*n
visit_time2=[0]*n
visited=[0]*n
def dfs(now):
	global time
	visit_time1[now]=time
	time+=1
	for next in adj[now]:
		if not visited[next]:
			visited[next]=True
			dfs(next)
	visit_time2[now]=time
	time+=1
time=1
for i in range(n):
	if not visited[i]:
		visited[i]=True
		dfs(i)
for i in range(n):
	print(i+1,visit_time1[i],visit_time2[i])

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]