Go: package main

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

const (
	initialBufSize = 100000
	maxBufSize     = 1000000
)

var sc *bufio.Scanner

func initScanner(r io.Reader) *bufio.Scanner {
	buf := make([]byte, initialBufSize)

	sc := bufio.NewScanner(r)
	sc.Buffer(buf, maxBufSize)
	sc.Split(bufio.ScanWords) // bufio.ScanLines
	return sc
}

func main() {
	sc = initScanner(os.Stdin)
	resolve(parseProblem())
}

type graph struct {
	size  int
	edges [][]int
}

func parseProblem() *graph {
	n := scanInt(sc)
	g := &graph{
		size:  n,
		edges: make([][]int, n),
	}
	for i := 0; i < g.size; i++ {
		_ = scanInt(sc)
		k := scanInt(sc)
		g.edges[i] = make([]int, k)
		for j := 0; j < k; j++ {
			g.edges[i][j] = scanInt(sc) - 1
		}
	}
	return g
}

func resolve(g *graph) {
	ds := make([]int, g.size)
	fs := make([]int, g.size)
	time := 0
	for i := 0; i < len(ds); i++ {
		if ds[i] == 0 {
			time++
			time = _dfs(ds, fs, time, g, i)
		}
	}
	for i := 0; i < len(ds); i++ {
		fmt.Println(i+1, ds[i], fs[i])
	}
	return
}

func _dfs(ds, fs []int, time int, g *graph, idx int) int {
	ds[idx] = time
	for _, next := range g.edges[idx] {
		if ds[next] > 0 {
			continue
		}
		time++
		time = _dfs(ds, fs, time, g, next)
	}
	time++
	fs[idx] = time
	return time
}

// snip-scan-funcs
func scanInt(sc *bufio.Scanner) int {
	sc.Scan()
	i, _ := strconv.Atoi(sc.Text())
	return int(i)
}
func scanString(sc *bufio.Scanner) string {
	sc.Scan()
	return sc.Text()
}

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:])