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



import sys

UNVISITED, VISITED_IN_STACK, POPPED_OUT = 0, 1, 2


def generate_adj_matrix(v_info):
    for v_detail in v_info:
        v_adj_list = v_detail[2:]
        assert len(v_adj_list) == int(v_detail[1])
        for each in v_adj_list:
            init_adj_matrix[int(v_detail[0]) - 1][int(each) - 1] = 1
    return init_adj_matrix


def graph_dfs(v_init):
    global time

    
    vertex_visit_stack.append(v_init)
    vertex_status_list[v_init] = VISITED_IN_STACK
    vertex_d_time[v_init] += time
    

    while len(vertex_visit_stack) > 1:
        current_vertex = vertex_visit_stack[-1]
        next_vertex = get_adj_vertices(_vertex=current_vertex)

        if next_vertex:
            if vertex_status_list[next_vertex] is UNVISITED:
                vertex_status_list[next_vertex] = VISITED_IN_STACK
                time += 1
                vertex_d_time[next_vertex] += time
                vertex_visit_stack.append(next_vertex)
        else:
            vertex_visit_stack.pop()
            vertex_status_list[current_vertex] = POPPED_OUT
            time += 1
            vertex_f_time[current_vertex] += time

    return None


def get_adj_vertices(_vertex):
    for j in range(vertex_num):
        if adj_matrix[int(_vertex) - 1][j]:
            adj_matrix[int(_vertex) - 1][j] = 0
            return j + 1
    return None


def dfs_start():
    global time
    for i in range(vertex_num):
        if vertex_status_list[i + 1] == UNVISITED:
            
            graph_dfs(v_init=i + 1)
            time += 1


if __name__ == '__main__':
    _input = sys.stdin.readlines()
    vertex_num = int(_input[0])
    vertex_info = list(map(lambda x: x.split(), _input[1:]))
    init_adj_matrix = [[0] * vertex_num for _ in range(vertex_num)]
    

    
    vertex_visit_stack = [-1]
    vertex_status_list = [UNVISITED] * vertex_num
    vertex_status_list.insert(0, -1)
    vertex_d_time, vertex_f_time = ([0] * (vertex_num + 1) for _ in range(2))

    adj_matrix = generate_adj_matrix(vertex_info)
    time = 1
    dfs_start()
    for k in range(vertex_num):
        print(k + 1, vertex_d_time[k + 1], vertex_f_time[k + 1])

Solution (Python):



import sys

UNVISITED, VISITED_IN_STACK, POPPED_OUT = 0, 1, 2


def generate_adj_matrix(v_info):
    for v_detail in v_info:
        v_adj_list = v_detail[2:]
        assert len(v_adj_list) == int(v_detail[1])
        for each in v_adj_list:
            init_adj_matrix[int(v_detail[0]) - 1][int(each) - 1] = 1
    return init_adj_matrix


def graph_dfs(v_init):
    global time

    
    vertex_visit_stack.append(v_init)
    vertex_status_list[v_init] = VISITED_IN_STACK
    vertex_d_time[v_init] += time
    

    while len(vertex_visit_stack) > 1:
        current_vertex = vertex_visit_stack[-1]
        next_vertex = get_adj_vertices(vertex=current_vertex)

        if next_vertex:
            if vertex_status_list[next_vertex] is UNVISITED:
                vertex_status_list[next_vertex] = VISITED_IN_STACK
                time += 1
                vertex_d_time[next_vertex] += time
                vertex_visit_stack.append(next_vertex)
        else:
            vertex_visit_stack.pop()
            vertex_status_list[current_vertex] = POPPED_OUT
            time += 1
            vertex_f_time[current_vertex] += time

    return None


def get_adj_vertices(vertex):
    index = int(vertex) - 1
    for j in range(vertex_num):
        if adj_matrix[index][j]:
            adj_matrix[index][j] = 0
            return j + 1
    return None


