Go: package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
)

var scanner = bufio.NewScanner(os.Stdin)

func nextString() string {
	scanner.Scan()
	return scanner.Text()
}

func nextInt() int {
	n, err := strconv.Atoi(nextString())
	if err != nil {
		fmt.Printf("strconv.Atoi failed: %v\n", err)
	}
	return n
}

var infty = 1000000000

type nodeKey int

type DirectedGraphNode struct {
	key       nodeKey
	adjacents []*DirectedGraphNode
	visited   bool
	d         int
	f         int
	parent    *DirectedGraphNode
}

type DirectedGraph struct {
	nodes []*DirectedGraphNode
}

func (g *DirectedGraph) setAdjacency(l, r nodeKey) {
	g.nodes[l].adjacents = append(g.nodes[l].adjacents, g.nodes[r])
}

func newDirectedGraph(nNodes int) *DirectedGraph {
	graph := DirectedGraph{}
	graph.nodes = make([]*DirectedGraphNode, nNodes)
	for iNodes := 0; iNodes < nNodes; iNodes++ {
		graph.nodes[iNodes] = &DirectedGraphNode{}
		graph.nodes[iNodes].key = nodeKey(iNodes)

		graph.nodes[iNodes].visited = false
		graph.nodes[iNodes].d = infty
		graph.nodes[iNodes].f = infty
		graph.nodes[iNodes].parent = nil
	}
	return &graph
}

type QueueEntry struct {
	node *DirectedGraphNode
	next *QueueEntry
}

type Queue struct {
	head, tail *QueueEntry
}

func (q *Queue) enqueue(node *DirectedGraphNode) {
	entry := QueueEntry{}
	entry.node = node

	if q.tail == nil {
		q.head = &entry
		q.tail = &entry
		return
	}

	q.tail.next = &entry
	q.tail = q.tail.next
}

func (q *Queue) dequeue() *QueueEntry {
	if q.head == nil {
		return nil
	}
	poped := q.head
	q.head = q.head.next
	if q.head == nil {
		q.tail = nil
	}
	return poped
}

func (q *Queue) isEmpty() bool {
	return q.head == nil
}

var time = 0

func fillDistancesByDepthFirstSearch(g *DirectedGraph) {
	for _, u := range g.nodes[1:] {
		if !u.visited {
			dfsVisit(g, u)
		}
	}
}

func dfsVisit(g *DirectedGraph, u *DirectedGraphNode) {
	time++
	u.d = time

	u.visited = true
	for _, v := range u.adjacents {
		if !v.visited {
			v.parent = u
			dfsVisit(g, v)
		}
	}
	time++
	u.f = time
}

func main() {
	scanner.Split(bufio.ScanWords)

	nNodes := nextInt()
	g := newDirectedGraph(nNodes + 1)

	for iNode := 0; iNode < nNodes; iNode++ {
		nodeKeyLeft := nodeKey(nextInt())
		nAdj := nextInt()
		for iAdj := 0; iAdj < nAdj; iAdj++ {
			nodeKeyRight := nodeKey(nextInt())
			g.setAdjacency(nodeKeyLeft, nodeKeyRight)
		}
	}

	fillDistancesByDepthFirstSearch(g)

	for iNode := 1; iNode <= nNodes; iNode++ {
		node := g.nodes[iNode]
		fmt.Println(node.key, node.d, node.f)
	}
}

C++: #include <iostream>
#include <list>
#include <vector>

struct TNode
{
	int Index;
	bool Visited;
	std::list<TNode*> Target;
	
	int ClockStart;
	int ClockEnd;
	
	TNode(int AIndex)
	: Index(AIndex), Visited(false), ClockStart(0), ClockEnd(0)
	{
	}
	
	void Visit(int& Clock)
	{
		if(Visited) return;
		Visited = true;
		ClockStart = Clock;
		++Clock;
		for(std::list<TNode*>::iterator It = Target.begin(); It != Target.end(); ++It){
			(*It)->Visit(Clock);
		}
		ClockEnd = Clock;
		++Clock;
	}
};

class TGraph
{
	std::vector<TNode*> FNodes;
public:
	TGraph(int Count)
	: FNodes(Count)
	{
		for(int i = 0; i < Count; ++i){
			FNodes[i] = new TNode(i + 1);
		}
	}
	
	~TGraph()
	{
		for(unsigned int i = 0; i < FNodes.size(); ++i){
			delete FNodes[i];
		}
	}
	
	void InputNode(int Index, int BranchCount)
	{
		for(int i = 0; i < BranchCount; ++i){
			int Target;
			std::cin >> Target;
			FNodes[Index - 1]->Target.push_back(FNodes[Target - 1]);
		}
	}
	
	void DepthFirstSearch()
	{
		int Clock = 1;
		FNodes[0]->Visit(Clock);
	}
	
	void OutputClocks()const
	{
		for(unsigned int i = 0; i < FNodes.size(); ++i){
			std::cout << FNodes[i]->Index      << " "
			          << FNodes[i]->ClockStart << " "
			          << FNodes[i]->ClockEnd   << std::endl;
		}
	}
};

