Go: package main

import "fmt"

type node struct {
	id, d, v int
	adj      []node
}

var n int
var seen []bool
var graph []node

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func dfs(v, t int) int {
	// fmt.Printf("dfs(v %d, t %d) en:\n", v, t)
	seen[v] = true
	graph[v].v = t
	tt := t
	for _, vv := range graph[v].adj {
		if !seen[vv.id] {
			tt = max(tt, dfs(vv.id, tt+1))
		}
	}
	graph[v].d = tt + 1
	// fmt.Printf("dfs(v %d, t %d) ex: d %d\n", v, t, graph[v].d)
	return graph[v].d
}

func main() {
	fmt.Scan(&n)
	graph = make([]node, n+1)
	for i := 1; i <= n; i++ {
		var u, k, v int
		fmt.Scan(&u, &k)
		graph[u].id = u
		// 頂点uはk個の隣接頂点を持っている
		for j := 0; j < k; j++ {
			fmt.Scan(&v)
			var t node
			t.id = v
			graph[u].adj = append(graph[u].adj, t)
		}
	}
	// fmt.Println("n", n, "graph", graph)
	seen = make([]bool, n+1)
	// t := dfs(1, 1)
	v, t := 1, 1
	done := false
	for !done {
		tt := dfs(v, t)
		done = true
		for i := range seen {
			if !seen[i] {
				done = false
				v = graph[i].id
				t = tt
				break
			}
		}
	}
	for i := 1; i <= n; i++ {
		fmt.Printf("%d %d %d\n", i, graph[i].v, graph[i].d)
	}
}

Python: from sys import stdin
input = stdin.readline

N = int(input())
WHITE = 0
GRAY = 1
BLACK = 2

M = [[0]*N for _ in range(N)]
color = [WHITE]*N  # colorの初期化は最初に行っておく。
d = [0]*N
f = [0]*N

def dfs_visit(u):
    global tt
    color[u] = GRAY
    tt += 1
    d[u] = tt # 最初の訪問
    for v in range(N):
        if M[u][v] == 0:
            continue
        if color[v] == WHITE:
            dfs_visit(v)
    color[u] = BLACK
    tt += 1
    f[u] = tt # 訪問の完了

def dfs():
    global tt
    tt = 0

    for u in range(N):
        if color[u] == WHITE:
            # 未訪問のuを始点として深さ優先探索
            dfs_visit(u)
    for u in range(N):
        print(str(u+1) + ' ' + str(d[u]) + ' ' + str(f[u]))
for _ in range(N):
    u, k, *vv = input().split()
    u = int(u)-1  # 0オリジンにする
    k = int(k)    # kは使わない
    for v in vv:
        v = int(v)-1
        M[u][v] = 1
dfs()

Python: global t
t = 0

class Node:
    def __init__(self, num, deg, neib):
        self.num = num
        self.deg = deg
        self.neib = neib

def dfs(G, d, f, now): #now:1,2,...
    #print("now:",now)
    global t
    t += 1
    #print("t:",t)
    if d[now-1] != 0:
        t -= 1
        #print("has searched or hit roop")
    else:
        d[now-1] = t
        #print("d:",d)
        #print("f:",f)
        for i in G[now-1].neib:
            #print("i:",i)
            if i != -1:
                #print("next node")
                dfs(G, d, f, i)
            #else: print("end of branch")
        t += 1
        f[now-1] = t

        #print("f:",f)


dnum = int(input()) #頂点数
N = []
for i in range(dnum):
    data = input().split()
    
    u = int(data[0])
    k = int(data[1])
    if k > 0:
        v = list(map(int, data[2:]))
    else:
        v = [-1]

    node = Node(u,k,v)
    N.append(node)

d = [0]*dnum #find time
f = [0]*dnum #finish time

while 0 in d:
    s = d.index(0)
    dfs(N, d, f, s+1)
    #print("looks like finish")

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

Python: class Node(object):
    def __init__(self, V):
        self.V = V
        self.find_time = 0
        self.finish_time = 0
        self.is_finded = False


n = int(input())
nodes = [0] * 100
for i in range(n):
    data = input().split()
    V = list(map(int, data[2:]))
    V.sort(reverse = True)
    nodes[int(data[0])] = Node(V)