def dfs_start():
    global time
    for i in range(vertex_num):
        if vertex_status_list[i + 1] == UNVISITED:
            
            graph_dfs(v_init=i + 1)
            time += 1


if __name__ == '__main__':
    _input = sys.stdin.readlines()
    vertex_num = int(_input[0])
    vertex_info = list(map(lambda x: x.split(), _input[1:]))
    init_adj_matrix = [[0] * vertex_num for _ in range(vertex_num)]
    

    
    vertex_visit_stack = [-1]
    vertex_status_list = [UNVISITED] * vertex_num
    vertex_status_list.insert(0, -1)
    vertex_d_time, vertex_f_time = ([0] * (vertex_num + 1) for _ in range(2))

    adj_matrix = generate_adj_matrix(vertex_info)
    
    time = 1
    dfs_start()
    for k in range(vertex_num):
        print(k + 1, vertex_d_time[k + 1], vertex_f_time[k + 1])

Solution (Python):



import sys

UNVISITED, VISITED_IN_STACK, POPPED_OUT = 0, 1, 2


def generate_adj_matrix(v_info):
    for v_detail in v_info:
        v_adj_list = v_detail[2:]
        
        for each in v_adj_list:
            init_adj_matrix[int(v_detail[0]) - 1][int(each) - 1] = 1
    return init_adj_matrix


def graph_dfs(v_init):
    global time

    
    vertices_visit_stack.append(v_init)
    vertices_status_list[v_init] = VISITED_IN_STACK
    vertices_d_time[v_init] += time
    

    while len(vertices_visit_stack) > 1:
        current_vertex = vertices_visit_stack[-1]
        next_vertex = get_adj_vertices(vertex=current_vertex)

        if next_vertex:
            if vertices_status_list[next_vertex] is UNVISITED:
                vertices_status_list[next_vertex] = VISITED_IN_STACK
                time += 1
                vertices_d_time[next_vertex] += time
                vertices_visit_stack.append(next_vertex)
        else:
            vertices_visit_stack.pop()
            vertices_status_list[current_vertex] = POPPED_OUT
            time += 1
            vertices_f_time[current_vertex] += time

    return None


def get_adj_vertices(vertex):
    index = int(vertex) - 1
    for j in range(vertices_num):
        if adj_matrix[index][j]:
            adj_matrix[index][j] = 0
            return j + 1
    return None


def dfs_start():
    global time
    for i in range(vertices_num):
        if vertices_status_list[i + 1] == UNVISITED:
            
            graph_dfs(v_init=i + 1)
            time += 1


if __name__ == '__main__':
    _input = sys.stdin.readlines()
    vertices_num = int(_input[0])
    vertices_info = list(map(lambda x: x.split(), _input[1:]))
    init_adj_matrix = [[0] * vertices_num for _ in range(vertices_num)]
    

    
    vertices_visit_stack = [-1]
    vertices_status_list = [UNVISITED] * vertices_num
    vertices_status_list.insert(0, -1)
    vertices_d_time, vertices_f_time = ([0] * (vertices_num + 1) for _ in range(2))

    adj_matrix = generate_adj_matrix(vertices_info)
    
    time = 1
    dfs_start()
    for k in range(vertices_num):
        print(k + 1, vertices_d_time[k + 1], vertices_f_time[k + 1])

Solution (Python):



import sys

UNVISITED, VISITED_IN_STACK, POPPED_OUT = 0, 1, 2


def generate_adj_matrix(v_info):
    for v_detail in v_info:
        v_adj_list = v_detail[2:]
        
        for each in v_adj_list:
            init_adj_matrix[int(v_detail[0]) - 1][int(each) - 1] = 1
    return init_adj_matrix


