Go: package main

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

type vertexId int

type vertex struct {
	id vertexId
	firstVisitAt int
	finishVisitAt int
	adjs []vertexId
}

func createVertex(id int, adjsInt []int) vertex {
	adjs := make([]vertexId, len(adjsInt))
	for i := 0; i < len(adjs); i++ {
		adjs[i] = vertexId(adjsInt[i])
	}
	return vertex{
		id: vertexId(id),
		firstVisitAt: 0,
		finishVisitAt: 0,
		adjs: adjs,
	}
}

func (v *vertex) doesAllAdjsVisited(vertices []vertex) bool {
	for _, vId := range v.adjs {
		adj := vertices[vId-1]
		if !adj.isVisited() {
			return false
		}
	}
	return true
}

func (v *vertex) isFirstVisit() bool {
	return v.firstVisitAt == 0
}

func (v *vertex) isVisited() bool {
	return v.firstVisitAt > 0
}

func (v *vertex) nextVertex(vertices []vertex) (vertexId, error) {
	for _, vId := range v.adjs {
		adj := vertices[vId-1]
		if !adj.isVisited() {
			return vId, nil
		}
	}
	return vertexId(-1), fmt.Errorf("illegal")
}

func dfs(currentId vertexId, timestamp int, vertices []vertex) int {
	timestamp = timestamp + 1
	currentVertex := &vertices[currentId-1]
	if currentVertex.isFirstVisit() {
		currentVertex.firstVisitAt = timestamp
	}
	for !currentVertex.doesAllAdjsVisited(vertices) {
		nextVertexId, _ := currentVertex.nextVertex(vertices)
		timestamp = dfs(nextVertexId, timestamp, vertices)
	}
	timestamp = timestamp + 1
	currentVertex.finishVisitAt = timestamp
	return timestamp
}

func main() {
	sc := bufio.NewScanner(os.Stdin)
	sc.Split(bufio.ScanWords)

	n, err := nextInt(sc)
	if err != nil {
		panic(err)
	}

	vertices := make([]vertex, n)
	for i := 0; i < n; i++ {
		id, err := nextInt(sc)
		if err != nil {
			panic(err)
		}
		adjN, err := nextInt(sc)
		if err != nil {
			panic(err)
		}
		adjs := make([]int, adjN)
		for j := 0; j < adjN; j++ {
			adjId, err := nextInt(sc)
			if err != nil {
				panic(err)
			}
			adjs[j] = adjId
		}
		vertices[i] = createVertex(id, adjs)
	}

	dfs(vertexId(1), 0, vertices)

	for i := 0; i < n; i++ {
		fmt.Printf("%d %d %d\n", vertices[i].id, vertices[i].firstVisitAt, vertices[i].finishVisitAt)
	}
}

func nextText(sc *bufio.Scanner) string {
	sc.Scan()
	return sc.Text()
}

func nextInt(sc *bufio.Scanner) (int, error) {
	return strconv.Atoi(nextText(sc))
}

Python: from sys import stdin
n = int(stdin.readline())
M = [list(map(int, stdin.readline().split()[2:])) for i in range(n)]
sndf = [[False, i] for i in range(1, n + 1)]
tt = 0
def dfs(u):
    global tt
    sndf[u][0] = True
    tt += 1
    sndf[u].append(tt)
    for v in M[u]:
        v -= 1
        if not sndf[v][0]:
            dfs(v)
    tt += 1
    sndf[u].append(tt)
for i in range(0, n):
    if not sndf[i][0]:
        dfs(i)
    print(*sndf[i][1:])

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:
    j=2
    while t<N*2 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])
        r.pop(-1)
        p.pop(-1)
        if len(r)>0:
            i=r[-1]-1
        else:
            j=1
            while j<N and a[j]==1:
                j+=1
            if j<N:
                t+=1
                i=j-1
                r.append(j)
                p.append([j,t])
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(num):
    global time
    time +=1
    color[num]="gray"
    D[num][0]=time
    for i in M[num]:
        if color[i]=="white":
            DFS(i)
    color[num]="black"
    time +=1
    D[num][1]=time


n=int(input())
M=[[] for _ in range(n+1)]
for i in range(n):
    for j in list(map(int,input().split()))[2:]:
        M[i+1].append(j)
color=["white" for _ in range(n+1)]
D=[[0,0] for _ in range(n+1)]
time=0
for i in range(n):
    if color[i+1]=="white":
        DFS(i+1)

for i in range(n):
    print(i+1,*D[i+1])

Python: n=int(input())

next=[[] for i in range(n)]
for i in range(n):
	l=list(map(int,input().split()))
	u=l[0]
	k=l[1]
	for j in range(2,k+2):
		next[u-1].append(l[j]-1)

stk=[]
stk.append(0)
time=1
d=[0 for i in range(n)]
f=[0 for i in range(n)]
know=[0 for i in range(n)]

def dfs(x):
	global time
	know[x]=1
	d[x]=time
	time+=1
	for n in next[x]:
		if know[n]==0:
			dfs(n)
	f[x]=time
	time+=1
	
for i in range(n):
	if know[i]==0:
		dfs(i)

for i in range(n):
	out=[]
	out.append(i+1)
	out.append(d[i])
	out.append(f[i])
	print(*out)

Python: # -*- coding: utf-8 -*-

import sys
sys.setrecursionlimit(10 ** 9)
def input(): return sys.stdin.readline().strip()
def INT(): return int(input())
def MAP(): return map(int, input().split())
def LIST(): return list(map(int, input().split()))
INF=float('inf')

N=INT()
nodes=[[] for i in range(N)]
for i in range(N):
    l=LIST()
    u=l[0]
    l=l[2:]
    for v in l:
        nodes[u-1].append(v-1)
    nodes[u-1].sort()

ans=[[0]*2 for i in range(N)]
visited=[False]*N
time=0
def rec(u):
    if visited[u]:
        return
    visited[u]=True
    global time
    time+=1
    ans[u][0]=time
    for v in nodes[u]:
        rec(v)
    time+=1
    ans[u][1]=time

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