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 C# (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CompProgLib;

namespace ALDS1_11_B
{
    public class Program

    {
        public static void Main(string[] args)
        {
            
            int n = ReadInt();
            Graph gr = new Graph();

            for (int i = 0 ; i < n ; i++)
            {
                int[] line = ReadIntAr();
                gr.SetGraph(line[0], line.Skip(2).ToArray());
            }
            
            foreach (var key in gr.Adj.Keys)
            {
               if(!gr.Adj[key].IsVisited) gr.DFS(key);
            }

            foreach (var item in gr.Adj)
            {
                Console.WriteLine("{0} {1} {2}", item.Key, item.Value.D, item.Value.F);
            }
        }


        static string ReadSt() { return Console.ReadLine(); }
        static int ReadInt() { return int.Parse(Console.ReadLine()); }
        static long ReadLong() { return long.Parse(Console.ReadLine()); }
        static double ReadDouble() { return double.Parse(Console.ReadLine()); }
        static string[] ReadStAr(char sep = ' ') { return Console.ReadLine().Split(sep); }
        static int[] ReadIntAr(char sep = ' ') { return Array.ConvertAll(Console.ReadLine().Split(sep), e => int.Parse(e)); }
        static long[] ReadLongAr(char sep = ' ') { return Array.ConvertAll(Console.ReadLine().Split(sep), e => long.Parse(e)); }
        static double[] ReadDoubleAr(char sep = ' ') { return Array.ConvertAll(Console.ReadLine().Split(sep), e => double.Parse(e)); }

    }

}

namespace CompProgLib
{
    public class Graph
    {
        public class Node
        {
            public List<int> Vartex { get; internal set; }
            public int D { get; internal set; }
            public int F { get; internal set; }
            public bool IsVisited { get; internal set; }

            public Node(List<int> v)
            {
                Vartex = v;
            }
        }

        public Dictionary<int, Node> Adj { get; set; }

        public Graph()
        {
            Adj = new Dictionary<int, Node>();
        }

        /// <summary>
        /// 隣接行列の指定したインデックスに値をセットする
        /// </summary>
        /// <param name="index">頂点u</param>
        /// <param name="item">頂点uに接続する頂点</param>
        public void SetGraph(int index, int[] item)
        {
            Adj.Add(index, new Node(item.ToList()));
        }

        /// <summary>
        /// 行列を0で初期化する
        /// </summary>
        public void Clear() { Adj.Clear(); }

        /// <summary>
        /// 深さ優先探索
        /// </summary>
        private int Time = 0;
        public void DFS(int v)
        {
            Adj[v].D = ++Time;
            Adj[v].IsVisited = true;
            foreach (int vartex in Adj[v].Vartex)
            {
                if (!Adj[vartex].IsVisited) DFS(vartex);                
            }
            Adj[v].F = ++Time;
        }
    }
}