def graph_dfs(v_init):
    global time

    
    vertices_visit_stack.append(v_init)
    vertices_status_list[v_init] = VISITED_IN_STACK
    vertices_d_time[v_init] += time
    

    while len(vertices_visit_stack) > 1:
        current_vertex = vertices_visit_stack[-1]
        next_vertex = get_adj_vertices(vertex=current_vertex)

        if next_vertex:
            if vertices_status_list[next_vertex] is UNVISITED:
                vertices_status_list[next_vertex] = VISITED_IN_STACK
                time += 1
                vertices_d_time[next_vertex] += time
                vertices_visit_stack.append(next_vertex)
        else:
            vertices_visit_stack.pop()
            vertices_status_list[current_vertex] = POPPED_OUT
            time += 1
            vertices_f_time[current_vertex] += time

    return None


def get_adj_vertices(vertex):
    index = int(vertex) - 1
    for j in range(vertices_num):
        if adj_matrix[index][j]:
            adj_matrix[index][j] = 0
            return j + 1
    return None


def dfs_start():
    global time
    for i in range(vertices_num):
        if vertices_status_list[i + 1] == UNVISITED:
            
            graph_dfs(v_init=i + 1)
            time += 1


if __name__ == '__main__':
    _input = sys.stdin.readlines()
    vertices_num = int(_input[0])
    vertices_info = list(map(lambda x: x.split(), _input[1:]))
    init_adj_matrix = tuple([[0] * vertices_num for _ in range(vertices_num)])
    

    
    vertices_visit_stack = [-1]
    vertices_status_list = [UNVISITED] * vertices_num
    vertices_status_list.insert(0, -1)
    vertices_d_time, vertices_f_time = ([0] * (vertices_num + 1) for _ in range(2))

    adj_matrix = generate_adj_matrix(vertices_info)
    
    time = 1
    dfs_start()
    for k in range(vertices_num):
        print(k + 1, vertices_d_time[k + 1], vertices_f_time[k + 1])

Solution (Python):



"""
input:
6
1 2 2 3
2 2 3 4
3 1 5
4 1 6
5 1 6
6 0

output:
1 1 12
2 2 11
3 3 8
4 9 10
5 4 7
6 5 6
"""
import sys
from collections import deque

UNVISITED, VISITED_IN_STACK, POPPED_OUT = 0, 1, 2


def generate_adj_matrix(v_info):
    for v_detail in v_info:
        v_index, adj_num, *adj_list = map(int, v_detail)
        
        init_adj_table[v_index].extend(sorted(adj_list))
    return init_adj_table


def graph_dfs(v_init):
    global time

    
    stack.append(v_init)
    color[v_init] = VISITED_IN_STACK
    d_time[v_init] += time
    

    while len(stack) > 1:
        current = stack[-1]
        v_table = adj_table[current]
        adj = v_table.popleft() if v_table else None

        if adj:
            if color[adj] is UNVISITED:
                color[adj] = VISITED_IN_STACK
                time += 1
                d_time[adj] += time
                stack.append(adj)
        else:
            stack.pop()
            color[current] = POPPED_OUT
            time += 1
            f_time[current] += time

    return None


def dfs_start():
    global time
    for i in range(vertices_num):
        if color[i + 1] == UNVISITED:
            
            graph_dfs(i + 1)
            time += 1


if __name__ == '__main__':
    _input = sys.stdin.readlines()
    vertices_num = int(_input[0])
    vertices_info = map(lambda x: x.split(), _input[1:])
    init_adj_table = tuple(deque() for _ in range(vertices_num + 1))
    

    
    stack = [-1]
    color = [UNVISITED] * (vertices_num + 1)
    d_time, f_time = ([0] * (vertices_num + 1) for _ in range(2))

    adj_table = generate_adj_matrix(vertices_info)
    
    time = 1
    dfs_start()
    for k, v in enumerate(zip(d_time[1:], f_time[1:]), 1):
        print(k, *v)

Solution (Python):



"""
input:
6
1 2 2 3
2 2 3 4
3 1 5
4 1 6
5 1 6
6 0

output:
1 1 12
2 2 11
3 3 8
4 9 10
5 4 7
6 5 6
"""
import sys
from collections import deque

