Go: package main

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

// repr state of visited node
// WHITE yet visit
// GEAY  visiting
// BLACK visited
const (
	WHITE int = iota
	GRAY
	BLACK
)

type dfsGraph struct {
	g      [][]int
	colors []int
	stime  []int // Start time of visiting node
	ftime  []int // Finish time of visiting node
}

var time int

func makeAdjList() [][]int {
	var n int
	fmt.Scanf("%d", &n)

	adj := make([][]int, n)
	for i := 0; i < n; i++ {
		adj[i] = make([]int, n)
	}

	sc := bufio.NewScanner(os.Stdin)
	for i := 0; i < n; i++ {
		sc.Scan()
		nodeInfo := strings.Split(sc.Text(), " ")
		outDegree, _ := strconv.Atoi(nodeInfo[1])

		if outDegree > 0 {
			for k := 0; k < outDegree; k++ {
				j, _ := strconv.Atoi(nodeInfo[k+2])
				j-- // convert 1 based to 0 based
				adj[i][j] = 1
			}
		}
	}

	return adj
}

func (dg dfsGraph) dfsVisit(u int) {
	// 頂点uを訪問中に設定
	dg.colors[u] = GRAY
	time++
	dg.stime[u] = time

	// uの隣接nodeを訪問
	for v := 0; v < len(dg.g); v++ {
		if dg.g[u][v] == 0 {
			continue // 辺がなければスキップ
		}

		// vが未訪問なら訪問
		if dg.colors[v] == WHITE {
			dg.dfsVisit(v)
		}
	}

	// 頂点uを訪問済みに設定
	dg.colors[u] = BLACK
	time++
	dg.ftime[u] = time
}

func (dg dfsGraph) dfs() {
	for i := 0; i < len(dg.g); i++ {
		if dg.colors[i] == WHITE {
			dg.dfsVisit(i)
		}
	}
}

func (dg dfsGraph) printDfsTime() {
	for i := 0; i < len(dg.g); i++ {
		fmt.Printf("%d %d %d\n", i+1, dg.stime[i], dg.ftime[i])
	}
}

func main() {
	adj := makeAdjList()
	colors := make([]int, len(adj))
	stime := make([]int, len(adj))
	ftime := make([]int, len(adj))
	graph := dfsGraph{adj, colors, stime, ftime}
	graph.dfs()
	graph.printDfsTime()
}

C++: #include <iostream>
#include <stack>
#include <algorithm>
#include <cmath>
using namespace std;

int M[101][101], cond[101], st[101], en[101], n, t;
stack<int> S;

void setAdj()
{
	int u, k, v;
	for (int i = 0; i < n; i++) {
		cin >> u >> k;
		for (int j = 0; j < k; j++) {
			cin >> v;
			M[u][v] = 1;
		}
	}
}

void dfs(int x)
{
	S.push(x);
	cond[x] = -1; //?¨???????
	st[x] = ++t;

	int i, j;
	while (!S.empty()) {
		int u = S.top();
		for (i = 1; i <= n; i++) {
			if (M[u][i] == 1 && cond[i] == 0) {
				break;
			}
		}
		if (i == n + 1) {
			cond[u] = 1;
			en[u] = ++t;
			S.pop();
		}
		else {
			S.push(i);
			cond[i] = -1;
			st[i] = ++t;	
		}
	}
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);

	cin >> n;
	t = 0;
	setAdj();
	
	for (int i = 1; i <= n; i++)
		if (cond[i] == 0) dfs(i);

	for (int i = 1; i <= n; i++) {
		cout << i << " " << st[i] << " " << en[i] << endl;
	}
	return 0;
}

C++: #include <iostream>
#include <fstream>
#include <cassert>
#include <string.h>
#include <vector>
#include <map>
#include <stack>

enum Color
{
    kWhite,
    kGray,
    kBlack,
};

// 頂点数.
int n;

// 各頂点の隣接リスト表現.
std::map< int, std::vector<int> > adj_list;

// 各頂点の訪問状態を管理する.
std::vector<Color> c;

// 初回訪問時.
std::vector<int> d;

// 二回目訪問時.
std::vector<int> f;

