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.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using static System.Math;

namespace CSharpSpiral {
	class Program {
		static void Main(string[] args) {
			var sw = new StreamWriter(Console.OpenStandardOutput()) {
				AutoFlush=
#if DEBUG
			true
#else
			false
#endif
			};
			Console.SetOut(sw);
			new Program().Solve(new ConsoleInput(
#if DEBUG
			new StreamReader("../../../inputData.txt")
#else
			Console.In
#endif
			, ' '));
			Console.Out.Flush();
		}
		public void Solve(ConsoleInput cin) {
			var N = cin.ReadInt;
			var G = new Graph<int>(N);
			for(int i = 0; i<N; i++) {
				var u = cin.ReadInt;
				var k = cin.ReadInt;
				if(k==0) continue;
				var emits = cin.ReadIntArray(k);
				foreach(var to in emits) {
					G.AddEdge(u-1, to-1, 1);
				}
			}
			var visited = new bool[N];
			var count = 0;
			var preorder = new int[N];
			var postorder = new int[N];
			for(int i = 0; i<N; i++) {
				if(visited[i]) continue;
				G.DFS(i, v => { preorder[v.Id]=++count; visited[v.Id]=true; }, v => { postorder[v.Id]=++count; });
			}
			for(int i = 0; i<N; i++) {
				Console.WriteLine($"{i+1} {preorder[i]} {postorder[i]}");
			}
		}

	}
	static class ExtendClass {
		public static void Swap<T>(this T[] A, int x, int y) {
			var tmp = A[x];
			A[x]=A[y];
			A[y]=tmp;
		}
		public static string Join<T>(this IEnumerable<T> X, string separator = " ") => string.Join(separator, X);
		public static IEnumerable<int> Indices<T>(this T[] X) => Enumerable.Range(0, X.Length);
		public static IEnumerable<int> Indices<T>(this T[,] X, int dim)
			=> Enumerable.Range(0, X.GetLength(dim));
		//public static IEnumerable<(int i1, int i2)> Indices<T>(this T[,] X)
		//	=> X.Indices(0).SelectMany(i => X.Indices(1).Select((i, j) => (i, j)));
		public static string Join<T>(this T[,] X, string separatorD2 = ",", string separatorD1 = "\n")
			=> X.Indices(0).Select(
				i => X.Indices(1).Select(j => X[i, j]).Join(separatorD2)
			).Join(separatorD1);
	}
	class ConsoleInput {
		private readonly TextReader _stream;
		private readonly char _separator = ' ';
		private readonly Queue<string> inputStream;
		public ConsoleInput(TextReader stream, char separator = ' ') {
			this._separator=separator;
			this._stream=stream;
			inputStream=new Queue<string>();
		}
		public string Read {
			get {
				if(inputStream.Count!=0) return inputStream.Dequeue();
				string[] tmp = _stream.ReadLine().Split(_separator);
				for(int i = 0; i<tmp.Length; ++i)
					inputStream.Enqueue(tmp[i]);
				return inputStream.Dequeue();
			}
		}
		public string ReadLine { get { return _stream.ReadLine(); } }
		public int ReadInt { get { return int.Parse(Read); } }
		public long ReadLong { get { return long.Parse(Read); } }
		public double ReadDouble { get { return double.Parse(Read); } }
		public string[] ReadStrArray(long N) {
			var ret = new string[N];
			for(long i = 0; i<N; ++i)
				ret[i]=Read;
			return ret;
		}
		public int[] ReadIntArray(long N) { var ret = new int[N]; for(long i = 0; i<N; ++i) ret[i]=ReadInt; return ret; }
		public long[] ReadLongArray(long N) { var ret = new long[N]; for(long i = 0; i<N; ++i) ret[i]=ReadLong; return ret; }
		public double[] ReadDoubleArray(long N) { var ret = new double[N]; for(long i = 0; i<N; ++i) ret[i]=ReadDouble; return ret; }
		public bool isEOF {
			get { return _stream.Peek()==-1; }
		}
	}
	class Node<T> {
		public T Value { get; set; }
		public int Id { get; set; }
		public int Order{ get; set; }
		public bool visited { get; set; }
		public virtual List<Edge<T>> Outs { get; set; } = new List<Edge<T>>();
		public void Adopt(Edge<T> child) {
			Outs.Add(child);
		}

		public virtual List<Node<T>> Nexts() => Outs.Select(e => e.to).ToList();
	}
	struct Edge<T> {
		public Node<T> from { get; set; }
		public Node<T> to { get; set; }
		public T value { get; set; }
		public Edge(Node<T> _from, Node<T> _to, T _value) {
			from=_from; to=_to; value=_value;
		}
	}
	class Graph<T> {
		public Node<T>[] member { get; }
		public int N { get; }
		public Graph(int N) {
			member=new Node<T>[N];
			this.N=N;
			for(int i = 0; i<N; i++) {
				member[i]=new Node<T>() { Id=i };
			}
		}
		public void AddEdge(int i, int j, T value) {
			var e = new Edge<T>(member[i], member[j], value);
			member[i].Adopt(e);
		}
		public string EmitMatrix() {
			var rows = new string[N];
			for(int i = 0; i<N; i++) {
				var values = new T[N];
				foreach(var e in member[i].Outs)
					values[e.to.Id]=e.value;
				rows[i]=values.Join();
			}
			return rows.Join("\n");
		}
		public void DFS(int start, Action<Node<T>> onEnter, Action<Node<T>> onLeave) {
			var S = new Stack<Node<T>>();
			S.Push(member[start]);
			var entered = new bool[N];
			var leaved = new bool[N];
			member[start].visited=true;
			while(S.Any()) {
				var v = S.Peek();
				if(!entered[v.Id]) {
					onEnter(v);
					entered[v.Id]=true;
				}
				var next = v.Nexts().Where(w => !w.visited);
				if(next.Any()) {
					var w = next.First();
					S.Push(w);
					w.visited=true;
				} else {
					S.Pop();
					if(!leaved[v.Id]) {
						onLeave(v);
						leaved[v.Id]=true;
					}
				}
			}
		}

	}
}