UNVISITED, VISITED_IN_STACK, POPPED_OUT = 0, 1, 2


def generate_adj_matrix(v_info):
    for v_detail in v_info:
        v_index, adj_num, *adj_list = map(int, v_detail)
        
        init_adj_table[v_index].extend(sorted(adj_list))
    return init_adj_table


def graph_dfs(v_init):
    global time

    
    stack.append(v_init)
    color[v_init] = VISITED_IN_STACK
    d_time[v_init] += time
    

    while len(stack) > 1:
        current = stack[-1]
        v_table = adj_table[current]
        adj = v_table.popleft() if v_table else None

        if adj:
            if color[adj] is UNVISITED:
                color[adj] = VISITED_IN_STACK
                time += 1
                d_time[adj] += time
                stack.append(adj)
        else:
            stack.pop()
            color[current] = POPPED_OUT
            time += 1
            f_time[current] += time

    return None


def dfs_start():
    global time
    for i in range(vertices_num):
        if color[i + 1] == UNVISITED:
            
            graph_dfs(i + 1)
            time += 1


if __name__ == '__main__':
    _input = sys.stdin.readlines()
    vertices_num = int(_input[0])
    vertices_info = map(lambda x: x.split(), _input[1:])
    init_adj_table = tuple(deque() for _ in range(vertices_num + 1))
    

    
    stack = [-1]
    color = [UNVISITED] * (vertices_num + 1)
    d_time, f_time = ([0] * (vertices_num + 1) for _ in range(2))

    adj_table = generate_adj_matrix(vertices_info)
    
    time = 1
    dfs_start()
    for k, v in enumerate(zip(d_time[1:], f_time[1:]), 1):
        print(k, *v)

Solution (Python):



"""
input:
6
1 2 2 3
2 2 3 4
3 1 5
4 1 6
5 1 6
6 0

output:
1 1 12
2 2 11
3 3 8
4 9 10
5 4 7
6 5 6
"""
import sys

UNVISITED, VISITED_IN_STACK, POPPED_OUT = 0, 1, 2


def generate_adj_matrix(v_info):
    for v_detail in v_info:
        v_index, adj_num, *adj_list = map(int, v_detail)
        
        init_adj_table[v_index].extend(sorted(adj_list, reverse=True))
    return init_adj_table


def graph_dfs(v_init):
    global time

    
    stack.append(v_init)
    color[v_init] = VISITED_IN_STACK
    d_time[v_init] += time
    

    while len(stack) > 1:
        current = stack[-1]
        v_table = adj_table[current]
        adj = v_table.pop() if v_table else None

        if adj:
            if color[adj] is UNVISITED:
                color[adj] = VISITED_IN_STACK
                time += 1
                d_time[adj] += time
                stack.append(adj)
        else:
            stack.pop()
            color[current] = POPPED_OUT
            time += 1
            f_time[current] += time

    return None


def dfs_start():
    global time
    for i in range(vertices_num):
        if color[i + 1] == UNVISITED:
            
            graph_dfs(i + 1)
            time += 1


if __name__ == '__main__':
    _input = sys.stdin.readlines()
    vertices_num = int(_input[0])
    vertices_info = map(lambda x: x.split(), _input[1:])
    init_adj_table = tuple([] for _ in range(vertices_num + 1))
    

    
    stack = [-1]
    color = [UNVISITED] * (vertices_num + 1)
    d_time, f_time = ([0] * (vertices_num + 1) for _ in range(2))

    adj_table = generate_adj_matrix(vertices_info)
    
    time = 1
    dfs_start()
    for k, v in enumerate(zip(d_time[1:], f_time[1:]), 1):
        print(k, *v)

Solution (Python):



"""
input:
6
1 2 2 3
2 2 3 4
3 1 5
4 1 6
5 1 6
6 0

output:
1 1 12
2 2 11
3 3 8
4 9 10
5 4 7
6 5 6
"""
import sys

