Problem:
Depth First Search Depth-first search (DFS) follows the strategy to search ”deeper” in the graph whenever possible. In DFS, edges are recursively explored out of the most recently discovered vertex $v$ that still has unexplored edges leaving it. When all of $v$'s edges have been explored, the search ”backtracks” to explore edges leaving the vertex from which $v$ was discovered. This process continues until all the vertices that are reachable from the original source vertex have been discovered. If any undiscovered vertices remain, then one of them is selected as a new source and the search is repeated from that source. DFS timestamps each vertex as follows:  $d[v]$ records when $v$ is first discovered.  $f[v]$ records when the search finishes examining $v$’s adjacency list.  Write a program which reads a directed graph $G = (V, E)$ and demonstrates DFS on the graph based on the following rules:  $G$ is given in an adjacency-list. Vertices are identified by IDs $1, 2,... n$ respectively.  IDs in the adjacency list are arranged in ascending order.  The program should report the discover time and the finish time for each vertex.  When there are several candidates to visit during DFS, the algorithm should select the vertex with the smallest ID.  The timestamp starts with 1.  Input In the first line, an integer $n$ denoting the number of vertices of $G$ is given. In the next $n$ lines, adjacency lists of $u$ are given in the following format: $u$ $k$ $v_1$ $v_2$ ... $v_k$ $u$ is ID of the vertex and $k$ denotes its degree. $v_i$ are IDs of vertices adjacent to $u$. Output For each vertex, print $id$, $d$ and $f$ separated by a space character in a line. $id$ is ID of the vertex, $d$ and $f$ is the discover time and the finish time respectively. Print in order of vertex IDs. Constraints  $1 \leq n \leq 100$  Sample Input 1 4
1 1 2
2 1 4
3 0
4 1 3 Sample Output 1 1 1 8
2 2 7
3 4 5
4 3 6 Sample Input 2 6
1 2 2 3
2 2 3 4
3 1 5
4 1 6
5 1 6
6 0 Sample Output 2 1 1 12
2 2 11
3 3 8
4 9 10
5 4 7
6 5 6   This is example for Sample Input 2 (discover/finish)  Reference Introduction to Algorithms, Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford Stein. The MIT Press.

Solution (Python):
def dfs(G,n):

	global ptr
	
	
	seen[n] = True

	
	F[n] = ptr
	ptr += 1

	for i in G[n]:
		
		if seen[i] == True :
			continue
		dfs(G,i)

	
	L[n] = ptr
	ptr += 1

if __name__ == '__main__':

	n = int(input())
	
	G = [[] for _ in range(n+1)] 
	F = [0 for _ in range(n+1)]
	L = [0 for _ in range(n+1)]

	
	
	seen = [False for _ in range(n+1)]

	for i in range(n):
		cmd = list(map(int,input().split()))
		m = cmd[1]
		if m != 0:
			for j in range(m):
				G[i+1].append(cmd[j+2])
	ptr = 1
	for i in range(1,n):
		if seen[i] == False :
			dfs(G,i)

	for i in range(1,n+1):
		print(i,F[i],L[i])

Solution (Python):
n = int(input())
u = [list(map(int,input().split())) for _ in range(n)]
ts = [[0,0] for _ in range(n)]
time = 0

def dfs(i):
  global time
  ts[i][0] = time
  for j in range(u[i][1]):
    a = u[i][j+2]-1
    if ts[a][0] == 0:
      time += 1
      dfs(a)
  time += 1
  ts[i][1] = time
  
for i in range(n):
  if ts[i][0] == 0:
    time += 1
    dfs(i)
  
for i in range(n):
  print(i+1, ts[i][0], ts[i][1])

Solution (Python):

import sys
input = sys.stdin.readline
from collections import deque


N = int(input())
graph = [deque([]) for _ in range(N+1)]
for _ in range(N):
    u, k, *v = [int(x) for x in input().split()]
    v.sort()
    for i in v:
        graph[u].append(i)
        
        
