Go: package main

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

const MAX = 101

var f [MAX]int
var d [MAX]int
var list [][]int
var sc = bufio.NewScanner(os.Stdin)

func scanInt() int {
	num, _ := strconv.Atoi(scanString())
	return num
}

func scanString() string {
	sc.Scan()
	return sc.Text()
}

func init() {
	sc.Split(bufio.ScanWords)
}

func dfs(u, cnt int) int {
	if d[u] != 0 {
		return cnt
	}

	cnt++
	d[u] = cnt
	for _, next := range list[u] {
		cnt = dfs(next, cnt)
	}
	cnt++
	f[u] = cnt
	return cnt
}

func main() {
	n := scanInt()
	list = make([][]int, n+1)
	for i := 1; i <= n; i++ {
		u := scanInt()
		k := scanInt()
		for j := 0; j < k; j++ {
			n := scanInt()
			list[u] = append(list[u], n)
		}
	}

	cnt := 0
	for i := 1; i <= n; i++ {
		cnt = dfs(i, cnt)
	}

	w := bufio.NewWriter(os.Stdout)
	for i := 1; i <= n; i++ {
		fmt.Fprint(w, i)
		fmt.Fprint(w, " ")
		fmt.Fprint(w, d[i])
		fmt.Fprint(w, " ")
		fmt.Fprint(w, f[i])
		fmt.Fprintln(w)
	}
	w.Flush()
}

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

import sys

UNVISITED, VISITED_IN_STACK, POPPED_OUT = 0, 1, 2


def generate_adj_matrix(v_info):
    for v_detail in v_info:
        v_adj_list = v_detail[2:]
        assert len(v_adj_list) == int(v_detail[1])
        for each in v_adj_list:
            init_adj_matrix[int(v_detail[0]) - 1][int(each) - 1] = 1
    return init_adj_matrix


def graph_dfs(v_init):
    global time

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

    while len(vertex_visit_stack) > 1:
        current_vertex = vertex_visit_stack[-1]
        next_vertex = get_adj_vertices(_vertex=current_vertex)

        if next_vertex:
            if vertex_status_list[next_vertex] is UNVISITED:
                vertex_status_list[next_vertex] = VISITED_IN_STACK
                time += 1
                vertex_d_time[next_vertex] += time
                vertex_visit_stack.append(next_vertex)
        else:
            vertex_visit_stack.pop()
            vertex_status_list[current_vertex] = POPPED_OUT
            time += 1
            vertex_f_time[current_vertex] += time

    return None


def get_adj_vertices(_vertex):
    for j in range(vertex_num):
        if adj_matrix[int(_vertex) - 1][j]:
            adj_matrix[int(_vertex) - 1][j] = 0
            return j + 1
    return None


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


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

    # config length = (vertex_num + 1)
    vertex_visit_stack = [-1]
    vertex_status_list = [UNVISITED] * vertex_num
    vertex_status_list.insert(0, -1)
    vertex_d_time, vertex_f_time = ([0] * (vertex_num + 1) for _ in range(2))

    adj_matrix = generate_adj_matrix(vertex_info)
    time = 1
    dfs_start()
    for k in range(vertex_num):
        print(k + 1, vertex_d_time[k + 1], vertex_f_time[k + 1])

Python: n = int(input())
graph = [-1] + [list(map(int, input().split())) for _ in range(n)]
seen = [False]*(n+1)
seen[0] = True
d = [-1]*(n+1)
f = [-1]*(n+1)
time = 0


def dfs(v):
    global time
    time += 1
    d[v] = time
    seen[v] = True
    k = graph[v][1]
    if k > 0:
        for i in range(k):
            w = graph[v][i+2]
            if seen[w] is False:
                dfs(w)
    
    time += 1
    f[v] = time

v = 0
while v <= n:
    if seen[v] is False:
        dfs(v)
    
    v += 1

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

