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: from collections import deque
n = int(input())
v = {i:[] for i in range(n)}
for i in range(n):
    u = list(map(int, input().split()))
    for j in range(2, 2+u[1]):
        v[u[0]-1].append(u[j]-1)

global cnt1 
cnt1 = 0
visited = [False for _ in range(n)]
f = [0 for _ in range(n)]
l = [0 for _ in range(n)]
def DFS(now, visited):
    global cnt1
    cnt1 += 1
    f[now] = cnt1
    visited[now] = True
    for nv in v[now]:
        if visited[nv]:
            continue
        DFS(nv, visited)
    cnt1 += 1
    l[now] = cnt1

for value in range(n):
    if not visited[value]:
        DFS(value, visited)
    
for i in range(n):
    print(i+1, f[i], l[i])

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: n = int(input())
B = [[0 for i in range(n)] for j in range(n)]
chk = [0 for i in range(n)]
s = []
i_array = [0 for i in range(n)]
time = 1
node_start_time = [0 for i in range(n)]
node_finish_time = [0 for i in range(n)]

for i in range(n):
    A = list(map(int,input().split()))
    for j in range(A[1]):
        B[A[0]-1][A[j+2]-1] = 1

for i in range(n):
    if(chk[i] == 1):
        continue
    chk[i] = 1
    node_start_time[i] = time
    time += 1
    s.append(i)
    while(len(s) != 0):
        flag = 0
        v = s[len(s)-1]
        for j in range(i_array[v],n):
            if(B[v][j] == 1 and chk[j] == 0):
                chk[j] = 1
                s.append(j)
                node_start_time[j] = time
                time += 1
                i_array[v] = j+1
                flag = 1
                break
        if(flag == 0):
            s.pop()
            node_finish_time[v] = time
            time += 1

for i in range(n):
    print(i+1,node_start_time[i],node_finish_time[i])

Python: def main():
    n = int(input())
    _next, state, d, f = [], [False] * n, [0] * n, [0] * n
    for _ in range(n):
        u, k, *v = map(lambda s: int(s) - 1, input().split())
        _next.append(sorted(v, reverse=True))
    stack = []
    time = 0

    while True:
        for i in range(n):
            if not state[i]:
                stack.append(i)
                state[i] = True
                time += 1
                d[i] = time
                break
        if not stack:
            break
        while stack:
            u = stack[-1]
            if _next[u]:
                v = _next[u].pop()
                if not state[v]:
                    state[v] = True
                    time += 1
                    d[v] = time
                    stack.append(v)
            else:
                time += 1
                f[u] = time
                stack.pop()

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


if __name__ == '__main__':
    main()

Python: def dfs(v, cnt):
  D[v] = cnt
  cnt += 1
  for c in edge[v]:
    if D[c] == -1:
      cnt = dfs(c, cnt)
  F[v] = cnt
  cnt += 1
  return cnt

N = int(input())
edge = [[] for _ in range(N)]
for _ in range(N):
  u, _, *v = map(lambda x:int(x)-1, input().split())
  edge[u] = sorted(v)
D, F = [-1] * N, [-1] * N
c = 1
for i in range(N):
  if D[i] == -1:
    c = dfs(i, c)
for i, (d, f) in enumerate(zip(D, F)):
  print(i + 1, d, f)

Python: # =============================================================================
#　Depth First Search
# =============================================================================
import sys
sys.setrecursionlimit(10**8)

N=int(input())
Graph=[list(map(int,input().split()))[2:] for _ in range(N)]
Graph.insert(0,[])
seen=[False for _ in range(N+1)]
first_order=[0]*(N+1)
last_order=[0]*(N+1)
time=1

def dfs(Graph,v):
    global seen
    global time
    seen[v]=True
    first_order[v]=time
    time+=1
    for nv in Graph[v]:
        if seen[nv]:
            continue
        dfs(Graph,nv)

    last_order[v]=time
    time+=1

for v in range(1,N+1):
    if not seen[v]:
        dfs(Graph,v)
for i in range(1,N+1):
    print(i,first_order[i],last_order[i])