Go: package main

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

var scanner = bufio.NewScanner(os.Stdin)

func nextString() string {
	scanner.Scan()
	return scanner.Text()
}

func nextInt() int {
	n, err := strconv.Atoi(nextString())
	if err != nil {
		fmt.Printf("strconv.Atoi failed: %v\n", err)
	}
	return n
}

var infty = 1000000000

type nodeKey int

type DirectedGraphNode struct {
	key       nodeKey
	adjacents []*DirectedGraphNode
	visited   bool
	d         int
	f         int
	parent    *DirectedGraphNode
}

type DirectedGraph struct {
	nodes []*DirectedGraphNode
}

func (g *DirectedGraph) setAdjacency(l, r nodeKey) {
	g.nodes[l].adjacents = append(g.nodes[l].adjacents, g.nodes[r])
}

func newDirectedGraph(nNodes int) *DirectedGraph {
	graph := DirectedGraph{}
	graph.nodes = make([]*DirectedGraphNode, nNodes)
	for iNodes := 0; iNodes < nNodes; iNodes++ {
		graph.nodes[iNodes] = &DirectedGraphNode{}
		graph.nodes[iNodes].key = nodeKey(iNodes)

		graph.nodes[iNodes].visited = false
		graph.nodes[iNodes].d = infty
		graph.nodes[iNodes].f = infty
		graph.nodes[iNodes].parent = nil
	}
	return &graph
}

type QueueEntry struct {
	node *DirectedGraphNode
	next *QueueEntry
}

type Queue struct {
	head, tail *QueueEntry
}

func (q *Queue) enqueue(node *DirectedGraphNode) {
	entry := QueueEntry{}
	entry.node = node

	if q.tail == nil {
		q.head = &entry
		q.tail = &entry
		return
	}

	q.tail.next = &entry
	q.tail = q.tail.next
}

func (q *Queue) dequeue() *QueueEntry {
	if q.head == nil {
		return nil
	}
	poped := q.head
	q.head = q.head.next
	if q.head == nil {
		q.tail = nil
	}
	return poped
}

func (q *Queue) isEmpty() bool {
	return q.head == nil
}

var time = 0

func fillDistancesByDepthFirstSearch(g *DirectedGraph) {
	for _, u := range g.nodes[1:] {
		if !u.visited {
			dfsVisit(g, u)
		}
	}
}

func dfsVisit(g *DirectedGraph, u *DirectedGraphNode) {
	time++
	u.d = time

	u.visited = true
	for _, v := range u.adjacents {
		if !v.visited {
			v.parent = u
			dfsVisit(g, v)
		}
	}
	time++
	u.f = time
}

func main() {
	scanner.Split(bufio.ScanWords)

	nNodes := nextInt()
	g := newDirectedGraph(nNodes + 1)

	for iNode := 0; iNode < nNodes; iNode++ {
		nodeKeyLeft := nodeKey(nextInt())
		nAdj := nextInt()
		for iAdj := 0; iAdj < nAdj; iAdj++ {
			nodeKeyRight := nodeKey(nextInt())
			g.setAdjacency(nodeKeyLeft, nodeKeyRight)
		}
	}

	fillDistancesByDepthFirstSearch(g)

	for iNode := 1; iNode <= nNodes; iNode++ {
		node := g.nodes[iNode]
		fmt.Println(node.key, node.d, node.f)
	}
}

Python: 
def DFS(i):
    for j in range(n):
        if A[i][j] == 1 and d[j] == 0:
            time = time + 1
            d[j] = time
            DFS(j)
    time = time + 1
    f[i] = time

n = int(raw_input())
A = [0] * n
for i in range(n):
    A[i] = [0] * n

for i in range(n):
    value = map(int, raw_input().split())
    u = value[0] - 1
    k = value[1]
    nodes = value[2:]
    for i in range(k):
        v = nodes[i] - 1
        A[u][v] = 1

d = [0] * n
f = [0] * n
time = 1
d[0] = time
DFS(0)

for i in range(n):
    print(str(i + 1) + " " + str(d[0]) + " " + str(f[0]))

Python: from collections import defaultdict

def dfs(here, connect, visited, answer):
    global time
    answer[here][1] = time
    time += 1
    visited[here] = 1
    for c in connect[here]:
        if not visited[c]:
            dfs(c, connect, visited, answer)
    answer[here][2] = time
    time += 1

v_num = int(input())
connect = defaultdict(list)
for _ in range(v_num):
    inp = [int(n) - 1 for n in input().split(" ")]
    connect[inp[0]].extend(sorted(inp[2:]))
answer = [[n + 1 for m in range(3)] for n in range(v_num)]
time = 1
visited = [0 for n in range(v_num)]
dfs(0, connect, visited, answer)
for v in range(v_num):
    print(*answer[v])

Python: from collections import deque
time = 1

def dfs(adj_list, d, f, color, u):

    global time
    S = list()

    S.append(u)
    color[u] = "G"
    d[u] = time
    time += 1

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

        if len(adj_list[u]) != 0:
            v = adj_list[u].popleft()

            if color[v] == "W":
                color[v] = "G"
                d[v] = time
                time += 1
                S.append(v)
        else:
            S.pop()
            color[u] = "B"
            f[u] = time
            time += 1

def Main():
    
    N = int(input())
    adj_list = [deque() for n in range(N)]
    d = [0] * N
    f = [0] * N
    color = [ "W" for i in range(len(d)) ]

    for n in range(N):
        u, k, *V = map(int, input().split())

        if k > 0:
            for i in V:
                adj_list[n].append(i - 1)

    while(True):

        ind = None
        for i in range(N):
            if color[i] == "W":
                ind = i
                break

        if ind == None:
            break
        else:
            dfs(adj_list, d, f, color, ind)

    for i in range(N):
        print("{} {} {}".format(i + 1, d[i], f[i] ))

Main()

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)
    d_time[v_init] += time
    # init end

    while stack:
        current = stack[-1]
        v_table = adj_table[current]
        color[current]=VISITED_IN_STACK
        # 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):
        if color[i + 1] == UNVISITED:
            # print('round: ', i + 1)
            graph_dfs(i + 1)
            time += 1


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

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

    adj_table = generate_adj_matrix(v_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())
D=[0]*(n+1)
F=[0]*(n+1)
v=[[] for i in range(n+1)]
flg=True
t=1
for i in range(n):
  a=list(map(int,input().split()))
  v[a[0]]=sorted(a[2:])

def dfs(p):
  global t
  if D[p]!=0: return
  D[p]=t
  t+=1
  for i in v[p]:
    if D[i]==0: dfs(i)
  F[p]=t
  t+=1

while flg:
  flg=False
  for i in range(1,n+1):
    if D[i]==0:
      flg=True
      dfs(i)

for i in range(1,n+1):
  print(f'{i} {D[i]} {F[i]}')