Go: package main

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

// repr state of visited node
// WHITE yet visit
// GEAY  visiting
// BLACK visited
const (
	WHITE int = iota
	GRAY
	BLACK
)

type dfsGraph struct {
	g      [][]int
	colors []int
	stime  []int // Start time of visiting node
	ftime  []int // Finish time of visiting node
}

var time int

func makeAdjList() [][]int {
	var n int
	fmt.Scanf("%d", &n)

	adj := make([][]int, n)
	for i := 0; i < n; i++ {
		adj[i] = make([]int, n)
	}

	sc := bufio.NewScanner(os.Stdin)
	for i := 0; i < n; i++ {
		sc.Scan()
		nodeInfo := strings.Split(sc.Text(), " ")
		outDegree, _ := strconv.Atoi(nodeInfo[1])

		if outDegree > 0 {
			for k := 0; k < outDegree; k++ {
				j, _ := strconv.Atoi(nodeInfo[k+2])
				j-- // convert 1 based to 0 based
				adj[i][j] = 1
			}
		}
	}

	return adj
}

func (dg dfsGraph) dfsVisit(u int) {
	// 頂点uを訪問中に設定
	dg.colors[u] = GRAY
	time++
	dg.stime[u] = time

	// uの隣接nodeを訪問
	for v := 0; v < len(dg.g); v++ {
		if dg.g[u][v] == 0 {
			continue // 辺がなければスキップ
		}

		// vが未訪問なら訪問
		if dg.colors[v] == WHITE {
			dg.dfsVisit(v)
		}
	}

	// 頂点uを訪問済みに設定
	dg.colors[u] = BLACK
	time++
	dg.ftime[u] = time
}

func (dg dfsGraph) dfs() {
	for i := 0; i < len(dg.g); i++ {
		if dg.colors[i] == WHITE {
			dg.dfsVisit(i)
		}
	}
}

func (dg dfsGraph) printDfsTime() {
	for i := 0; i < len(dg.g); i++ {
		fmt.Printf("%d %d %d\n", i+1, dg.stime[i], dg.ftime[i])
	}
}

func main() {
	adj := makeAdjList()
	colors := make([]int, len(adj))
	stime := make([]int, len(adj))
	ftime := make([]int, len(adj))
	graph := dfsGraph{adj, colors, stime, ftime}
	graph.dfs()
	graph.printDfsTime()
}

Python: n = int(input())
A = [[0 for j in range(n)] for i in range(n)]
for i in range(n):
    arr = list(map(int, input().split(' ')))
    u, k, v = arr[0], arr[1], arr[2:]
    for j in range(k):
        A[u-1][v[j]-1] = 1

hist_stack = [0]
time_hist = [0]

vert_hist = [[] for i in range(n)]
vert_hist[0].append(1)
time = 2
while True:
    flag = False
    if len(hist_stack) == 0: break
    for j in range(n):
        if A[hist_stack[-1]][j] == 1 and j not in time_hist:
            hist_stack.append(j)
            time_hist.append(j)
            vert_hist[j].append(time)
            flag = True
            break
    if not flag:
        j = hist_stack.pop()
        time_hist.append(j)
        vert_hist[j].append(time)
    time += 1

for i in range(n):
    print(i+1, ' '.join(list(map(str, vert_hist[i]))))

Python: #coding:utf-8

n = int(input())
c = ["white" for i in range(n)]
d = [0 for i in range(n)]
f = [0 for i in range(n)]
S = []
class DFS:
    def __init__(self, key, color="white",nex=None):
        self.color = color
        self.nex = nex
        self.key = key

objList = [DFS(i+1) for i in range(n)]
for i in range(n):
    data = list(map(int,input().split()))
    times = data[1]
    obj = objList[i]
    for j in range(times):
        index = data[2+j] - 1
        nextobj = DFS(index+1)
        obj.nex = nextobj
        obj = obj.nex

S.append(1)
obj = objList[0]
obj.color = "gray"
d[0] = 1
f[0] = 1
c[0] = "gray"

time = 1
while S != []:
    index = S[-1] - 1
    u = objList[index]
    v = u.nex

    time += 1
    if v != None and c[v.key - 1] == "white":
        objList[index] = v
        index = v.key - 1
        v = objList[index]
        c[v.key-1] = "gray"
        d[index] = time
        S.append(v.key)
        
    else:
        S.pop()
        c[u.key-1] = "black"
        f[index] = time

k = 1
for i,j in zip(d,f):
    print(k,i,j)
    k += 1