UNVISITED, VISITED_IN_STACK, POPPED_OUT = 0, 1, 2


def generate_adj_matrix(v_info):
    for v_detail in v_info:
        v_index, adj_num, *adj_list = map(int, v_detail)
        
        init_adj_table[v_index].extend(sorted(adj_list, reverse=True))
    return init_adj_table


def graph_dfs(v_init):
    global time

    
    stack.append(v_init)
    color[v_init] = VISITED_IN_STACK
    d_time[v_init] += time
    

    while stack:
        current = stack[-1]
        v_table = adj_table[current]
        
        adj = v_table.pop() if v_table else None

        if adj:
            if color[adj] is UNVISITED:
                color[adj] = VISITED_IN_STACK
                time += 1
                d_time[adj] += time
                stack.append(adj)
        else:
            stack.pop()
            color[current] = POPPED_OUT
            time += 1
            f_time[current] += time

    return None


def dfs_start():
    global time
    for i in range(vertices_num):
        if color[i + 1] == UNVISITED:
            
            graph_dfs(i + 1)
            time += 1


if __name__ == '__main__':
    _input = sys.stdin.readlines()
    vertices_num = int(_input[0])
    vertices_info = map(lambda x: x.split(), _input[1:])
    init_adj_table = tuple([] for _ in range(vertices_num + 1))
    

    
    stack = []
    color = [UNVISITED] * (vertices_num + 1)
    d_time, f_time = ([0] * (vertices_num + 1) for _ in range(2))

    adj_table = generate_adj_matrix(vertices_info)
    
    time = 1
    dfs_start()

    for index, v in enumerate(zip(d_time[1:], f_time[1:]), 1):
        print(index, *v)

Solution (Python):



"""
input:
6
1 2 2 3
2 2 3 4
3 1 5
4 1 6
5 1 6
6 0

output:
1 1 12
2 2 11
3 3 8
4 9 10
5 4 7
6 5 6
"""
import sys

UNVISITED, VISITED_IN_STACK, POPPED_OUT = 0, 1, 2


def generate_adj_matrix(v_info):
    for v_detail in v_info:
        v_index, adj_num, *adj_list = map(int, v_detail)
        
        init_adj_table[v_index].extend(sorted(adj_list, reverse=True))
    return init_adj_table


def graph_dfs(v_init):
    global time

    
    stack.append(v_init)
    color[v_init] = VISITED_IN_STACK
    d_time[v_init] += time
    

    while stack:
        current = stack[-1]
        v_table = adj_table[current]
        color[current]=VISITED_IN_STACK
        
        adj = v_table.pop() if v_table else None

        if adj:
            if color[adj] is UNVISITED:
                color[adj] = VISITED_IN_STACK
                time += 1
                d_time[adj] += time
                stack.append(adj)
        else:
            stack.pop()
            color[current] = POPPED_OUT
            time += 1
            f_time[current] += time

    return None


def dfs_start():
    global time
    for i in range(vertices):
        if color[i + 1] == UNVISITED:
            
            graph_dfs(i + 1)
            time += 1


if __name__ == '__main__':
    _input = sys.stdin.readlines()
    vertices = int(_input[0])
    v_info = map(lambda x: x.split(), _input[1:])
    init_adj_table = tuple([] for _ in range(vertices + 1))
    

    
    stack = []
    color = [UNVISITED] * (vertices + 1)
    d_time, f_time = ([0] * (vertices + 1) for _ in range(2))

    adj_table = generate_adj_matrix(v_info)
    
    time = 1
    dfs_start()

    for index, v in enumerate(zip(d_time[1:], f_time[1:]), 1):
        print(index, *v)

Solution (Python):



"""
input:
6
1 2 2 3
2 2 3 4
3 1 5
4 1 6
5 1 6
6 0

output:
1 1 12
2 2 11
3 3 8
4 9 10
5 4 7
6 5 6
"""
import sys

