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:    #depth first
N=int(input())
V=[]
a=[0]
for i in range(N):
    V.append([int(i) for i in input().split()])
    w=V[i][2:]
    w.sort()
    V[i]=V[i][:2]+w
    a.append(0)
V=sorted(V,key=lambda x:x[0])
c=1
t=1
i=0
r=[1]
a[1]=1
p=[[1,t]]
q=[]
while t<N*2-1:
    j=2
    while t<N*2-1 and j-2<V[i][1] and V[i][1]>0 and a[V[i][j]]==1:
        j+=1
    t+=1
    if j-2<V[i][1]:
        a[V[i][j]]=1
        c+=1
        r.append(V[i][j])
        p.append([V[i][j],t])
        i=V[i][j]-1
    else:
        q.append(p[-1]+[t])
#end time immediately case?
        r.pop(-1)
        p.pop(-1)
        i=r[-1]-1
       # print(q)
q.append([1,1,N*2])
q=sorted(q,key=lambda x:x[0])
for i in range(N):
    for j in range(3):
        q[i][j]=str(q[i][j])
    print(" ".join(q[i]))

Python: def DFS(G):
    ans = [0] + [[0,0,0] for _ in range(len(G))]
    def main(G,i):
        ans[0] += 1
        ans[i] = [i, ans[0], ans[0]]
        for j in sorted(G[i-1][2:]):
            if ans[j][0]==0: main(G,j)
        ans[0] += 1
        ans[i][2] = ans[0]
    main(G,1)
    return ans[1:]


if __name__=='__main__':
    n = int(input())
    G = [list(map(int,input().split())) for _ in range(n)]
    for out in DFS(G): print(*out)

Python: n = int(input())
graph = [[] for _ in range(n)]

global time
global visited 
global f_time 
global e_time 

time = 1
visited = [0 for _ in range(n)]
f_time = [0 for _ in range(n)]
e_time = [0 for _ in range(n)]

def input_graph(n):
  for _ in range(n):
    node_id, num, *v = list(map(int, input().split()))
    for i in range(num):
      graph[node_id-1].append(v[i]-1)

def dfs(node_id):
  global time
  f_time[node_id] = time
  time += 1

  for ad_node in graph[node_id]:
    if visited[ad_node] == 1:
      continue
    visited[ad_node] = 1
    dfs(ad_node)

  e_time[node_id] = time
  time += 1



if __name__ == "__main__":
  input_graph(n)
  for i in range(n):
    if visited[i] == 1:
      continue
    visited[i] = 1
    dfs(i)

  for i, (f, e) in enumerate(zip(f_time, e_time)):
    print(i+1, f, e)

Python: # -*- coding: utf-8 -*-
import sys
INF=10**18
MOD=10**9+7
def input(): return sys.stdin.readline().rstrip()


c=0
def main():
    N=int(input())
    edge=[[] for _ in range(N)]
    for i in range(N):
        l=list(map(lambda x:int(x)-1,input().split()))
        for x in l[2:]:
            edge[i].append(x)
    d=[-1]*N
    f=[-1]*N
    used=[False]*N
    def dfs(v):
        global c
        used[v]=True
        d[v]=c
        for nv in edge[v]:
            if not used[nv]:
                c+=1
                dfs(nv)
        c+=1
        f[v]=c
    global c
    while not all(used):
        for i in range(N):
            if not used[i]:
                c+=1
                dfs(i)

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

if __name__ == '__main__':
    main()

Python: import math,string,itertools,fractions,heapq,collections,re,array,bisect,sys,random,time

sys.setrecursionlimit(10**7)
inf = 10**20
mod = 10**9 + 7

stdin = sys.stdin

ni = lambda: int(ns())
na = lambda: list(map(int, stdin.readline().split()))
ns = lambda: stdin.readline().rstrip()  # ignore trailing spaces

n = ni()
g = []
for i in range(n):
    t = na()
    u = t[0] - 1
    k = t[1]
    v = [x-1 for x in t[2:]]
    g.append(v)
d = [0] * n
f = [0] * n
#print(g)
seen = [False] * n
s = 0
t = 0
def dfs(g, v):
    global t
    #print(v+1, t)
    if seen[v]:
        return
    seen[v] = True
    d[v] = t
    t += 1    
    for next_v in g[v]:
        #if seen[next_v]: continue
        dfs(g, next_v)
    f[v] = t
    t += 1
for i in range(n):
    if len(g[i]) != 0:
        dfs(g, i)
for i in range(n):
    print(i+1, d[i]+1, f[i]+1)

Python: import sys


def dfs(u):
    global time
    color[u] = "GRAY"
    time += 1
    d[u] = time
    for v in range(n):
        if M[u][v] and color[v] == "WHITE":
            dfs(v)
    color[u] = "BLACK"
    time += 1
    f[u] = time


if __name__ == "__main__":
    n = int(sys.stdin.readline())
    color = ["WHITE"] * n
    time = 0
    d = [-1] * n
    f = [-1] * n
    M = [[0] * n for i in range(n)]
    for inp in sys.stdin.readlines():
        inp = list(map(int, inp.split()))
        for i in inp[2:]:
            M[inp[0]-1][i-1] = 1
    dfs(0)
    for i in range(n):
        print(i+1, d[i], f[i])

Python: # https://onlinejudge.u-aizu.ac.jp/courses/lesson/1/ALDS1/11/ALDS1_11_B

G = {}
d = {}
f = {}
used = set()
t = 1


def dfs(cur):
    global G, d, f, t

    used.add(cur)
    d[cur] = t

    for i in G[cur]:
        if i in used:
            continue
        t += 1
        dfs(i)
    t += 1
    f[cur] = t


if __name__ == "__main__":
    N = int(input())

    for _ in range(N):
        u, k, *V = list(map(int, input().split()))
        G[u] = V

    for i in range(1, N+1):
        if i not in used:
            dfs(i)
            t += 1

    for i in G.keys():
        print(i, d[i], f[i])