void makeAdjListFromInput(int n)
{
    for (int i = 0; i < n; ++i)
    {
        int vertex;
        int degree;

        std::cin >> vertex;
        std::cin >> degree;

        assert(vertex <= n);
        assert(degree <= n);

        std::vector<int> adj_vertexes;

        for (int j = 0; j < degree; ++j)
        {
            int adj;
            std::cin >> adj;
            adj_vertexes.push_back(adj - 1);
        }

        adj_list[vertex - 1] = adj_vertexes;
    }
}

int nextVertex(int current)
{
    std::vector< int > adjs = adj_list[current];
    for (std::vector< int >::iterator it = adjs.begin(); it != adjs.end(); ++it)
    {
        if (c[(*it)] == kWhite)
            return (*it);
    }

    // 見つからなかった.
    return 0;
}

void depthFirstSearch()
{
    int counter = 0;
    std::stack<int> tmp_stack;

    // 諸々初期化.
    for (int i = 0; i < n; ++i)
    {
        c.push_back(kWhite);
        d.push_back(0);
        f.push_back(0);
    }

    // 最初の頂点を積む.
    int first = adj_list.begin()->first;
    tmp_stack.push(first);
    c[first] = kGray;
    d[first] = ++counter;

    while (! tmp_stack.empty())
    {
        int current = tmp_stack.top();
        int next = nextVertex(current);
        if (next)
        {
            tmp_stack.push(next);
            c[next] = kGray;
            d[next] = ++counter;
            
        }
        else
        {
            int pop = tmp_stack.top();
            tmp_stack.pop();
            c[pop] = kBlack;
            f[pop] = ++counter;
        }
    }
}

int main()
{
    // std::ifstream ifs("input/alds1_11_b_02.txt");
    // if (!ifs)
    //     assert(false);
    // std::cin.rdbuf(ifs.rdbuf());

    std::cin >> n;

    makeAdjListFromInput(n);

    depthFirstSearch();

    for (std::map< int, std::vector<int> >::iterator it = adj_list.begin(); it != adj_list.end(); ++it)
    {
        int v = it->first;
        std::cout << v + 1 << " " << d[v] << " " << f[v] << std::endl;
    }

    return 0;
}

C++: #include <bits/stdc++.h>
using namespace std;

#define rep(i, a, b) for (int i = (a); i < (int)(b); i++)
#define rrep(i, a, b) for (int i = (a); i >= (int)(b); i--)
#define all(x) (x).begin(), (x).end()
using i32 = int32_t;
using i64 = int64_t;
using f32 = float;
using f64 = double;
using P   = pair<int, int>;

template <class T>
bool chmin(T& a, T b) {
    if (a > b) {
        a = b;
        return true;
    } else {
        return false;
    }
}
template <class T>
bool chmax(T& a, T b) {
    if (a < b) {
        a = b;
        return true;
    } else {
        return false;
    }
}

template <class T>
void dump_vec(const vector<T>& v) {
    auto len = v.size();
    rep(i, 0, len) {
        cout << v[i] << (i == (int)len - 1 ? "\n" : " ");
    }
}

struct FastIO {
    FastIO() {
        cin.tie(0);
        ios::sync_with_stdio(false);
        cout << fixed << setprecision(20);
    }
} FASTIO;

//---------------------------------------------------------------------------------------------------

//---------------------------------------------------------------------------------------------------

vector<int> ds;
vector<int> fs;
vector<vector<int>> G;

int stamp = 0;

void dfs(int u) {
    if (ds[u] >= 0) return;
    ds[u] = ++stamp;

    for (auto& v : G[u]) {
        dfs(v);
    }
    fs[u] = ++stamp;
}

signed main() {
    int N;
    cin >> N;
    G.resize(N);
    ds.assign(N, -1);
    fs.assign(N, -1);
    rep(i, 0, N) {
        int id, k;
        cin >> id >> k;
        id--;
        rep(j, 0, k) {
            int u;
            cin >> u;
            u--;
            G[id].push_back(u);
        }
        sort(all(G[id]));
    }
    rep(i, 0, N) {
        dfs(i);
    }
    rep(i, 0, N) {
        cout << i + 1 << " " << ds[i] << " " << fs[i] << "\n";
    }
}