UNVISITED, VISITED_IN_STACK, POPPED_OUT = 0, 1, 2


def generate_adj_matrix(v_info):
    for v_detail in v_info:
        v_index, adj_num, *adj_list = map(int, v_detail)
        
        init_adj_table[v_index].extend(sorted(adj_list, reverse=True))
    return init_adj_table


def graph_dfs(v_init):
    global time

    
    stack.append(v_init)
    d_time[v_init] += time
    

    while stack:
        current = stack[-1]
        v_table = adj_table[current]
        color[current]=VISITED_IN_STACK
        
        adj = v_table.pop() if v_table else None

        if adj:
            if color[adj] is UNVISITED:
                color[adj] = VISITED_IN_STACK
                time += 1
                d_time[adj] += time
                stack.append(adj)
        else:
            stack.pop()
            color[current] = POPPED_OUT
            time += 1
            f_time[current] += time

    return None


def dfs_start():
    global time
    for i in range(vertices):
        if color[i + 1] == UNVISITED:
            
            graph_dfs(i + 1)
            time += 1


if __name__ == '__main__':
    _input = sys.stdin.readlines()
    vertices = int(_input[0])
    v_info = map(lambda x: x.split(), _input[1:])
    init_adj_table = tuple([] for _ in range(vertices + 1))
    

    
    stack = []
    color = [UNVISITED] * (vertices + 1)
    d_time, f_time = ([0] * (vertices + 1) for _ in range(2))

    adj_table = generate_adj_matrix(v_info)
    
    time = 1
    dfs_start()

    for index, v in enumerate(zip(d_time[1:], f_time[1:]), 1):
        print(index, *v)

Solution (Python):

        
def DFS(i,A,d,f,t):
    if d[i-1]:
        return t
    d[i-1]=t
    t+=1
    for j in A[i-1]:
        t=DFS(j,A,d,f,t)
    f[i-1]=t
    t+=1
    return t

if __name__=="__main__":
    n=int(input())
    A=[]
    for i in range(n):
        A.append(list(map(int,input().split(" ")))[2:])
    d=[0]*n
    f=[0]*n
    t=1
    for i in range(n):
        if d[i]==0:
            t=DFS(i+1,A,d,f,t)
    for i in range(n):
        print("{} {} {}".format(i+1,d[i],f[i]))

Solution (Python):
from enum import Enum


class Dfs(object):
    """ Depth First Search """
    class Status(Enum):
        white = 1
        gray = 2
        black = 3

    def __init__(self, data):
        self.time = 0
        num_of_nodes = len(data)+1
        self.color = [Dfs.Status.white] * (num_of_nodes+1)
        self.S = []
        self.M = self._make_matrix(data)
        self.s_time = [0] * (len(data) + 1)
        self.f_time = [0] * (len(data) + 1)

    def _make_matrix(self, data):
        """ ??£??\??????????????? (M[i][j]?????¢??§??????????????????+1??????????????????????????????) """
        num = len(data)
        graph_table = [[0] * (num+1) for _ in range(num+1)]
        for d in data:
            node_id = d[0]
            num_of_e = d[1]
            for e in d[2:]:
                graph_table[node_id][e] = 1
        return graph_table

    def search(self, start):
        self.time += 1
        self.s_time[start] = self.time
        self.S.append(start)
        self.color[start] = Dfs.Status.gray

        while self.S:
            u = self.S[-1]
            v = self.next(u)
            if v != None:
                if self.color[v] == Dfs.Status.white:
                    self.color[v] = Dfs.Status.gray
                    self.time += 1
                    self.s_time[v] = self.time
                    self.S.append((v))
            else:
                self.S = self.S[:-1]
                self.color[u] = Dfs.Status.black
                self.time += 1
                self.f_time[u] = self.time

    def next(self, node):
        """ ?¬?????¨???????????±???????????????????????????????????????????????¨??????????????????????????????? """
        edges = self.M[node]
        for i in range(1, len(edges)):
            if edges[i] == 1:
                if self.color[i] == Dfs.Status.white:
                    return i
        return None

    def print(self):
        for r in self.M:
            print(*r)


