Go: package main

import (
	"fmt"
)

func main() {
	var n int
	fmt.Scan(&n)
	g := make([][]int, n+1)
	for i := 0; i < n; i++ {
		var u,k int
		fmt.Scan(&u)
		fmt.Scan(&k)
		g[u] = make([]int, k)
		for j := 0; j < k; j++ {
			fmt.Scan(&g[u][j])
		}
	}

	d := make([]int, n+1)
	f := make([]int, n+1)
	t := 1
	for i := 1; i <= n; i++ {
		t = dfs(&g, &d, &f, i, t)
	}

	for i := 1; i <= n; i++ {
		fmt.Printf("%d %d %d\n", i, d[i], f[i])
	}
}

func dfs(g *[][]int, d *[]int, f *[]int, id int, t int) int {
	if (*d)[id] > 0 {
		return t
	}
	(*d)[id] = t
	t += 1
	for i := 0; i < len((*g)[id]); i++ {
		t = dfs(g, d, f, (*g)[id][i], t)
	}
	(*f)[id] = t
	return t+1
}

C++: #include <map>
#include <set>
#include <list>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <vector>
#include <complex>
#include <cstdlib>
#include <cstring>
#include <numeric>
#include <utility>
#include <iostream>
#include <algorithm>
#include <functional>
#include <unordered_map>
#include <unordered_set>

using namespace std;

#define ll long long
#define ull unsigned long long
#define INF (1 << 30)
#define LLINF (1LL << 62)
#define MOD7 1000000007
#define MOD9 1000000009
#define eps 1e-9
#define P pair<int, int>
#define pii pair<int, int>
#define pll pair<ll, ll>
#define pul pair<ull, ull>
#define all(a) (a).begin(), (a).end()
#define FOR(i,a,b) for (int i=(a);i<(b);++i)
#define RFOR(i,a,b) for (int i=(b)-1;i>=(a);--i)
#define REP(i,n) for (int i=0;i<(n);++i)
#define RREP(i,n) for (int i=(n)-1;i>=0;--i)

void YES() { cout << "YES" << endl; }
void NO() { cout << "NO" << endl; }
void Yes() { cout << "Yes" << endl; }
void No() { cout << "No" << endl; }
void yes() { cout << "yes" << endl; }
void no() { cout << "no" << endl; }

template<class T>
class DirectedGraph {
public:
	class Edge {
	public:
		int to;
		T cost;

		Edge(int t, T c) : to(t), cost(c) {}

		bool operator<(const Edge& right) const {
			return cost == right.cost ? to < right.to : cost < right.cost;
		}
	};

	vector<vector<Edge>> G;
	int V;

	DirectedGraph(int n = 0) {
		resize(n);
	}

	void resize(int n) {
		V = n;
		G.resize(n);
	}

	void addEdge(int from, int to, T cost = 0) {
		int v = max(from, to);
		if (v >= V)
			resize(v + 1);
		G[from].push_back(Edge(to, cost));
	}


	int t = 1;
	vector<pii> stamp;
	vector<bool> visit;
	void dfs(int s) {
		visit.resize(V);
		stamp.resize(V);
		calcDfs(s);
	}

	void calcDfs(int s) {
		if (visit[s])
			return;

		stamp[s].first = t++;

		visit[s] = true;
		for (int i = 0; i < G[s].size(); ++i) {
			calcDfs(G[s][i].to);
		}

		stamp[s].second = t++;
	}

	vector<int> bfs() {

	}
};

int main() {
	DirectedGraph<int> g;
	int n, id, k, to;
	cin >> n;
	for (int i = 0; i < n; ++i) {
		cin >> id >> k;
		while (k--) {
			cin >> to;
			g.addEdge(id, to);
		}
	}

	for (int i = 1; i <= n; ++i)
		g.dfs(i);

	for (int i = 1; i <= n; ++i) {
		printf("%d %d %d\n", i, g.stamp[i].first, g.stamp[i].second);
	}

	return 0;
}

C++: #include<iostream>
#include<vector>
using namespace std;
int cnt=1;
void depth(vector< vector<int> > &vv,vector<int> &f,vector<int> &c,int num){
	
	f[num]=cnt;
	cnt++;
	
	for(int i=0; i<vv[num].size(); i++){
		if(vv[num][i]!=0 && f[i]==0){
			depth(vv,f,c,i);
		}
	}

	c[num]=cnt;
	cnt++;

}
int main(){
	int n;
	cin>>n;
	vector< vector<int> > v(n,vector<int> (n,0));
	vector<int> ft(n,0);
	vector<int> ct(n,0);
	int u[n];
	for(int i=0; i<n; i++){
		int k;
		cin>>u[i]>>k;
		for(int j=0; j<k; j++){
			int x;
			cin>>x;
			v[i][x-1]=1;
		}
	}
	for(int i=0; i<n; i++){
		if(ft[i]==0){
			depth(v,ft,ct,i);
		}
		cout<<u[i]<<" "<<ft[i]<<" "<<ct[i]<<endl;
	}
  return 0;
}

