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: def get_unvisted_child(v, timestamp):
  while len(G[v]) > 0:
    c = G[v].pop(0)
    if not c in timestamp: return c
  return -1

def get_unvisited_node(G, timestamp):
  for v in sorted(G):
    if not v in timestamp: return v
  return -1

def dept_first_search(G):
  t = 1
  timestamp = {}
  stack = []

  v = get_unvisited_node(G, timestamp)
  while v > 0:
    stack.append(v)
    timestamp[v] = [t]
    t += 1

    while len(stack) > 0:
      v = stack[-1]
      c = get_unvisted_child(v, timestamp)
      if c > 0:
        #c = G[v].pop(0)
        stack.append(c)
        timestamp[c] = [t]
      else:
        timestamp[v].append(t)
        stack.pop()
      t += 1

    v = get_unvisited_node(G, timestamp)

  for v in sorted(timestamp):
    print(v, *timestamp[v])

G = {}
for i in range(int(input())):
  x = list(map(int, input().split()))
  G[x[0]] = x[2:]

dept_first_search(G)

Python: def d(u):
 global t
 C[u]=1;D[u]=t;t+=1
 for v in M[u]:v=int(v)-1;C[v]or d(v)
 F[u]=t;t+=1
N=int(input());R=range(N)
M=[input().split()[2:]for _ in R]
C,D,F=[0]*N,[0]*N,[0]*N
t=1
for i in R:C[i]or d(i)
for i in R:print(i+1,D[i],F[i])

Python: #!/usr/bin/env python3

import sys
import math
from bisect import bisect_right as br
from bisect import bisect_left as bl
sys.setrecursionlimit(2147483647)
from heapq import heappush, heappop,heappushpop
from collections import defaultdict
from itertools import accumulate
from collections import Counter
from collections import deque
from operator import itemgetter
from itertools import permutations
mod = 10**9 + 7
inf = float('inf')
def I(): return int(sys.stdin.readline())
def LI(): return list(map(int,sys.stdin.readline().split()))

cnt = 1
def dfs(x):
    global cnt
    if s[x] == None:
        s[x] = cnt
        cnt += 1
    for v in edges[x]:
        if s[v] == None:
            dfs(v)
    g[x] = cnt
    cnt += 1
    return 

n = I()
edges = [[] for _ in range(n)]
for i in range(n):
    edges[i] = list(map(lambda x:x-1,LI()[2:]))

s = [None]*n
g = [None]*n
for i in range(n):
    if s[i] == None:
        dfs(i)
for i in range(n):
    print(i+1,s[i],g[i])

Python: from typing import List


def dfs(adj_matrix: List[List[int]], vartex: int) -> int:
    global step
    global discover_times
    global finish_times
    if 0 != discover_times[vartex]:
        return 0
    discover_times[vartex] = step

    for col_idx in range(len(adj_matrix)):
        if (0 != adj_matrix[vartex][col_idx]) and (0 == discover_times[col_idx]):
            step += 1
            dfs(adj_matrix, col_idx)

    step += 1
    finish_times[vartex] = step

    return 1


if __name__ == "__main__":
    num_vertices = int(input())
    adj_matrix = [[0] * num_vertices for i in range(num_vertices)]

    for _ in range(num_vertices):
        vertex, _, *adjs = map(lambda x: int(x), input().split())
        for adj in adjs:
            adj_matrix[vertex - 1][adj - 1] = 1

    step = 1
    discover_times = [0] * num_vertices
    finish_times = [0] * num_vertices

    for vartex in range(num_vertices):
        if 1 == dfs(adj_matrix, vartex):
            step += 1

    for vertex, (d, f) in enumerate(zip(discover_times, finish_times)):
        print(f"{vertex + 1} {d} {f}")

Python: def dfs(u, node_info, matrix):
    # ????????????????????¨??????????????????
    colors = [0] * len(matrix)
    detect_time = [0] * len(matrix)
    finished_time = [0] * len(matrix)
    time = 1
    stack = list()
    stack.append(u)
    colors[u] = 1
    detect_time[u] = time
    while len(stack):
        for i, val in enumerate(matrix[u]):
            if val == 1 and colors[i] == 0:
                time += 1
                stack.append(i)
                colors[i] = 1
                detect_time[i] = time
                u = i
                break
        else:
            time += 1
            e = stack.pop()
            colors[e] = 2
            finished_time[e] = time
            if len(stack):
                u = stack[-1]
    for i in range(len(matrix)):
        print('{} {} {}'.format(i + 1, detect_time[i], finished_time[i]))


if __name__ == '__main__':
    N = int(input())
    matrix = [[0] * N for _ in range(N)]
    color = [0] * N
    for i in matrix:
        node_info = [int(i) for i in input().split()]
        node_i = node_info[0] - 1
        if not node_info[1] == 0:
            for i in node_info[2:]:
                matrix[node_i][i - 1] = 1
    dfs(0, None, matrix)

Python: def dfs(G, u, t, d, visited):
  found = t
  visited.add(u)
  t += 1
  for v in G[u]:
    if v not in visited:
      t = dfs(G, v, t, d, visited)
  complete = t
  d[u] = (found, complete)
  t+=1
  return t


n = int(input())
G = {}
for _ in range(n):
  entries = list(map(int, input().split(' ')))
  u = entries[0]
  k = entries[1]
  G[u] = set()
  for v in entries[2:]:
    G[u].add(v)

d = {}
visited = set()
t = 1
for i in range(1,n+1):
  if i not in visited:
    t = dfs(G, i, t, d, visited)
for i in sorted(d):
  print(i,d[i][0],d[i][1])