if __name__ == '__main__':
    
    num = int(input())
    data = []
    for _ in range(num):
        data.append(list(map(int, input().split(' '))))

    
    d = Dfs(data)
    for i in range(1, num+1):
        if d.color[i] == Dfs.Status.white:
            d.search(i)

    
    for i in range(1, num+1):
        print('{0} {1} {2}'.format(i, d.s_time[i], d.f_time[i]))

Solution (Python):



"""

input:
6
1 2 2 3
2 2 3 4
3 1 5
4 1 6
5 1 6
6 0

output:
1 1 12
2 2 11
3 3 8
4 9 10
5 4 7
6 5 6

"""
import sys

UNVISITED, VISITED_IN_STACK, POPPED_OUT = 0, 1, 2


def dfs(v_init):
    global timer

    
    stack = list()
    stack.append(v_init)
    d_time[v_init] += timer
    

    while stack:
        current = stack[-1]
        v_table = adj_table[current]
        visited[current] = VISITED_IN_STACK
        
        adj = v_table.pop() if v_table else None

        if adj:
            if visited[adj] is UNVISITED:
                visited[adj] = VISITED_IN_STACK
                timer += 1
                d_time[adj] += timer
                stack.append(adj)
        else:
            stack.pop()
            visited[current] = POPPED_OUT
            timer += 1
            f_time[current] += timer

    return None


def dfs_init():
    global timer
    for v in range(v_num):
        if visited[v + 1] == UNVISITED:
            dfs(v + 1)
            timer += 1


if __name__ == '__main__':
    _input = sys.stdin.readlines()
    v_num = int(_input[0])
    vertices = map(lambda x: x.split(), _input[1:])

    
    
    visited = [UNVISITED] * (v_num + 1)
    d_time, f_time = ([0] * (v_num + 1) for _ in range(2))
    adj_table = tuple([] for _ in range(v_num + 1))
    for v_info in vertices:
        v_index, adj_num, *adj_list = map(int, v_info)
        
        adj_table[v_index].extend(sorted(adj_list, reverse=True))

    
    timer = 1
    dfs_init()

    for index, time_info in enumerate(zip(d_time[1:], f_time[1:]), 1):
        print(index, *time_info)

Solution (Python):



"""

input:
6
1 2 2 3
2 2 3 4
3 1 5
4 1 6
5 1 6
6 0

output:
1 1 12
2 2 11
3 3 8
4 9 10
5 4 7
6 5 6

"""
import sys

UNVISITED, VISITED_IN_STACK, POPPED_OUT = 0, 1, 2


def dfs(v_init):
    global timer

    
    stack = list()
    stack.append(v_init)
    d_time[v_init] += timer
    

    while stack:
        current = stack[-1]
        v_table = adj_table[current]
        visited[current] = VISITED_IN_STACK
        
        adj = v_table.pop() if v_table else None

        if adj:
            if visited[adj] is UNVISITED:
                visited[adj] = VISITED_IN_STACK
                timer += 1
                d_time[adj] += timer
                stack.append(adj)
        else:
            stack.pop()
            visited[current] = POPPED_OUT
            timer += 1
            f_time[current] += timer

    return None


def dfs_init():
    global timer
    for v in range(v_num):
        if visited[v + 1] == UNVISITED:
            timer += 1
            dfs(v + 1)


if __name__ == '__main__':
    _input = sys.stdin.readlines()
    v_num = int(_input[0])
    vertices = map(lambda x: x.split(), _input[1:])

    
    
    visited = [UNVISITED] * (v_num + 1)
    d_time, f_time = ([0] * (v_num + 1) for _ in range(2))
    adj_table = tuple([] for _ in range(v_num + 1))
    for v_info in vertices:
        v_index, adj_num, *adj_list = map(int, v_info)
        
        adj_table[v_index].extend(sorted(adj_list, reverse=True))

    
    timer = 0
    dfs_init()

    for index, time_info in enumerate(zip(d_time[1:], f_time[1:]), 1):
        print(index, *time_info)