C++: #include<bits/stdc++.h>
#pragma GCC optimize("Ofast")
using namespace std;
typedef long long ll;
typedef pair<ll, ll> PLL;
typedef vector<int> VI;
typedef vector<char> VC;
typedef vector<double> VD;
typedef vector<string> VS;
typedef vector<ll> VLL;
typedef vector<PLL> VP;
const static int INF = 1000000000;
const static int MOD = 1000000007;
const int dx[4]={1, 0, -1, 0};
const int dy[4]={0, 1, 0, -1};
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return true; } return false; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return true; } return false; }
#define rep(i,n) for (ll i=0; i<(ll)(n); i++)
#define repd(i,n) for (ll i=n-1; i>=0; i--)
#define rept(i,m,n) for(ll i=m; i<n; i++)
#define stl_rep(itr, x) for (auto itr = x.begin(); itr != x.end(); ++itr)
#define all(x) (x).begin(), (x).end()
#define F first
#define S second
#define PF push_front
#define PB push_back
#define SORT(V) sort((V).begin(), (V).end())
#define RVERSE(V) reverse((V).begin(), (V).end())
#define paired make_pair
#define PRINT(V) for(auto v : (V)) cout << v << " "
//charを整数に
int ctoi(char c) { if (c >= '0' && c <= '9') { return c - '0'; } return 0; }
// 累積和 for (int i = 0; i < N; ++i) s[i+1] = s[i] + a[i]; 
void cum_sum(int N,vector<double> a, vector<double> &s){ for(int i=0; i<N; i++){ s[i+1]=s[i]+a[i];}}
//ユークリッドの控除法
ll gcd(ll a,ll b){
    if(b == 0) return a;
    return gcd(b,a%b);
}
//最小公倍数
ll lcm(ll a,ll b){
    ll g = gcd(a,b);
    return a / g * b; // Be careful not to overflow
}
//素数判定
bool is_prime(long long n) {
    if (n <= 1) return false;
    for (long long p = 2; p * p <= n; ++p) {
        if (n % p == 0) return false;
    }
    return true;
}
int getdigit(ll num){
    unsigned digit=0;
    while(num!=0){
        num /= 10;
        digit++;
    }
    return digit;
}
//空白文字も入力 getline(cin, S);
//桁数指定 setprecision
vector<bool> seen;
vector<int> first_order;
vector<int> last_order;

void dfs(vector<vector<int>> &G, int v, int &ptr){
    first_order[v]=ptr++;
    seen[v]=true;
    for(auto nv:G[v]){
        if(seen[nv]) continue;
        dfs(G, nv, ptr);
    }
    last_order[v]=ptr++;
}

int main()
{
    int n;
    cin >> n;
    vector<vector<int>> G(n);
    rep(i,n){
        int a,b;
        cin >> a;
        cin >> b;
        a--;
        rep(i,b){
            int c;
            cin >> c; 
            c--;
            G[a].push_back(c);
        }
    }
    seen.assign(n, false);
    first_order.resize(n);
    last_order.resize(n);
    int ptr=1;
    rep(i,n){
        if(seen[i]==false){
            dfs(G, i, ptr);
        }
    }
    for(int i=0; i<n; i++){
       cout << i+1 << " " << first_order[i] << " " << last_order[i] << endl;
    }
}

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

static const int N=100;
static const int WHITE=0;
static const int GRAY=1;
static const int BLACK=2;

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

// uに隣接するvを番号順に取得
int next(int u){
    for(int v=0; v<n; v++){ // 訪問した場所は探索しなくていいため、v+1にしている？
        nt[u] = v+1;
        if(M[u][v]) return v;
    }
    return -1;
}

// スタックを用いた深さ優先探索
void dfs_visit(int r){
    for(int i=0; i<n; i++) nt[i] = 0;

    stack<int> S;
    S.push(r);
    color[r] = GRAY;
    d[r] = ++tt;

    while(!S.empty()){
        int u=S.top();
        int v=next(u);
        if(v!=-1){
            if(color[v] == WHITE){
                color[v] = GRAY;
                d[v] = ++tt;
                S.push(v);
            }
        }
        else{
            S.pop();
            color[u] = BLACK;
            f[u] = ++tt;
        }
    }
}

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

    // 未訪問のuを始点として深さ優先探索
    for(int u=0; u<n; u++){
        if(color[u] == WHITE) dfs_visit(u);
    }
    for(int i=0; i<n; i++){
        cout << i+1 << " " << d[i] << " " << f[i] <<endl; 
    }
}

int main(int argc, char const *argv[])
{
    int u, k, v;

    cin >> n;
    for(int i=0; i<n; i++){
        for(int j=0; j<n; j++) M[i][j] = 0;
    }

    for(int i=0; i<n; i++){
        cin >> u >> k;
        u--; // 0 origin
        for(int j=0; j<k; j++){
            cin >> v;
            v--;
            M[u][v] = 1;
        }
    }

    dfs();

    return 0;
}