find_q = []
find_q.append(1)
cnt = 1
q_size = len(find_q)
while q_size != 0:
    #print(find_q)
    node = nodes[find_q[q_size -1]]

    if node.is_finded == False:
        node.find_time = cnt
        cnt += 1
        node.is_finded = True
        if len(node.V) == 0:
            node.finish_time = cnt
            cnt += 1
            del find_q[q_size -1]
            q_size = len(find_q)
        else:
            for x in node.V:
                if x in find_q:
                    find_q.remove(x)
                if nodes[x].finish_time == 0: 
                    find_q.append(x)
            q_size = len(find_q)

    else:   #node is finded
        node.finish_time = cnt
        cnt += 1
        del find_q[q_size -1]
        q_size = len(find_q)
        continue

for i in range(1, n+1):
    print(i, nodes[i].find_time, nodes[i].finish_time)

Python: def d(u):
 global t
 C[u]=0;D[u]=t;t+=1
 for v in M[u]:
  v=int(v)-1
  if C[v]:d(v)
 F[u]=t;t+=1
N=int(input());R=range(N)
M=[input().split()[2:]for _ in R]
C,D,F=[1]*N,[0]*N,[0]*N
t=1
for i in R:
 if C[i]:d(i)
for i in R:print(i+1,D[i],F[i])

Python: n=int(input())
G=[]
for i in range(n):
    u,k,*l=map(int,input().split())
    G.append(l)
#print(G)
log_finish=[0]*n
log_start=[0]*n

from collections import deque
def dfs(G):
    q=deque()
    for i in range(n,0,-1):
        q.append((i,-1,0))
    log_finish[0]=1
    log_start[0]=1
    cnt=0
    while q:
        #print(q,cnt)
        V,P,S=q.pop()
        if log_finish[V-1]==0 or log_finish[V-1]==log_start[V-1]:
            cnt+=1
            if not log_finish[V-1]:log_start[V-1]=cnt
            log_finish[V-1]=cnt
        #print(V,P,S,cnt)


        if S==0:
            #下に遷移していくときの処理
            q.append((V,P,1))
            l=[]
            if not G[V-1]:continue
            for new_v in G[V-1]:
                if log_start[new_v-1]!=0:continue
                l.append((new_v,V,0))
            q+=l[::-1]

dfs(G)
for i in range(n):
    print(i+1,log_start[i],log_finish[i])

Python: def curserch(N,k,t,P,n):
    g = 0
    t = t+1
    P[k]["d"] = t
    for i in range(1,n+1):
        if N[k][i]==1 and P[i]["d"]==0:
            P[i]["f"] = g = curserch(N,i,t,P,n)
    if g !=0:
        return g+1
    else:
        return t+1

n = int(input())
A = [[0 for j in range(n+1)] for i in range(n+1)]


for i in range(n):
    vec = input().split()
    u = int(vec[0])
    k = int(vec[1])
    nodes = vec[2:]
    for i in range(int(k)):
        v = int(nodes[i])
        A[u][v] = 1

P=[{"d":0} for i in range(n+1)]
h = 0
for i in range(1,n+1):
    if P[i]["d"]==0:
        P[i]["f"] = h = curserch(A,i,h,P,n)
for i in range(1,n+1):
    print(i,P[i]["d"],P[i]["f"])

Python: #!/usr/bin/env python3
import sys
input = lambda: sys.stdin.readline()[:-1]
sys.setrecursionlimit(10**8)

n = int(input())
G1 = [0]*n
G2 = [[0]*n for i in range(n)]
d = [0]*n
f = [0]*n
for i in range(n):
    inp = tuple(map(int, input().split()))
    G1[inp[0]-1]=sorted(inp[2:])
time=0

def dfs(vertex):
    if d[vertex]:return
    global time
    time+=1
    d[vertex]=time
    for v in G1[vertex]:
        if not d[v-1]:
            dfs(v-1)
    time+=1
    f[vertex]=time
    return

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

Python: #http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ALDS1_11_B&lang=ja

def INT(): return int(input())
def MAP(): return map(int, input().split())
def LIST(): return list(map(int, input().split()))

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

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)
    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: # DFS(再帰） v:頂点
def DFS(v,dis,fin):
  global time
  # 訪問したので発見時刻を記入
  dis[v] = time
  time += 1
  
  # vに隣接している頂点をみる
  for u in V[v]:
    if dis[u] is None:
      DFS(u,dis,fin)
  
  # 処理が完了したので完了時刻を記入
  fin[v] = time
  time += 1
  
n = int(input())
# 0番目を始点として初期化
V = [[i for i in range(n)]]

for i in range(n):
  _, __, *a = map(int, input().split())
  V.append(a)

dis = [None]*(n+1)# 頂点を発見した時刻
fin = [None]*(n+1)# 頂点の完了時刻
time = 0
DFS(0,dis,fin)

for i in range(1,n+1):
  print(i, dis[i], fin[i])