Solution (Python):



"""

input:
6
1 2 2 3
2 2 3 4
3 1 5
4 1 6
5 1 6
6 0

output:
1 1 12
2 2 11
3 3 8
4 9 10
5 4 7
6 5 6

"""
import sys

UNVISITED, VISITED_IN_STACK, POPPED_OUT = 0, 1, 2


def dfs(v_init):
    global timer

    
    stack = list()
    stack.append(v_init)
    d_time[v_init] += timer
    

    while stack:
        current = stack[-1]
        v_table = adj_table[current]
        visited[current] = VISITED_IN_STACK
        
        adj = v_table.pop() if v_table else None

        if adj:
            if visited[adj] is UNVISITED:
                visited[adj] = VISITED_IN_STACK
                timer += 1
                d_time[adj] += timer
                stack.append(adj)
        else:
            stack.pop()
            visited[current] = POPPED_OUT
            timer += 1
            f_time[current] += timer

    return None


def dfs_init():
    global timer
    for v in range(v_num):
        if visited[v + 1] == UNVISITED:
            timer += 1
            dfs(v + 1)


if __name__ == '__main__':
    _input = sys.stdin.readlines()
    v_num = int(_input[0])
    vertices = map(lambda x: x.split(), _input[1:])

    
    
    visited = [UNVISITED] * (v_num + 1)
    d_time, f_time = ([0] * (v_num + 1) for _ in range(2))
    adj_table = tuple([] for _ in range(v_num + 1))
    for v_info in vertices:
        v_index, adj_num, *adj_list = map(int, v_info)
        
        adj_table[v_index].extend(sorted(adj_list, reverse=True))

    
    timer = 0
    dfs_init()

    for index, time_info in enumerate(zip(d_time[1:], f_time[1:]), 1):
        print(index, *time_info)

Solution (Python):



"""

input:
6
1 2 2 3
2 2 3 4
3 1 5
4 1 6
5 1 6
6 0

output:
1 1 12
2 2 11
3 3 8
4 9 10
5 4 7
6 5 6

"""
import sys

UNVISITED, VISITED_IN_STACK, POPPED_OUT = 0, 1, 2


def dfs(v_init):
    global timer

    
    stack = list()
    stack.append(v_init)
    d_time[v_init] += timer
    

    while stack:
        current = stack[-1]
        v_table = adj_table[current]
        visited[current] = VISITED_IN_STACK
        
        adj = v_table.pop() if v_table else None

        if adj:
            if visited[adj] is UNVISITED:
                visited[adj] = VISITED_IN_STACK
                timer += 1
                d_time[adj] += timer
                stack.append(adj)
        else:
            stack.pop()
            visited[current] = POPPED_OUT
            timer += 1
            f_time[current] += timer

    return None


def dfs_init():
    global timer
    for v in range(v_num):
        if visited[v + 1] == UNVISITED:
            timer += 1
            dfs(v + 1)


if __name__ == '__main__':
    _input = sys.stdin.readlines()
    v_num = int(_input[0])
    vertices = map(lambda x: x.split(), _input[1:])

    visited = [UNVISITED] * (v_num + 1)
    d_time, f_time = ([0] * (v_num + 1) for _ in range(2))
    adj_table = tuple([] for _ in range(v_num + 1))
    for v_info in vertices:
        v_idx, adj_num, *adj_list = map(int, v_info)
        
        adj_table[v_idx].extend(sorted(adj_list, reverse=True))

    timer = 0
    dfs_init()

    for v_idx, time_info in enumerate(zip(d_time[1:], f_time[1:]), 1):
        print(v_idx, *time_info)