Python: class Vertex:
    def __init__(self,key):
        self.id = key
        self.connectedTo = {}
        self.color = 'white'
        self.dist =10000000
        self.pred = None
        self.disc = 0
        self.fin = 0
    
    def addNeighbor(self,nbr,weight=0):
        self.connectedTo[nbr] = weight

    def setColor(self,color):
        self.color = color

    def setDistance(self,d):
        self.dist = d

    def setPred(self,p):
        self.pred = p

    def setDiscovery(self,dtime):
        self.disc = dtime
        
    def setFinish(self,ftime):
        self.fin = ftime
        
    def getFinish(self):
        return self.fin
        
    def getDiscovery(self):
        return self.disc
        
    def getPred(self):
        return self.pred
        
    def getDistance(self):
        return self.dist
        
    def getColor(self):
        return self.color

    def getConnections(self):
        return self.connectedTo.keys()

    def getWeight(self,nbr):
        return self.connectedTo[nbr]

    def __str__(self):
        return str(self.id) + ' connectedTo: ' + str([x.id for x in self.connectedTo])

    def getId(self):
        return self.id


class Graph:
    def __init__(self):
        self.vertList = {}
        self.costList={}
        self.numVertices = 0

    def addVertex(self,key):
        self.numVertices = self.numVertices + 1
        newVertex = Vertex(key)
        self.vertList[key] = newVertex
        return newVertex

    def getVertex(self,n):
        if n in self.vertList:
            return self.vertList[n]
        else:
            return None

    def __contains__(self,n):
        return n in self.vertList

    def addEdge(self,f,t,cost=0):
        if f not in self.vertList:
            nv = self.addVertex(f)
        if t not in self.vertList:
            nv = self.addVertex(t)
        self.vertList[f].addNeighbor(self.vertList[t], cost)

    def getVertices(self):
        return self.vertlist.keys()

    def __iter__(self):
        return iter(self.vertList.values())


class DFSGraph(Graph):
	def __init__(self):
		super().__init__()
		self.time = 0

	def dfs(self):
		for aVertex in self:
			aVertex.setColor('white')
			aVertex.setPred(-1)
		for aVertex in self:
			if aVertex.getColor() == 'white':
				self.dfsvisit(aVertex)

	def dfsvisit(self,startVertex):

		for aVertex in self:
			aVertex.setColor('white')
			aVertex.setPred(-1)

		startVertex.setColor('gray')
		self.time += 1
		startVertex.setDiscovery(self.time)
		for nextVertex in startVertex.getConnections():
			if nextVertex.getColor() == 'white':
				nextVertex.setPred(startVertex)
				self.dfsvisit(nextVertex)
		startVertex.setColor('black')
		self.time += 1
		startVertex.setFinish(self.time)

Python: 
#graphの頂点vertex(インデックス、0オリジン)を深さ優先探索。dis_time:最初に訪れた時のtimeを管理するリスト
#fin_time:その頂点に対して、探索が終わった時のtimeを管理するリスト　tmp_time:現在のtime(関数内で変更できるようにリスト)
def DPS(graph,vertex,dis_time,fin_time,tmp_time):
    dis_time[vertex]=tmp_time[0]
    for i in range(len(graph[0])):
        if(graph[vertex][i] !=0 and dis_time[i]==0):#枝先の頂点が探索済みでなかったら、
            tmp_time[0]+=1
            DPS(graph,i,dis_time,fin_time,tmp_time)
    
    if(dis_time[vertex]==tmp_time[0]):#vertexから、どの頂点に対しても調査が進まなかったら
        tmp_time[0]+=1
    fin_time[vertex]=tmp_time[0]
    tmp_time[0]+=1



#グラフの作成
n=int(input())
graph=[[0]*n for loop in range(n)]
for loop in range(n):
    tmp_ope=list(map(int,input().split()))
    for j in range(tmp_ope[1]):
        graph[tmp_ope[0]-1][tmp_ope[j+2]-1]=1

dis_time=[0]*n
fin_time=[0]*n
tmp_time=[1]
DPS(graph,0,dis_time,fin_time,tmp_time)

for i in range(n):
    print(f"{i+1} {dis_time[i]} {fin_time[i]}")