Go: package main

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

var N int
var A [][]int
var t int
var color, d, f []int

const (
	WHITE = iota
	GRAY
	BLACK
)

func dfsVisit(u int) {
	color[u] = GRAY
	t ++
	d[u] = t
	for v:=0; v<N; v++ {
		if A[u][v] == 0 {
			continue
		}
		if color[v] == WHITE {
			dfsVisit(v)
		}
	}
	color[u] = BLACK
	t++
	f[u] = t
}

func dfs() {
	for u:=0; u<N; u++ {
		if color[u] == WHITE {
			dfsVisit(u)
		}
	}
	for u:=0; u<N; u++{
		fmt.Printf("%d %d %d\n", u+1, d[u], f[u])
	}
}


func nextInt(scanner *bufio.Scanner) int {
	scanner.Scan()
	num, _ := strconv.Atoi(scanner.Text())
	return num
}

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	scanner.Split(bufio.ScanWords)
	N = nextInt(scanner)
	color = make([]int, N)
	d = make([]int, N)
	f = make([]int, N)
	A = make([][]int, N)
	for i:=0; i<N; i++{
		A[i] = make([]int, N)
	}
	for i:=0; i<N; i++{
		index := nextInt(scanner) - 1
		cnt := nextInt(scanner)
		for j:=0; j<cnt; j++ {
			v := nextInt(scanner) - 1
			A[index][v] = 1
		}
	}
	dfs()
}

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

def solve():
    from collections import deque

    N = int(input())
    Us = [[] for _ in range(N)]

    for i in range(N):
        _in = list(map(int, input().split()))
        if len(_in) == 2:
            continue
        u, k, Vs = _in[0], _in[1], _in[2:]
        Vs.sort()
        for v in Vs:
            Us[u-1].append(v-1)
        Us[u-1] = deque(Us[u-1])

    find = [0 for _ in range(N)]  # 発見時刻
    terminated = [0 for _ in range(N)]  # 終了時刻
    tim = [0]  # 経過時間

    def dfs(now):
        while Us[now]:
            nxt = Us[now].popleft()

            if find[nxt] != 0:
                continue

            tim[0] += 1
            find[nxt] = tim[0]

            dfs(nxt)

        if terminated[now] == 0:
            tim[0] += 1
            terminated[now] = tim[0]

    for i in range(N):
        if find[i] == 0:
            tim[0] += 1
            find[i] = tim[0]
            dfs(i)

    for i in range(N):
        print(i+1, find[i], terminated[i])


if __name__ == "__main__":
    solve()

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


class Graph:
    def __init__(self, n, adj_matrix):
        self.n = n
        self.adj_matrix = adj_matrix

    def show(self):
        for _ in self.adj_matrix:
            print(*_)

    def dfs(self):
        self.states = [2] * self.n
        self.d = [None] * self.n
        self.f = [None] * self.n
        self.time = 0

        for u in range(self.n):
            if self.states[u] == 2:
                self.dfs_visit(u)

    def dfs_visit(self, u):
        self.states[u] = 1
        self.time += 1
        self.d[u] = self.time

        for v, edge in enumerate(self.adj_matrix[u]):
            if edge and self.states[v] == 2:
                self.dfs_visit(v)

        self.states[u] = 0
        self.time += 1
        self.f[u] = self.time

    def show_dfs(self, start=0):
        self.dfs()
        for i, (d, f) in enumerate(zip(self.d, self.f)):
            print(i + 1, d, f)


if __name__ == '__main__':
    n = int(input())
    adj_matrix = [[0] * n for i in range(n)]
    for i in range(n):
        for v in input().split()[2:]:
            adj_matrix[i][int(v) - 1] = 1

    g = Graph(n, adj_matrix)
    g.show_dfs()

Python: def dfs():
    tt = 0
    for u in range(N):
        if colors[u] == WHITE:
            tt = dfs_visit(u, tt)

def dfs_visit(u, tt):
    tt += 1
    colors[u] = GLAY
    d[u] = tt
    for v in range(N):
        if adjacency_list[u][v] == 1 and colors[v] == WHITE:
            tt = dfs_visit(v, tt)
    tt += 1
    colors[u] = BLACK
    f[u] = tt
    return tt


N = int(input())
adjacency_list = [[0 for j in range(N)] for i in range(N)]
for _ in range(N):
    u, k, *v = map(int, input().split())
    for i in v:
        adjacency_list[u-1][i-1] = 1

WHITE = 0
GLAY = 1
BLACK = 2
colors = [WHITE for _ in range(N)]
d = [0 for _ in range(N)]
f = [0 for _ in range(N)]

dfs()

for i in range(N):
    print("{} {} {}".format(i+1, d[i], f[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: import sys
sys.setrecursionlimit(10**9)
from collections import deque

n = int(input())
u = [[] for i in range(n+1)] #隣接リスト
for i in range(n):
    v = list(map(int, input().split()))
    u[v[0]] = v[1:] #v = [次数, 頂点...]

d = [-1] * (n+1)
f = [-1] * (n+1)
visited = [False] * (n+1)
visited[0] = True
time = 1

#再帰
def dfs(c):
    global time
    d[c] = time
    time += 1
    visited[c] = True
    for i in range(1, u[c][0]+1):
        if not visited[u[c][i]]:
            dfs(u[c][i])
    f[c] = time
    time += 1
"""
探索は元の始点から到達可能なすべての頂点を発見するまで続き、
未発見の頂点が残っていれば、
その中の番号が一番小さい１つを新たな始点として探索を続けます。
"""
while False in visited:
    dfs(visited.index(False))

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

Python: def dfs_time(G, s):
    # ?????????
    color = {key: 'White' for key in G.keys()}
    d = {key: 0 for key in G.keys()}
    f = {key: 0 for key in G.keys()}

    # ????????????
    S = [s]
    color[s] = 'Gray'
    time = 1
    d[s] = time

    while len(S) > 0:
        u = S[-1]
        v_list = G[u]
        if v_list:
            v = v_list.pop()
        else: v = None
        if v is not None:
            if color[v] == 'White':
                color[v] = 'Gray'
                time += 1
                d[v] = time
                S.append(v)
        else:
            S.pop()
            color[u] = 'Black'
            time += 1
            f[u] = time

    return d, f


if __name__ == '__main__':
    G = {}
    n = int(input())
    for _ in range(n):
        tmp = list(map(int, input().split()))
        u = tmp.pop(0)
        k = tmp.pop(0)
        G[u] = tmp

    d, f= dfs_time(G, 1)

    for node in G:
        print('{0} {1} {2}'.format(node, d[node], f[node]))

Python: # coding: UTF-8
from collections import deque
#入力値の整理
n = int(input())
adj={}
visited={}
d={}
f={}
t=0
for i in range(n):
  raw=list(map(int,input().split()))
  u = raw.pop(0)
  k = raw.pop(0)
  raw.sort()
  q = deque(raw)
  adj[u] = q
  visited[u] = False
  d[u] = -1
  f[u] = -1

next = 1
v = next
d[next] = t + 1
stack = deque()

while True:
  t = t+1
  clear = True
  while adj[v]:
    cand = adj[v].popleft()
    if not visited[cand]:
      next = cand
      d[cand] = t + 1
      visited[cand] = True
      clear = False
      break
  if clear:
    f[v] = t + 1
    if stack:
      next = stack.pop()
      v = next
    else:
      break
  else:
    stack.append(v)
    v = next

#print
i = 0
for j in range(n):
  i += 1
  print(str(i) + " " + str(d[i]) + " " + str(f[i]))

#return d,f