int main()
{
	int Count;
	std::cin >> Count;
	TGraph Graph(Count);
	for(int i = 0; i < Count; ++i){
		int Index;
		std::cin >> Index;
		int BranchCount;
		std::cin >> BranchCount;
		Graph.InputNode(Index, BranchCount);
	}
	Graph.DepthFirstSearch();
	Graph.OutputClocks();
	return 0;
}

C++: #include <iostream>
#include <vector>
#include <string>

using namespace std;

int n;
vector<vector<int>> g; 
int time = 0;
vector<int> d, f;
 
void dfs(int node){
    time++;

    if(d[node] == 0){
        d[node] = time;
    }

    for(auto next : g[node]){
        if(d[next] == 0){
            dfs(next);
        }
    }
    
    time++;
    if(f[node] == 0){
        f[node] = time;
    }
}
    
int main(){
    
    cin >> n;

    d.assign(n + 1, 0);
    f.assign(n + 1, 0);

    g.assign(n + 1, vector<int>());

    for(int i = 0; i < n; i++)
    {
        int nod, numOut;
        cin  >> nod >> numOut;
        for(int j = 0; j < numOut; j++)
        {
            int temp;
            cin >> temp;
            g[nod].push_back(temp);
        }
    }
    
    dfs(1);

    for(int i = 1; i <= n; i++)
    {
        cout << i << " " << d[i] << " " << f[i] << endl;
    }
    

    return 0;
}

C++: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
constexpr int di[] = {0, 1, 0, -1}, dj[] = {1, 0, -1, 0};
#define rep(i, n) for (int i = 0; i < n; i++)
#define repr(i, n) for (int i = n; i >= 0; i--)
#define sort(v) sort((v).begin(), (v).end())
#define sortr(v) sort((v).rbegin(), (v).rend())
#define all(v) (v).begin(), (v).end()
#define max 100005
#define nil -1

vector<vector<int>> g;
int t=0;
vector<int> d,f;
vector<bool> visited;

void dfs(int u){
    visited[u]=true;
    t++;
    d[u]=t;
    for(auto to:g[u]){
        if(!visited[to]){
            dfs(to);
        }
    }
    t++;
    f[u]=t;
}

int main() {
  int  n,u,k,v;
  cin>>n;
    g.resize(n);
    d.resize(n);
    f.resize(n);
    visited.resize(n, false);
  rep(i,n){
      cin>>u>>k;
      u--;
      for(int j=0;j<k;j++){
          cin>>v;
          v--;
          g[u].push_back(v);
        }
    }
    rep(i,n){
        if(!visited[i]){
            dfs(i);
        }
    }
    rep(i,n){
        cout<<i+1<<" "<<d[i]<<" "<<f[i]<<endl;
    }
  return 0;
}

C++: #include<iostream>
#include<stdio.h>

#define N 100
#define WHITE 0
#define GRAY 1
#define BLACK 2

int n;
int M[N][N];
int color[N];
int d[N];
int f[N];
int tt;

//再帰関数によるDFS
void dfs_visit(int u)
{
    int v;
    color[u]=GRAY;
    d[u]=++tt;//最初の訪問

    for(v=0;v<n;v++)
    {
        if(M[u][v]==0) continue;
        if(color[v]==WHITE)
        {
            dfs_visit(v);
        }
    }

    //探索終了の記録
    //再帰初期のuほど遅く探索が終了する
    color[u]=BLACK;
    f[u]=++tt;
}

void dfs()
{
    int u;
    //初期化
    for(u=0;u<n;u++) color[u]=WHITE;
    tt=0;

    for(u=0;u<n;u++)
    {
        //未訪問のuを始点としてとしてDFS
        if(color[u]==WHITE) dfs_visit(u);
    }
    for(u=0;u<n;u++)
    {
        printf("%d %d %d\n",u+1,d[u],f[u]);
    }
}


int main()
{
    int u,v,k,i,j;

    scanf("%d",&n);
    for(i=0;i<n;i++)
    {
        for(j=0;j<n;j++)M[i][j]==0;
    }

    for(i=0;i<n;i++)
    {
        scanf("%d %d",&u,&k);
        u--;
        for(j=0;j<k;j++)
        {
            scanf("%d",&v);
            v--;
            M[u][v]=1;
        }
    }

    dfs();
    return 0;
}

C++: /**
 * Depth first search.
 * start from node 1
 * 1) increment time 
 * 2) find non visited adjacent node
 * 3) if found move to that node.  d[v'] = time
 * 4) if not found. f[v] = time
 * 5) else end.
 * 5) go to 2.
 */

#include <iostream>
using namespace std;
const int N = 101;
int adj[N][N] = {0};
int d[N]={0};
int f[N]={0};
int t = 1;

void dfs(int n) {
	d[n]=t;
	int k = adj[n][0];
	for (int j=1;j<=k;j++) {
		int nn = adj[n][j];
		if (d[nn]) continue;
		t++;
		dfs(nn);
	}
	f[n]=++t;
}

int main()
{
	int n;
	cin >> n;
	for (int i=1;i<=n;i++){
		int j, k;
		cin >> j >> k;
		adj[j][0]=k;
		for (int m=1;m<=k;m++) {
			int a;
			cin >> a;
			adj[j][m]=a;
		}
	}
	dfs(1);

	for (int i=1;i<=n;i++){
		cout << i << ' ' << d[i] << ' ' << f[i] << endl;
	}

	return 0;
}