time = 0
arrive_time = [-1] * (N+1) 
finish_time = [-1] * (N+1) 

def dfs(v):
    global time
    time += 1
    stack = [v]
    arrive_time[v] = time
    while stack:
        v = stack[-1]
        if graph[v]:
            w = graph[v].popleft()
            if arrive_time[w] < 0:
                time += 1
                arrive_time[w] = time
                stack.append(w)
        else:
            time += 1
            finish_time[v] = time
            stack.pop()
    return [arrive_time, finish_time]



for i in range(N):
    if arrive_time[i+1] < 0:
        ans = dfs(i+1)


for i in range(N):
    temp = [i + 1, ans[0][i+1], ans[1][i+1]]
    print(* temp)

Solution (Python):
import sys
sys.setrecursionlimit(10**6)

n = int(input())
graph = []
chart = [[int(i)] for i in range(1,n+1)]
for i in range(n):
    z = [c-1 for c in list(map(int,input().split()))][2:]
    graph.append(z)
time = 0

def dfs(nod):
    global graph
    global time
    
    if len(chart[nod]) != 1:
        return 
    
    
    
    
    
    
    time += 1
    chart[nod].append(time)
    
    
    for dis in graph[nod]:
            dfs(dis)

    
    time += 1
    chart[nod].append(time)
for i in range(n):
    dfs(i)
for i in range(n):
    print(*chart[i])

Solution (Python):
def dfs(index):
    global count
    d[index] = count
    count += 1
    for i in field[index]:
        if d[i]:
            continue
        count = dfs(i)
    f[index] = count
    return count + 1

n = int(input())
field = [[0,0]]
for _ in range(n):
    u, k, *v = map(int, input().split())
    field.append(v)
d = [0 for _ in range(n + 1)]
f = [0 for _ in range(n + 1)]

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

Solution (Python):

import sys
INF=10**18
MOD=10**9+7
def input(): return sys.stdin.readline().rstrip()


c=0
def main():
    N=int(input())
    edge=[[] for _ in range(N)]
    for i in range(N):
        l=list(map(lambda x:int(x)-1,input().split()))
        for x in l[2:]:
            edge[i].append(x)
    d=[-1]*N
    f=[-1]*N
    used=[False]*N
    def dfs(v):
        global c
        used[v]=True
        d[v]=c
        for nv in edge[v]:
            if not used[nv]:
                c+=1
                dfs(nv)
        c+=1
        f[v]=c
    global c
    while not all(used):
        for i in range(N):
            if not used[i]:
                c+=1
                dfs(i)

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

if __name__ == '__main__':
    main()

Solution (Python):


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

Solution (Python):



def dfs(u):
    global time
    color[u - 1] = 0
    time += 1
    d[u - 1] = time
    for v in range(1, n + 1):
        if A[u - 1][v - 1] == 1 and color[v - 1] == -1:
            dfs(v)
    color[u - 1] = 1
    time += 1
    f[u - 1] = time


n = int(input())
A = [[0 for i in range(n)] for i in range(n)]
for i in range(n):
    dat = [int(j) for j in input().split()]
    for j in range(dat[1]):
        A[dat[0] - 1][dat[2 + j] - 1] = 1

color = [-1 for i in range(n)]
d = [-1 for i in range(n)]
f = [-1 for i in range(n)]
time = 0
for i in range(n):
    if color[i] == -1:
        dfs(i+1)

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

Solution (Python):
import sys
input = lambda: sys.stdin.readline().rstrip() 
import bisect as bs

def resolve():
    n = int(input())
    ukv = [list(map(int, input().split())) for _ in range(n)]

    d = [-1]*n
    f = [-1]*n
    stk = []
    status = [0]*n

    t = 1
    for i in range(n):
        if status[i]==0:
            stk.append(i)
            while len(stk)>0:
                a = stk[-1]
                if status[a]==0:
                    d[a] = t
                    t += 1
                    status[a] = 1
                elif status[a]==1:
                    stk.pop()
                    f[a] = t
                    t += 1
                    status[a] = 2
                else:
                    stk.pop()
                for i in reversed(ukv[a][2:]):
                    if status[i-1]==0:
                        stk.append(i-1) 

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

