Go: package main

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

type vertexId int

type vertex struct {
	id vertexId
	firstVisitAt int
	finishVisitAt int
	adjs []vertexId
}

func createVertex(id int, adjsInt []int) vertex {
	adjs := make([]vertexId, len(adjsInt))
	for i := 0; i < len(adjs); i++ {
		adjs[i] = vertexId(adjsInt[i])
	}
	return vertex{
		id: vertexId(id),
		firstVisitAt: 0,
		finishVisitAt: 0,
		adjs: adjs,
	}
}

func (v *vertex) doesAllAdjsVisited(vertices []vertex) bool {
	for _, vId := range v.adjs {
		adj := vertices[vId-1]
		if !adj.isVisited() {
			return false
		}
	}
	return true
}

func (v *vertex) isFirstVisit() bool {
	return v.firstVisitAt == 0
}

func (v *vertex) isVisited() bool {
	return v.firstVisitAt > 0
}

func (v *vertex) nextVertex(vertices []vertex) (vertexId, error) {
	for _, vId := range v.adjs {
		adj := vertices[vId-1]
		if !adj.isVisited() {
			return vId, nil
		}
	}
	return vertexId(-1), fmt.Errorf("illegal")
}

func dfs(currentId vertexId, timestamp int, vertices []vertex) int {
	timestamp = timestamp + 1
	currentVertex := &vertices[currentId-1]
	if currentVertex.isFirstVisit() {
		currentVertex.firstVisitAt = timestamp
	}
	for !currentVertex.doesAllAdjsVisited(vertices) {
		nextVertexId, _ := currentVertex.nextVertex(vertices)
		timestamp = dfs(nextVertexId, timestamp, vertices)
	}
	timestamp = timestamp + 1
	currentVertex.finishVisitAt = timestamp
	return timestamp
}

func main() {
	sc := bufio.NewScanner(os.Stdin)
	sc.Split(bufio.ScanWords)

	n, err := nextInt(sc)
	if err != nil {
		panic(err)
	}

	vertices := make([]vertex, n)
	for i := 0; i < n; i++ {
		id, err := nextInt(sc)
		if err != nil {
			panic(err)
		}
		adjN, err := nextInt(sc)
		if err != nil {
			panic(err)
		}
		adjs := make([]int, adjN)
		for j := 0; j < adjN; j++ {
			adjId, err := nextInt(sc)
			if err != nil {
				panic(err)
			}
			adjs[j] = adjId
		}
		vertices[i] = createVertex(id, adjs)
	}

	dfs(vertexId(1), 0, vertices)

	for i := 0; i < n; i++ {
		fmt.Printf("%d %d %d\n", vertices[i].id, vertices[i].firstVisitAt, vertices[i].finishVisitAt)
	}
}

func nextText(sc *bufio.Scanner) string {
	sc.Scan()
	return sc.Text()
}

func nextInt(sc *bufio.Scanner) (int, error) {
	return strconv.Atoi(nextText(sc))
}

C++: #include <bits/stdc++.h>
#define REP(i,n) for (int i = 0; i <(n); ++i)
#define ALL(v) v.begin(), v.end()
using namespace std;
//using ll = long long;
//using P = pair<int,int>;
//static const double PI = acos(-1);


//---------------------------//
//DFS 再帰関数を利用


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;

void dfs_visit(int u){
  //cout << "u: " << u << endl; //来訪地点のチェック
  color[u] = GRAY;
  d[u] = ++tt;  //最初に訪れたときの処理
  REP(v,n){
    if(M[u][v] == 0) continue;
    //cout << "v: " << v << endl; // 次に向かう点をチェック
    if(color[v] == WHITE) {
      dfs_visit(v); //再帰
    }
  }
  color[u] = BLACK;
  f[u] = ++tt;  //最後に訪れたときの処理

}


void dfs(){
  //int u;
  // 初期化
  REP(u,n) color[u] = WHITE;
  tt = 0;
  //
  REP(u,n) {
    if( color[u] == WHITE) dfs_visit(u); //再帰関数に
  }
  REP(u,n){
    cout << u+1 << " " << d[u] << " " << f[u] << endl;
    //cout << color[u] << endl;
  }


}


int main(){
  int u,k,v;
  cin >> n;
  //隣接行列の初期化
  REP(i,n) REP(j,n) M[i][j] = 0;


  //隣接行列の作製
  REP(i,n){
    cin >> u >> k;
    --u;
    REP(j,k){
      cin >> v;
      --v;
      M[u][v] = 1;
    }

  }
  //dfs
  dfs();


  //隣接行列のoutput(確認用)
  //REP(i,n) {REP(j,n) cout << M[i][j];cout << endl;}



  return 0;
}

C++: #include<iostream>
#include<stack>
const int N = 100;
using namespace std;
int n,M[N][N];
int color[N],nt[N],d[N],f[N],start;
int next(int u){
	for(int i=nt[u];i<n;i++){
        nt[u] = i+ 1;
        if(M[u][i]) return i;
    }
	return -1;
}
void dfs_visit(int u){
    for(int i=0;i<n;i++) nt[i] = 0;
    stack<int> s;
	s.push(u);
	color[u] = 1;
	d[u] = ++start;
	while(!s.empty()){
		int x = s.top();
		int v = next(x);
		if(v!=-1){
			if(!color[v]){
				s.push(v);
				d[v] = ++start;
				color[v] = 1;
			}
		}else{
			s.pop();
            color[x] = 1;
			f[x] = ++start;
		}
	}
}
void dfs(){
	start = 0;
	for(int i=0;i<n;i++)
            if(!color[i])
	            dfs_visit(i);
	for(int i=0;i<n;i++)
		printf("%d %d %d\n",i+1,d[i],f[i]);
}
int main(){
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		int u,k,v;
		scanf("%d%d",&u,&k);
		while(k--){
			scanf("%d",&v);
			M[u-1][v-1] = 1;
		}
	}
	dfs();
	return 0;
}

