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: import sys, math
from itertools import permutations, combinations, accumulate
from collections import defaultdict, Counter, deque
from math import factorial#, gcd
from bisect import bisect_left #bisect_left(list, value)
sys.setrecursionlimit(10**7)
enu = enumerate
MOD = 10**9+7
def input(): return sys.stdin.readline()[:-1]
def pri(x): print('\n'.join(map(str, x)))

N = int(input())
G = [list(map(int, input().split())) for _ in range(N)]
c = [0]*N # 0:not found, 1:found, 2:finished
res = [[0]*2 for _ in range(N)]

time = 1
def dfs(index):
#    print('index:', index)
    global time
    if c[index]==0:
        c[index]=1
        res[index][0] = time # found
        time += 1
    elif c[index]==1:
        return
    elif c[index]==2:
        return

    u, k, *v = G[index]
    for node in v:
        dfs(node-1) # 1-index -> 0-index

    c[index] = 2
    res[index][1] = time # finished
    time += 1
    return

for i in range(N):
    dfs(i)
res = [[val1]+val2 for val1, val2 in zip(list(range(1, N+1)), res)]
for val in res:
    print(*val)

Python: 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])

Python: def dfs(v):
    global t, d, f, visited
    d[v] = t
    visited[v] = True
    t += 1
    for u in AL[v]:
        if not visited[u]:
            dfs(u)
    f[v] = t
    t += 1

# 入力
n = int(input())
AL = [[] for _ in range(n + 1)]
for v in range(1, n + 1):
    AL[v] = [int(x) for x in input().split()][2:]

# 計算
d = [0] * (n + 1)
f = [0] * (n + 1)
t = 1
visited = [False] * (n + 1)
for v in range(1, n + 1):
    if not visited[v]:
        dfs(v)

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

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])