Python: N = int(input())

E = [None] * (N+1)
for _ in range(N):
    u, k, *vs = list(map(int, input().split()))
    E[u] = vs

d = [0] * (N+1)
f = [0] * (N+1)
t = 0

def dfs(v):
    global t, d, f
    if d[v]:
        return
    t += 1
    d[v] = t
    for u in E[v]:
        dfs(u)
    t += 1
    f[v] = t

for v in range(1, N+1):
    dfs(v)

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

Python: n = int(input())

adj = [None]
for i in range(n):
    adj_i = list(map(int, input().split()[2:]))
    adj.append(adj_i)

# searched or not, number of vertex, discovery time and finishing time.
sndf = [None]
for i in range(1, n + 1):
    sndf.append([False, i])

path = []

time = 0

def dfs(u):
    global time
    sndf[u][0] = True
    time += 1
    sndf[u].append(time)

    for v in adj[u]:
        if not sndf[v][0]:
            dfs(v)
    sndf[u][0] = True
    time += 1
    sndf[u].append(time)


for i in range(1, n + 1):
    if not sndf[i][0]:
        dfs(i)

for x in sndf[1:]:
    print(*x[1:])

Python: #!usr/bin/env python3
from collections import defaultdict,deque
from heapq import heappush, heappop
from itertools import permutations
import sys
import math
import bisect
def LI(): return [int(x) for x in sys.stdin.readline().split()]
def I(): return int(sys.stdin.readline())
def LS():return [list(x) for x in sys.stdin.readline().split()]
def S():
    res = list(sys.stdin.readline())
    if res[-1] == "\n":
        return res[:-1]
    return res
def IR(n):
    return [I() for i in range(n)]
def LIR(n):
    return [LI() for i in range(n)]
def SR(n):
    return [S() for i in range(n)]
def LSR(n):
    return [LS() for i in range(n)]

sys.setrecursionlimit(1000000)
mod = 1000000007

cnt = 1
def solve():
    global cnt
    def dfs(x):
        global cnt
        f[x] = cnt
        for y in v[x]:
            if not d[y]:
                d[y] = cnt
                cnt += 1
                dfs(y)
        f[x] = cnt
        cnt += 1

    n = I()
    v = []
    for i in range(n):
        e = LI()
        u = e[2:]
        for i in range(len(u)):
            u[i] -= 1
        v.append(u)
    d = [0]*n
    f = [0]*n
    for i in range(n):
        if not d[i]:
            d[i] = cnt
            cnt += 1
            dfs(i)
    for i in range(n):
        print(i+1,d[i],f[i])
    return

#Solve
if __name__ == "__main__":
    solve()

Python: n=int(input())
edge=[[] for _ in range(n+1)]
for i in range(n):
  v,k,*u=list(map(int,input().split()))
  edge[v]=u
d=[0]*(n+1)
f=[0]*(n+1)
def dfs(now,t):
  d[now]=t
  vis.append(now)
  for i in edge[now]:
    if i not in vis:
      t=dfs(i,t+1)
  f[now]=t+1
  return t+1
vis=[]
t=1
for i in range(1,n+1):
  if i not in vis:
    t=dfs(i,t)+1
for i in range(1,n+1):
  print(i,d[i],f[i])

Python: n = int(raw_input())

d = [0 for i in range(n)]
f = [0 for i in range(n)]
a = [[0 for i in range(n)] for j in range(n)]
st = [0 for i in range(n)]
time = [0]

def dfs_visit(s):
    st[s] = 1
    time[0] += 1
    d[s] = time[0]
    
    for k in range(n):  
      if a[s][k] == 1 and st[k] == 0:
          dfs_visit(k)
    st[s] == 2
    time[0] += 1
    f[s] = time[0]

def main():
    for s in range(n):
        if st[s] == 0:
            def_visit(s)
    for s in range(n):
        print(s+1,d[s],f[s])

Python: def dfs(num, lst, d, f, cnt):
    if d[num] != 0:
        return cnt - 1
    d[num] = cnt
    for n in lst[num]:
        cnt += 1
        cnt = dfs(n - 1, lst, d, f ,cnt)
    cnt += 1
    f[num] = cnt
    return cnt


n = int(input())
d = [0 for i in range(n)]
f = [0 for i in range(n)]
lst = []
for _ in range(n):
    n = list(map(int, input().split()))
    lst.append(n[2:])

cnt = 1
while 0 in d:
    num = d.index(0)
    cnt = dfs(num, lst, d, f, cnt) + 1

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