Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

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 in Ruby (judge verdict: Accepted)

#-- 未訪問のxの隣接ノード番号を返す。見つからないとnilを返す。
#--------------------------------------------------------------
def next_neighbor nodes, x
  nodes[x][:neighbors].each do |neighbor|
    if nodes[neighbor][:visit] == nil
        return neighbor
    end
  end
  nil
end

#-- スタックが空になるまで探索
#--------------------------------------------------------------
def dfs stack, nodes, stamp
  if stack == []
    return [stack, nodes, stamp]
  end

  x = stack.last
  y = next_neighbor nodes, x
  stamp += 1

  if y == nil
  #-- y == nil -> 未訪問の隣接ノードがなくなった -> xをスタックから削除 して完了印
    stack.pop
    nodes[x][:fix] = stamp
  else
  #-- y == not nil -> 未訪問の隣接ノードが見つかった -> スタックへpushして訪問印
    stack.push y
    nodes[y][:visit] = stamp
  end

  dfs stack, nodes, stamp
end

#-- メイン処理
#-------------------
nodes = [] #-- 訪問時刻、完了時刻、隣接リストを持ったノードの配列
stack = [] #-- 訪問中のノードを格納するスタック
stamp = 0  #-- 訪問時刻

#-- 入力を受け取って自分の隣接リストを持つnodeのリスト(nodes)を作成
n = gets.to_i
n.times do
 no, na, *ns = gets.split.map(&:to_i)
 nodes[no] = { neighbors: ns }
end

#-- nodesを小さい方から調べて訪問してないならそれを支点としてDFSする
[*1...nodes.length].each do |i|
  if nodes[i][:visit] == nil
    stack.push i; stamp += 1; nodes[i][:visit] = stamp
    stack, nodes, stamp = dfs stack, nodes, stamp
  end
end

#-- 表示
[*1...nodes.length].each_with_index do |i|
  puts "#{i} #{nodes[i][:visit]} #{nodes[i][:fix]}"
end