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) isVisited() bool {
	return v.firstVisitAt > 0
}

func dfs(currentId vertexId, timestamp int, vertices []vertex) int {
	currentVertex := &vertices[currentId-1]
	if currentVertex.isVisited() {
		return timestamp
	}
	timestamp = timestamp + 1
	currentVertex.firstVisitAt = timestamp
	for _, adjId := range currentVertex.adjs {
		timestamp = dfs(adjId, timestamp, vertices)
	}
	timestamp = timestamp + 1
	currentVertex.finishVisitAt = timestamp
	return timestamp
}

func solveDfs(vertices []vertex) {
	timestamp := 0
	for {
		vid := vertexId(-1)
		for i := 0; i < len(vertices); i++ {
			if !vertices[i].isVisited() {
				vid = vertexId(i+1)
				break
			}
		}
		if vid > 0 {
			timestamp = dfs(vid, timestamp, vertices)
		} else {
			break
		}
	}
}

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)
	}

	solveDfs(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<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];

int next(int u){
  for(int v=nt[u];v<n;v++){
    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;
  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 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--;
    for(int j=0;j<k;j++){
      cin>>v;
      v--;
      M[u][v]=1;
    }
  }
  dfs();
  return 0;
}

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

const long N = 100;
const long WHITE = 0;
const long GRAY = 1;
const long BLACK = 2;

long n, M[N + 1][N + 1];
long color[N + 1], d[N + 1], f[N + 1], tt;
long nt[N + 1];

long next(long u){
	for (long v = nt[u]; v < n; v++){
		nt[u] = v + 1;
		if (M[u][v]) return v;
	}
	return -1;
}

void dfs_visit(long r){
	for (long i = 1; i <= n; i++) nt[i] = 0;

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

	while (!S.empty()){
		long u = S.top();
		long 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 (long i = 1; i <= n; i++){
		color[i] = WHITE;
		nt[i] = 0;
	}
	tt = 0;

	for (long u = 1; u <= n; u++){
		if (color[u] == WHITE) dfs_visit(u);
	}
	for (long i = 1; i <= n; i++){
		cout << i + 1 << " " << d[i] << " " << f[i] << endl;
	}
}

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

	for (long i = 1; i <= n; i++){
		cin >> u >> k;
		for (long j = 1; j <= n; j++){
			cin >> v;
			M[u][v] = 1;
		}
	}

	dfs();

	return 0;
}

C++: #include<bits/stdc++.h>
#define ll long long
#define rep(i, n) for(int i=0;i<(n);++i)
#define per(i, n) for(int i=(n)-1;i>=0;--i)
#define repa(i, n) for(int i=1;i<(n);++i)
#define foreach(i, n) for(auto &i:(n))
#define pii pair<int, int>
#define pll pair<long long, long long>
#define all(x) (x).begin(), (x).end()
#define bit(x) (1ll << (x))
const ll MOD = (ll)1e9+7;
const int INF = (ll)1e9+7;
const ll INFLL = (ll)1e18;
using namespace std;
template<class t>
using vvector = vector<vector<t>>;
template<class t>
using vvvector = vector<vector<vector<t>>>;
template<class t>
using priority_queuer = priority_queue<t, vector<t>, greater<t>>;
template<class t, class u> bool chmax(t &a, u b){if(a<b){a=b;return true;}return false;}
template<class t, class u> bool chmin(t &a, u b){if(a>b){a=b;return true;}return false;}

ll modpow(ll x, ll b){
	ll res = 1;
	while(b){
		if(b&1)res = res * x % MOD;
		x = x * x % MOD;
		b>>=1;
	}
	return res;
}

ll modinv(ll x){
	return modpow(x, MOD-2);
}

bool was_output = false;
template<class t>
void output(t a){
	if(was_output)cout << " ";
	cout << a;
	was_output = true;
}
void outendl(){
	was_output = false;
	cout << endl;
}

vvector<int> edges;
vector<int> found_time;
vector<int> finish_time;

int dfs(int place, int time){
	++time;
	found_time[place] = time;
	foreach(i, edges[place]){
		if(found_time[i]>=0)continue;
		time = dfs(i, time);
	}
	++time;
	finish_time[place] = time;
	return time;
}

int main(){
	int n;
	cin >> n;
	edges.resize(n);
	found_time.resize(n, -1);
	finish_time.resize(n, -1);
	rep(i, n){
		int t;
		int time;
		cin >> t >> time;
		--t;
		rep(j, time){
			int to;
			cin >> to;
			--to;
			edges[t].push_back(to);
		}
	}
	int time = 0;
	rep(i, n){
		if(found_time[i]<0)time = dfs(i, time);
	}
	rep(i, n){
		output(i+1);
		output(found_time[i]);
		output(finish_time[i]);
		outendl();
	}
	return 0;
}

C++: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define FORD(i,a,b) for(int i=a;i>=b;i--)
#define ALL(a)  (a).begin(),(a).end()
#define SZ(a) int((a).size())
#define SORT(c) sort((c).begin(),(c).end())
#define MEMSET(v, h) memset((v), h, sizeof(v))
#define sqr(x) ((x) * (x))
#define bit(n) (1LL<<(n))
#define pcnt(x) __builtin_popcountll(x)
#define PB push_back
#define MP make_pair
#define endl "\n"
using Edge = pair<int,int>;
using Graph = vector<vector<Edge>>;
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }
// ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
// ll lcm(ll a,ll b){return a/gcd(a,b)*b;}

int d[110],f[110];
int t;
bool visit[110];
vector<vector<int>> vec(110);

void dfs(int a) {
  if(!visit[a]){
    visit[a] = true;
    d[a] = ++t;
    for(auto x: vec[a]) dfs(x);
    f[a] = ++t;
  }
}

int main() {
  int n; cin >> n;
  FOR(i,0,n-1){
    int u,k,v; cin >> u >> k;
    --u;
    FOR(j,1,k){
      cin >> v;
      --v;
      vec[u].PB(v);
    }
  }
  FOR(i,0,n-1) dfs(i);
  FOR(i,0,n-1) cout << i+1 << " " << d[i] << " " << f[i] << "\n";




}