if __name__ == '__main__':
    resolve()

Solution (Python):
mod = 10 ** 9 + 7
mod2 = 2 ** 61 + 1
from collections import deque
import heapq
import time
from bisect import bisect_left, insort_left, bisect_right
import sys
import random
import itertools

input = sys.stdin.readline
_NUMINT_ALL = list(range(10))
_START_TIME = time.time()
INDEX_KETA = 10**12

def main():
    ans = solve()

    if ans is True or ans is False:
        YesNo(ans)
    elif ans is None:
        return

    if isinstance(ans, tuple):
        split_print_space(ans)


def solve():

    G = iip()
    ukv = iipt(G)

    edge = {}
    for i, d in enumerate(ukv):
        if d[1] == 0:
            continue
        a, b, *c = d
        if isinstance(c, int):
            c = [c]

        for j in c:
            edge[(a, j)] = True


    ans = [[i+1, 0, 0] for i in range(G)]
    t = 0
    ans[0] = [1, 1, G*2]
    found = {0:True}

    def src(node):
        nonlocal t
        found[node] = True
        for j in range(1, G+1):
            if (node, j) in edge and j not in found:
                found[j] = True
                t += 1
                ans[j - 1][1] = t
                src(j)

        t += 1
        ans[node-1][2] = t

    for i in range(1, G+1):
        if i not in found:
            t += 1
            ans[i - 1][1] = t
            src(i)
    

    for i in ans:
        split_print_space(i)