C++: #include <stdio.h>
#define REP(i,n) for(int i=0;i<n;i++)
#define N 100
#define WHITE 0
#define GRAY 1
#define BLACK 2
int n,M[N][N]={0};
int color[N]={WHITE},D[N],F[N],tt=0;
void DFS_VISIT(int u){
  int v;
  color[u]=GRAY;
  D[u]=++tt;
  REP(v,n){
    if(M[u][v]==0) continue;
    if(color[v]==WHITE) DFS_VISIT(v);
  }
  color[u]=BLACK;
  F[u]=++tt;
}
void DFS(){
  int u;
  REP(u,n) if(color[u]==WHITE) DFS_VISIT(u);
  REP(u,n) printf("%d %d %d\n",u+1,D[u],F[u]);
}
int main(){
  int u,v,k;
  scanf("%d",&n);
  REP(i,n){
    scanf("%d %d",&u,&k);
    u--;
    REP(j,k){
      scanf("%d",&v);
      M[u][--v]=1;
    }
  }
  DFS();
  return 0;
}

C++: #include <iostream>
//#include <iomanip>
//#include <string>
#include <vector>
#include <algorithm>
//#include <utility>
//#include <set>
//#include <map>
//#include <queue>
//#include <deque>
//#include <bitset>
//#include <math.h>
using namespace std ;
using ll = long long ;
//using ld = long double ;
using vll = vector<ll> ;
using vvll = vector<vll> ;
//using vc = vector<char> ;
//using vvc = vector<vc> ;
//using vb = vector<bool> ;
//using vvb = vector<vb> ;
//using pll = pair<ll,ll> ;
#define all(v) v.begin(),v.end()
//ll mod = 1000000007 ;
//long double pie = acos(-1) ;
//ll INF = 1000000000000 ;

//void yorn(bool a){if(a) cout << "Yes" << endl ; else cout << "No" << endl ;}
//void YorN(bool a){if(a) cout << "YES" << endl ; else cout << "NO" << endl ;}
//ll gcd(long long a,long long b){if(b==0) return a ; return gcd(b,a%b) ;}
//ll lcm(long long a,long long b){return a/gcd(a,b)*b ;}
//ll sa(long long a,long long b){if(a>b) return a-b ; return b-a ;}
//void fix_cout(){cout << fixed << setprecision(20) ;}
//void chmin(ll &a,ll b){if(a>b) a = b ;}

ll cnt = 1 ;

void DFS(vvll &g,vvll &ans,ll p){
	if(ans.at(p).at(0)!=-1) return ;
	ans.at(p).at(0) = cnt ;
	cnt++ ;
	for(int i=0;i<g.at(p).size();i++){
		DFS(g,ans,g.at(p).at(i)) ;
	}
	ans.at(p).at(1) = cnt ;
	cnt++ ;
}

int main(){
	ll n ; cin >> n ;
	vvll g(n,vll(0)) ;
	for(int i=0;i<n;i++){
		ll a,b ;
		cin >> a >> b ;
		vll c(b) ;
		for(int j=0;j<b;j++) cin >> c.at(j) ;
		sort(all(c)) ;
		for(int j=0;j<b;j++) g.at(i).emplace_back(c.at(j)-1) ;
	}
	vvll ans(n,vll(2,-1)) ;
	for(int i=0;i<n;i++){
		if(ans.at(i).at(0)==-1) DFS(g,ans,i) ;
	}
	for(int i=0;i<n;i++) cout << i+1 << " " << ans.at(i).at(0) << " " << ans.at(i).at(1) << "\n" ;
}

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

vector<int> G[100];
pair<int, int> T[100];
const int Inf = 10000*100000+100;
int timer = 1;

int main() {
  void dfs(int cur);
  int n;
  cin >> n;
  for (int i = 0; i < n; i++)
  {
    int u, k;
    cin >> u >> k;
    for (int l = 0; l < k; l++) {
      int v;
      cin >> v;
      G[i].push_back(v - 1);
    }
    T[i] = make_pair(Inf, Inf);
  }
  for (int i = 0; i < n; i++) {
    if (T[i].first == Inf) {
      dfs(i);
    }
  }
  for (int i = 0; i < n; i++)
  {
    cout << i + 1 << " " << T[i].first << " " << T[i].second << endl;
  }
}

void dfs(int cur) { // cur を訪問
  // cur の訪問時刻を記録
  T[cur].first = timer;
  timer += 1;
  // 動作確認用表示
  for (int dst : G[cur]) { // 全ての節点 dst について
    if (T[dst].first == Inf)
    { // cur から dst に辺があり，dst を未訪問なら
      dfs(dst);
    }
  }
  T[cur].second = timer;
  timer += 1;
}