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: n=int(input())

l=[[0 for i in range(n)] for j in range(n)]##静的確保 隣接行列
d=[0 for i in range(n)]##発見
f=[0 for i in range(n)]##完了
stack=[]##スタック
check=[]

for i in range(n):
    p=[int(x) for x in input().split()]
    
    for j in range(n):
        if j+1 in p[2:]:
            l[i][j]=1
##print("---隣接行列---")
##print(l)

time=1


while len(check)<n:
    for i in range(n):
        if i+1 not in check:
            stack+=[i+1]
            d[i]=time
            break
        else: pass

    while len(stack)!=0:
        ##print("----------while---------")
        for i in range(n):
            if l[stack[-1]-1][i]==1 and not i+1 in check and stack[-1]-1!=i:
                time+=1
                d[i]=time
                stack+=[i+1]

               ## print("stack:",stack)
               ## print("check:",check)
               ## print("d[",i,"]:",d[i])
                break
            elif i==n-1:
##最深    
                check+=[stack[-1]]
                time+=1
                f[stack.pop()-1]=time

               ## print("f[",i,"]:",f[i])
               ## print("check:",check)
    time+=1


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

Python: from collections import deque

def dfs(v):
    global t
    
    d[v] = t
    visited[v] = True
    t += 1
    
    for u in graph[v]:
        if not visited[u]: dfs(u)
    f[v] = t
    t += 1
    
    
n = int(input())
graph = [deque() for i in range(n)]

visited = [False] * n
d = [0] * n
f = [0] * n
t = 1

for i in range(n):
    nums = list(map(int, input().split()))
    for j in nums[2:]:
        graph[i].append(j-1)
         
for i in range(n):
    if not visited[i]: dfs(i)

for idx, df in enumerate(zip(d, f)):
    print(idx+1, df[0], df[1])

Python: from collections import defaultdict

def dfs(edges, n, d, f, time):
    if n in d:
        return
    time[0] += 1
    d[n] = time[0]
    for to in edges[n]:
        dfs(edges, to, d, f, time)
    time[0] += 1
    f[n] = time[0]

N = int(input())

edges = defaultdict(list)

for _ in range(N):
    l = list(map(int, input().split()))
    fr = l[0]
    degree = l[1]
    edges[fr] = l[2:]

d = {} # discover time                                                                                                                                                                                      
f = {} # finish time                                                                                                                                                                                        

time = [0]
for n in range(1, N+1):
    dfs(edges, n, d, f, time)

for n in range(1, N+1):
    print('%d %d %d' % (n, d[n], f[n]))

Python: def depth_search(i, adj, d, f, t):
    if d[i - 1]:
        return t
    d[i - 1] = t
    t += 1
    for v in adj[i - 1]:
        t = depth_search(v, adj, d, f, t)
    f[i - 1] = t
    t += 1
    return t
n = int(input())
adj = [list(map(int, input().split()))[2:] for _ in range(n)]

d = [0] * n
f = [0] * n

t = 1
for i in range(n):
    if d[i] == 0:
        t = depth_search(i + 1, adj, d, f, t)

for i, df in enumerate(zip(d, f)):
    print(i + 1, *df)

Python: from enum import Enum

class Dfs(object):
    """ Depth First Search """
    class Status(Enum):
        white = 1
        gray = 2
        black = 3

    def __init__(self, data):
        self.time = 0
        num_of_nodes = len(data)+1
        self.color = [Dfs.Status.white] * (num_of_nodes+1)
        self.S = []
        self.M = self._make_matrix(data)
        self.s_time = [0] * (len(data) + 1)
        self.f_time = [0] * (len(data) + 1)

    def _make_matrix(self, data):
        """ ??£??\??????????????? (M[i][j]?????¢??§??????????????????+1??????????????????????????????) """
        num = len(data)
        graph_table = [[0] * (num+1) for _ in range(num+1)]
        for d in data:
            node_id = d[0]
            num_of_e = d[1]
            for e in d[2:]:
                graph_table[node_id][e] = 1
        return graph_table

    def search(self, start):
        self.time += 1
        self.s_time[start] = self.time
        self.S.append(start)
        self.color[start] = Dfs.Status.gray

        while self.S:
            u = self.S[-1]
            v = self.next(u)
            if v != None:
                if self.color[v] == Dfs.Status.white:
                    self.color[v] = Dfs.Status.gray
                    self.time += 1
                    self.s_time[v] = self.time
                    self.S.append((v))
            else:
                self.S = self.S[:-1]
                self.color[u] = Dfs.Status.black
                self.time += 1
                self.f_time[u] = self.time

    def next(self, node):
        """ ?¬?????¨???????????±???????????????????????????????????????????????¨??????????????????????????????? """
        edges = self.M[node]
        for i in range(1, len(edges)):
            if edges[i] == 1:
                if self.color[i] == Dfs.Status.white:
                    return i
        return None

    def print(self):
        for r in self.M:
            print(*r)



if __name__ == '__main__':
    # ??????????????\???
    num = int(input())
    data = []
    for _ in range(num):
        data.append(list(map(int, input().split(' '))))

    # ???????????????
    d = Dfs(data)
    # d.print()
    d.search(1)

    # ???????????????
    for i in range(1, num+1):
        print('{0} {1} {2}'.format(i, d.s_time[i], d.f_time[i]))

Python: import sys
sys.setrecursionlimit(10**6)

n = int(input())
graph = []
chart = [[int(i)] for i in range(1,n+1)]
for i in range(n):
    z = [c-1 for c in list(map(int,input().split()))][2:]
    graph.append(z)
time = 0

def dfs(nod):
    global graph
    global time
    #break condition
    if len(chart[nod]) != 1:
        return 
    #end condition not necessary
    #if not graph[nod]:
    #    time += 1
    #    chart[nod].append(time)
    #    return
    # command
    time += 1
    chart[nod].append(time)
    
    # move
    for dis in graph[nod]:
            dfs(dis)

    # post-command
    time += 1
    chart[nod].append(time)
for i in range(n):
    dfs(i)
for i in range(n):
    print(*chart[i])