def kiriage_warizan(a, b):
    return -(-a//b)


def iip(listed=False):  
    d = input().rstrip("\n").split()
    try:
        ret = [int(i) for i in d]
    except:
        ret = [int(i) if i in _NUMINT_ALL else i for i in d]
        if len(ret) == 1 and listed is False:
            return ret[0]

    if len(ret) == 1 and not listed:
        return ret[0]
    return ret

def iipt(l, listed=True, num_only=True):  
    if isinstance(l, list):
        l = l[0] 
    ret = []
    for i in range(l):
        ret.append(iip(listed=listed))
    return ret


def saidai_kouyakusuu(A):  
    l = len(A)
    while True:
        m = min(A)
        mx = max(A)
        if m == mx:
            return m

        for i in range(l):
            if A[i] % m == 0:
                A[i] = m
            else:
                A[i] %= m


def index_sorted(sorted_list, target):
    idx = bisect_left(sorted_list, target)
    if idx != len(sorted_list) and sorted_list[idx] == target:
        return idx
    else:
        return False


def time_debug_10percent():
    a = random.randint(0, 9)
    if a == 9:
        sys.exit()

def time_debug(t):
    time.sleep(_START_TIME + t - time.time())
    sys.exit()


def make_graph_edge_flat(N):  
    ret = []
    for i in range(N-1):
        a, b, c = iip()
        a -= 1
        b -= 1
        ret[a].append((b, c))
        ret[b].append((a, c))
    return ret


def sort_tuples(l, index):  
    if isinstance(l, list):
        l.sort(key=lambda x: x[index])
        return l
    else:
        l = list(l)
        return sorted(l, key=lambda x: x[index])


def count_elements(l):  
    d = {}
    for i in l:
        if i in d:
            d[i] += 1
        else:
            d[i] = 1
    return d


def safeget(l, index, default="exception"):  
    if index >= len(l):                      
        if default == "exception":
            raise Exception("".join(["safegetに不正な値 ", index, "が渡されました。配列の長さは", len(l), "です"]))
        else:
            return default
    elif index < 0:
        if default == "exception":
            raise Exception("".join(["safegetに不正な値 ", index, "が渡されました。負の値は許可されていません"]))
        else:
            return default
    else:
        return l[index]


def sortstr(s):  
    return "".join(sorted(s))


def iip_ord(startcode="a"):  
    if isinstance(startcode, str):
        startcode = ord(startcode)
    return [ord(i) - startcode for i in input()]


def YesNo(s):  
    if s:
        print("Yes")
    else:
        print("No")


def fprint(s):  
    for i in s:
        print(i)


def bitall(N):  
    ret = []
    for i in range(2 ** N):
        a = []
        for j in range(N):
            a.append(i % 2)
            i //= 2
        ret.append(a)
    return ret

def split_print_space(s):  
    print(" ".join([str(i) for i in s]))


def split_print_enter(s):  
    print("\n".join([str(i) for i in s]))


def soinsuu_bunkai(n):  
    ret = []
    for i in range(2, int(n ** 0.5) + 1):
        while n % i == 0:
            n //= i
            ret.append(i)
        if i > n:
            break
    if n != 1:
        ret.append(n)
    return ret


def conbination(n, r, mod, test=False):  
    if n <= 0:
        return 0
    if r == 0:
        return 1
    if r < 0:
        return 0
    if r == 1:
        return n
    ret = 1
    for i in range(n - r + 1, n + 1):
        ret *= i
        ret = ret % mod

    bunbo = 1
    for i in range(1, r + 1):
        bunbo *= i
        bunbo = bunbo % mod

    ret = (ret * inv(bunbo, mod)) % mod
    if test:
        
        pass
    return ret


def inv(n, mod):  
    return power(n, mod - 2)


def power(n, p, mod_=mod):  
    if p == 0:
        return 1
    if p % 2 == 0:
        return (power(n, p // 2, mod_) ** 2) % mod_
    if p % 2 == 1:
        return (n * power(n, p - 1, mod_)) % mod_


def nibutan_func(func, target, left, right, side="left", seido = 1): 
    l = left
    r = right
    if seido == 1:
        x = (l + r) // 2
    else:
        x = (l + r) / 2
    while r-l > seido:
        
        if seido == 1:
            x = (l + r) // 2
        else:
            x = (l + r) / 2
        if func(x) == target:
            if side == "left":
                r=x
            else:
                l=x


        elif func(x) > target:
            r = x
        else:
            
            l = x

    
    if side == "left" and func(r) == target:
        return r
    elif side != "left" and func(l) == target:
        return l
    elif side == "left":
        return l
    else:
        return r


def nibutan_list(list_, target, side="left"):  
    if not isinstance(list_, list):
        list_ = list(list_)

    l = 0
    r = len(list_)
    x = (l + r) // 2
    while r-l > 1:
        x = (l+r)//2
        if list_[x] == target:
            return x
        elif list_[x] > target:
            r = x
        else:
            l = x

    if side == "left" or list_[x] == target:
        return l
    else:
        return r


class UfTree():
    def __init__(self, maxnum):
        self.parent = list(range(maxnum))
        self._size = [1] * maxnum
        self.rank = [0] * maxnum

    def size(self, a):
        return self._size[self.root(a)]

    def root(self, a):
        rank = 0
        cur = a
        while True:
            if self.parent[cur] == cur:
                
                
                return cur
            else:
                self.parent[cur] = self.parent[self.parent[cur]]
                cur = self.parent[cur]
                rank += 1

    def unite(self, a, b):
        ra = self.root(a)
        rb = self.root(b)
        if ra == rb:
            return self

        self._size[ra] += self._size[rb]
        self.parent[rb] = ra
        return self

if __name__ == "__main__":
    main()

Solution (Python):
n=int(input())
seen=[-1]*n
first_order=[0]*n
last_order=[0]*n
cnt=0
def dfs(G,s):
    global cnt
    first_order[s]=cnt+1
    cnt+=1
    seen[s]=1
    for nv in G[s]:
        if(seen[nv]!=-1):
            continue
        dfs(G,nv)
    last_order[s]=cnt+1
    cnt+=1

G=[[] for i in range(n)]
for i in range(n):
    li=list(map(int,input().split()))
    for x in range(2,len(li)):
        G[i].append(li[x]-1)
for i in range(n):
    if(seen[i]==-1):
        dfs(G,i)
for i in range(n):
    print(i+1,first_order[i],last_order[i])

Solution (Python):



import sys
read = sys.stdin.read
readline = sys.stdin.readline


def dfs(G, v, d, f, time):
    time += 1
    d[v] = time

    for e in G[v]:
        if d[e] == 0:
            time = dfs(G, e, d, f, time)

    time += 1
    f[v] = time

    return time


def main():
    n = int(readline())

    E = [[]]
    for _ in range(n):
        u,k,*v = map(int, readline().split())
        E.append(v)

    d = [0] * (n+1)
    f = [0] * (n+1)
    time = 0
    
    for i in range(1,n+1):
        if d[i] == 0:
            time = dfs(E, i, d, f, time)
    
    for i in range(1, n+1):
        print(i, d[i], f[i])


if __name__ == "__main__":
    main()

Solution (Python):
import sys
sys.setrecursionlimit(10**7) 

def dfs(G,v):
    global ptr
    first_order[v] = ptr
    ptr += 1
    seen[v] = True
    for next in G[v]:
        if seen[next]:
            continue
        dfs(G,next)

    last_order[v] = ptr
    ptr+=1

n = int(input())
G = [[] for _ in range(n)]
for _ in range(n):
    a = list(map(int, input().split()))
    u = a[0]
    k = a[1]
    v = a[2:]
    for i in v:
        G[u-1].append(i-1)

seen = [False]*n
first_order = [0]*n
last_order = [0]*n
ptr = 0
for i in range(n):
    if seen[i]:
        continue
    dfs(G,i)

for i in range(n):
    print('{} {} {}'.format(i+1,first_order[i]+1,last_order[i]+1))

Solution (Python):
import math
import copy
import sys
import fractions


import decimal
import heapq
import collections
import itertools
import bisect












def getInputIntList():
    outputDataList = []
    inputData = input().split()
    outputDataList = [int(n) for n in inputData]

    return outputDataList


def getSomeInputInt(n):
    outputDataList = []
    for i in range(n):
        inputData = int(input())
        outputDataList.append(inputData)

    return outputDataList


def getSomeInputListInt(n):
    inputDataList = []
    outputDataList = []
    for i in range(n):
        inputData = input().split()
        inputDataList = [int(n) - 1 for n in inputData]
        outputDataList.append(inputDataList)

    return outputDataList




n = int(input())

data = getSomeInputListInt(n)

ans = [[] for _ in range(n)]

edge = []
for d in data:
    edge.append(d[2:])


def dfs(i, cnt):
    if len(ans[i]) > 0:
        return cnt

    cnt += 1

    ans[i].append(cnt)
    for j in range(len(edge[i])):
        cnt = dfs(edge[i][j], cnt)

    cnt += 1
    ans[i].append(cnt)

    return cnt

tmp = 0
for i in range(n):
    tmp = dfs(i, tmp)

for i in range(n):
    print(i + 1, *ans[i], sep=" ")

Solution (Python):
n=int(input())
adj=[]
for i in range(n):
	a=list(map(int,input().split()))
	for j in range(2,len(a)):
		a[j]-=1
	adj.append(a[2:])
visit_time1=[0]*n
visit_time2=[0]*n
visited=[0]*n
def dfs(now):
	global time
	visit_time1[now]=time
	time+=1
	for next in adj[now]:
		if not visited[next]:
			visited[next]=True
			dfs(next)
	visit_time2[now]=time
	time+=1
time=1
for i in range(n):
	if not visited[i]:
		visited[i]=True
		dfs(i)
for i in range(n):
	print(i+1,visit_time1[i],visit_time2[i])

Solution (Python):

import sys
input = sys.stdin.readline
from collections import deque


N = int(input())
graph = [deque([]) for _ in range(N + 1)]
for _ in range(N):
    u, k, * v = [int(x) for x in input().split()] 
    v.sort()
    for i in v:
        graph[u].append(i)
        

time = 0
arrive_time = [-1] * (N + 1) 
finish_time = [-1] * (N + 1) 


def dfs(v):
    global time
    time += 1
    stack = [v]
    arrive_time[v] = time
    while stack:
        v = stack[-1]
        if graph[v]:
            w = graph[v].popleft()
            if arrive_time[w] < 0:
                time += 1
                arrive_time[w] = time
                stack.append(w) 
        else:
            time += 1
            finish_time[v] = time
            stack.pop()          
    return [arrive_time, finish_time]


for i in range(N):
    if arrive_time[i + 1] < 0:
        ans = dfs(i + 1)


for j in range(N):
    temp = [j + 1, ans[0][j + 1], ans[1][j + 1]]
    print(* temp)

Solution (Python):
n = int(input())
graph = [-1] + [list(map(int, input().split())) for _ in range(n)]
seen = [False]*(n+1)
seen[0] = True
d = [-1]*(n+1)
f = [-1]*(n+1)
time = 0


def dfs(v):
    global time
    time += 1
    d[v] = time
    seen[v] = True
    k = graph[v][1]
    if k > 0:
        for i in range(k):
            w = graph[v][i+2]
            if seen[w] is False:
                dfs(w)
    
    time += 1
    f[v] = time

v = 0
while v <= n:
    if seen[v] is False:
        dfs(v)
    
    v += 1

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

Solution (Python):
from collections import deque
time = 1

def dfs(adj_list, d, f, color, u):

    global time
    S = list()

    S.append(u)
    color[u] = "G"
    d[u] = time
    time += 1

    while len(S) != 0:
        u = S[-1]

        if len(adj_list[u]) != 0:
            v = adj_list[u].popleft()

            if color[v] == "W":
                color[v] = "G"
                d[v] = time
                time += 1
                S.append(v)
        else:
            S.pop()
            color[u] = "B"
            f[u] = time
            time += 1

def Main():
    
    N = int(input())
    adj_list = [deque() for n in range(N)]
    d = [0] * N
    f = [0] * N
    color = [ "W" for i in range(len(d)) ]

    for n in range(N):
        u, k, *V = map(int, input().split())

        if k > 0:
            for i in V:
                adj_list[n].append(i - 1)

    while(True):

        ind = None
        for i in range(N):
            if color[i] == "W":
                ind = i
                break

        if ind == None:
            break
        else:
            dfs(adj_list, d, f, color, ind)

    for i in range(N):
        print("{} {} {}".format(i + 1, d[i], f[i] ))

Main()

Solution (Python):
n = int(input())
M = [[0]*n for _ in range(n)]
st = [0]*n
d = [0]*n
f = [0]*n
tt = 0

def dfs(u,t):
    st[u] = 1
    t += 1
    d[u] = t
    for v in range(n):
        if M[u][v] == 0: continue
        if st[v] == 0: t = dfs(v,t)
    st[u] = 2
    t += 1
    f[u] = t
    return t

for _ in range(n):
    i = [int(i) for i in input().split()]
    u = i[0]
    k = i[1]
    V = i[2:]
    for v in V: M[u-1][v-1] = 1

for i in range(n):
    if st[i] == 0: tt = dfs(i,tt)

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

Solution (Python):
def main():

    inf = 1000000007
    n = int(input())
    e = [[] for _ in range(n)]
    d = [inf]*n
    f = [inf]*n
    step = 1

    def dfs(v):
        nonlocal step
        d[v] = step
        step+=1
        for u in e[v]:
            if d[u] == inf:dfs(u)
        f[v] = step
        step +=1

    e = [[] for _ in range(n)]
    for i in range(n):
        m = list(map(int,input().split()))
        for j in range(2,len(m)):
            e[m[0]-1].append(m[j]-1)
    for i in range(n):
        if d[i]==inf:dfs(i)
    for i in range(n):
        print (i+1,d[i],f[i])

if __name__ == '__main__':
    main()

Solution (Python):


G = {}
d = {}
f = {}
used = set()
t = 1


def dfs(cur):
    global G, d, f, t

    used.add(cur)
    d[cur] = t

    for i in G[cur]:
        if i in used:
            continue
        t += 1
        dfs(i)
    t += 1
    f[cur] = t


if __name__ == "__main__":
    N = int(input())

    for _ in range(N):
        u, k, *V = list(map(int, input().split()))
        G[u] = V

    for i in range(1, N+1):
        if i not in used:
            dfs(i)
            t += 1

    for i in G.keys():
        print(i, d[i], f[i])

Solution (Python):
n = int(input())
a = [None]
for i in range(n):
    adj = list(map(int,input().split()))
    a.append(adj[2:])
    
s = [None]
for i in range(1, n + 1):
    s.append([False, i])
    
time = 0

def dfs(u):
    global time
    s[u][0] = True
    time += 1
    s[u].append(time)
    
    for v in a[u]:
        if s[v][0] == False:
            dfs(v)
            
    time += 1
    s[u].append(time)
    
for i in range(1,n+1):
    if s[i][0] == False:
        dfs(i)
        
for x in s[1:]:
    print(*x[1:])

Solution (Python):
import math,string,itertools,fractions,heapq,collections,re,array,bisect,sys,random,time

sys.setrecursionlimit(10**7)
inf = 10**20
mod = 10**9 + 7

stdin = sys.stdin

ni = lambda: int(ns())
na = lambda: list(map(int, stdin.readline().split()))
ns = lambda: stdin.readline().rstrip()  

n = ni()
g = []
for i in range(n):
    t = na()
    u = t[0] - 1
    k = t[1]
    v = [x-1 for x in t[2:]]
    g.append(v)
d = [0] * n
f = [0] * n

seen = [False] * n
s = 0
t = 0
def dfs(g, v):
    global t
    
    if seen[v]:
        return
    seen[v] = True
    d[v] = t
    t += 1    
    for next_v in g[v]:
        
        dfs(g, next_v)
    f[v] = t
    t += 1
for i in range(n):
    if len(g[i]) != 0:
        dfs(g, i)
for i in range(n):
    print(i+1, d[i]+1, f[i]+1)

Solution (Python):
def inpl():
    return list(map(int, input().split()))


def dfs(v, step):
    if f[v] != -1:
        return step
    f[v] = step
    step += 1
    for nv in E[v]:
        
        step = dfs(nv - 1, step)
    d[v] = step
    return step + 1


n = int(input())
E = [[] for i in range(n)]
for _ in range(n):
    tmp = inpl()
    u, k = tmp[:2]
    E[u - 1] = tmp[2:]

d = [-1 for i in range(n)]
f = [-1 for i in range(n)]

step = 1
for v in range(n):
    step = dfs(v, step)

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

Solution (Python):

import sys
sys.setrecursionlimit(15000)
n = int(sys.stdin.readline())

ret = []
inp = sys.stdin.readlines()
G = [None]*(n)
d = [0]*(n)
f = [0]*(n)
def dfs(i,t):
  if d[i] != 0:
    return t
  t = t+1
  d[i] = t
  for j in G[i]:
    t = dfs(j,t)
  f[i] = t+1
  return f[i]
for i in range(n):
  v = list(map(int,inp[i].split()))
  G[v[0]-1] = list(map(lambda x: int(x-1),v[2:]))

t = 0
for j in range(n):
  t = dfs(j,t)

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

Solution (Python):

n = int(input())

graph = []
for _ in range(n):
    tmp = list(map(int, input().split()))
    if tmp[1] == 0:
        graph.append([])
    else:
        graph.append(tmp[2:])


check = [0]*n
count = 0
go = [0]*n
back = [0]*n

def dfs(v):
    
    global count
    if check[v] == 0:
        check[v] = 1
        count += 1
        go[v] = count
        tolist = graph[v]
        if len(tolist) > 0:
            for i in tolist:
                dfs(i-1)
        count += 1
        back[v] = count

while True:
    if 0 in check:
        k = check.index(0)
        dfs(k)
    else:
        break





for i in range(n):
    print("{} {} {}".format(i+1, go[i], back[i]))

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

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


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

Solution (Python):
def dfs(v, u=0):
    global n, t, d, f, reached
    if len(reached) == n:
        return

    d[u] = t
    t += 1

    reached.add(u + 1)
    for ui in range(v[u][1]):
        next = v[u][2 + ui]
        if next in reached:
            continue
        dfs(v, next - 1)

    f[u] = t
    t += 1


n = int(input())
v = []
for _ in range(n):
    v.append(list(map(int, input().split())))

t = 1
d = [0] * n
f = [0] * n
reached = set()


for ui in range(n):
    if ui + 1 not in reached:
        dfs(v, ui)

for ui in range(n):
    print('%d %d %d' % (ui + 1, d[ui], f[ui]))

Solution (Python):

def DFS(v,dis,fin):
  global time
  
  dis[v] = time
  time += 1
  
  
  for u in V[v]:
    if dis[u] is None:
      DFS(u,dis,fin)
  
  
  fin[v] = time
  time += 1
  
n = int(input())

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

Solution (Python):
n = int(input())

A = [[] for i in range(n)]

for i in range(n):
  A[i] = list(map(int, input().split()))

B = [[0 for i in range(2)] for j in range(n)]
order = []

time = 0

def dfs(n, num):
  global time
  while time < 2*n:
    a = num
    time += 1
    if B[num-1][0] == 0: 
      if A[num-1][1] != 0: 
        order.append(A[num-1][0]) 
        B[num-1][0] = time 
        A[num-1][1] -= 1 
        if B[A[num-1][2]-1][0] == 0: 
          num = A[num-1].pop(2) 
        else: 
          del A[num-1][2] 
      else: 
        l = len(order) 
        order.append(A[num-1][0]) 
        order.append(A[num-1][0]) 
        B[num-1][0] = time 
        time += 1 
        B[num-1][1] = time 
        num = order[l-1] 
    elif  B[num-1][1] == 0: 
      if A[num-1][1] == 0: 
        order.append(A[num-1][0]) 
        B[num-1][1] = time 
        m = order.index(num) 
        num = order[m-1] 
      else: 
        A[num-1][1] -= 1 
        order.append(A[num-1][0]) 
        if B[A[num-1][2]-1][0] == 0: 
          num = A[num-1].pop(2) 
        else: 
          del A[num-1][2] 
        time -= 1 
    else: 
      l = len(order) 
      num = order[l-1] 
      time -= 1 
      if num == a:
        break

for i in range(n):
  if B[i][0] == 0:
    dfs(n, A[i][0])

for i in range(n):
  print(str(i+1) + " ", end="")
  print(" ".join(map(str, B[i])))

Solution (Python):
G = {}
N = int(input())
for _ in range(N):
    L = list(map(int, input().split()))
    G[L[0]] = L[2:]


d = [-1] * N
f = [-1] * N
q = [1]
visited = [False] * N

time = 1


def dfs(v):
    global time
    visited[v-1] = True

    for nv in G[v]:
        if d[nv-1] < 0:
            d[nv-1] = time
            time += 1
        if not visited[nv-1]:
            dfs(nv)

    f[v-1] = time
    time += 1


for i in range(1, N+1):
    if not visited[i-1]:
        d[i-1] = time
        time += 1
        dfs(i)

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