Go: package main

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

// I/O
type Scanner struct {
	sc *bufio.Scanner
}

func NewScanner() *Scanner {
	sc := bufio.NewScanner(os.Stdin)
	sc.Split(bufio.ScanWords)
	sc.Buffer(make([]byte, 1024), int(1e+9))
	return &Scanner{sc}
}

func (s *Scanner) nextStr() string {
	s.sc.Scan()
	return s.sc.Text()
}

func (s *Scanner) nextInt() int {
	i, e := strconv.Atoi(s.nextStr())
	if e != nil {
		panic(e)
	}
	return i
}

func (s *Scanner) nextFloat() float64 {
	f, e := strconv.ParseFloat(s.nextStr(), 64)
	if e != nil {
		panic(e)
	}
	return f
}

func (s *Scanner) nextRuneSlice() []rune {
	return []rune(s.nextStr())
}

func (s *Scanner) nextIntSlice(n int) []int {
	res := make([]int, n)
	for i := 0; i < n; i++ {
		res[i] = s.nextInt()
	}
	return res
}

func (s *Scanner) nextFloatSlice(n int) []float64 {
	res := make([]float64, n)
	for i := 0; i < n; i++ {
		res[i] = s.nextFloat()
	}
	return res
}

// Arithmetic
func max(nums ...int) int {
	m := nums[0]
	for _, i := range nums {
		if m < i {
			m = i
		}
	}
	return m
}

func min(nums ...int) int {
	m := nums[0]
	for _, i := range nums {
		if m > i {
			m = i
		}
	}
	return m
}

func abs(x int) int {
	if x > 0 {
		return x
	}
	return -x
}

func pow(x, y int) int {
	res := 1
	for i := 0; i < y; i++ {
		res *= x
	}
	return res
}

func ceil(a, b int) int {
	if a%b == 0 {
		return a / b
	} else {
		return a/b + 1
	}
}

// Sort
type RuneSlice []rune

func (a RuneSlice) Len() int           { return len(a) }
func (a RuneSlice) Less(i, j int) bool { return a[i] < a[j] }
func (a RuneSlice) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }

// Main
func main() {
	sc := NewScanner()
	wtr := bufio.NewWriter(os.Stdout)
	N := sc.nextInt()
	G := make([][]int, N)
	for i := 0; i < N; i++ {
		u, k := sc.nextInt()-1, sc.nextInt()
		for j := 0; j < k; j++ {
			G[u] = append(G[u], sc.nextInt()-1)
		}
	}
	ans := make([][2]int, N)
	time := 0
	found := make(map[int]bool)
	var dfs func(cur int)
	dfs = func(cur int) {
		time++
		ans[cur][0] = time
		found[cur] = true
		for i := 0; i < len(G[cur]); i++ {
			next := G[cur][i]
			if !found[next] {
				dfs(G[cur][i])
			}
		}
		time++
		ans[cur][1] = time
	}
	for i := 0; i < N; i++ {
		if !found[i] {
			dfs(i)
		}
	}

	for i := 0; i < N; i++ {
		fmt.Fprint(wtr, i+1)
		for j := 0; j < 2; j++ {
			fmt.Fprint(wtr, " ")
			fmt.Fprint(wtr, ans[i][j])
		}
		fmt.Fprintln(wtr)
	}
	wtr.Flush()
}

C++: #include <iostream>
#include <cstdio>
#include <vector>
#define N 100
typedef struct SearchTime SearchTime;

struct SearchTime{
    int find = -1;
    int comp = -1;
    bool flag = false;
    void print(){
        std::cout << find << " " << comp << '\n';
    }
};

int cnt = 1;
SearchTime st[N];

void input_graph(std::vector<std::vector<int> >& Adj, int n){
    int u, k, v;
    for(int i=0; i<n; i++){
        std::cin >> u >> k;
        for(int j=0; j<k; j++){
            std::cin >> v;
            Adj[u-1].push_back(v);
        }
    }
}

void result(int n){
    for(int i=0; i<n; i++){
        std::cout << i+1 << " ";
        st[i].print();
    }
}

void DFS(std::vector<std::vector<int> >& Adj, int n){
    int i = 0;
    int j;
    int nexti;              //毎回-1する.
    std::vector<int> tmp;   //軌跡を保存
    bool newflag = false;
    //深さ優先探索
    while(cnt <= n*2){
        //下層へ探索
        //std::cout << "\nstrat\n";
        newflag = false;
        while(i != -1){
            st[i].flag = true;
            st[i].find = cnt;
            cnt++;
            //std::cout << "cnt:" << cnt-1 << '\n';
            tmp.push_back(i);
            //std::cout << "tmp.size():" << tmp.size() << '\n';
            //std::cout << "i:" << i+1 << '\n';
            //次の葉を探す
            if((int)Adj[i].size() != 0){//葉が最深でないとき
                j = 0;
                nexti = Adj[i][j]-1;
                while(st[nexti].flag){
                    j++;
                    if(j == (int)Adj[i].size()){//もし葉がすべて探索済みなら
                        st[i].comp = cnt;
                        cnt++;
                        //std::cout << "tochu\n";
                        //std::cout << "cnt:" << cnt-1 << '\n';
                        i = -1; //2つ目のwhile文抜ける
                        break;
                    }
                    nexti = Adj[i][j]-1;
                }
                if(i != -1) i = nexti;
            }
            else{//葉が最深のとき
                st[i].comp = cnt;
                cnt++;
                i = -1; //2つ目のwhile文抜ける
                //std::cout << "saishin\n";
                //std::cout << "cnt:" << cnt-1 << '\n';
                //std::cout << "tmp.size():" << tmp.size() << '\n';
                //std::cout << "i:" << i << '\n';
            }
        }
        //ここから根に向かって戻る. 未探索の葉があればそちらへ行く
        //std::cout << "\nback\n";
        tmp.pop_back();
        i = (int)tmp.back();
        tmp.pop_back();
        //std::cout << "tmp.size():" << tmp.size() << '\n';
        //std::cout << "i:" << i+1 << '\n';
        j = 0;
        nexti = Adj[i][j]-1;
        while(st[nexti].flag){
            j++;
            if(j == (int)Adj[i].size()){//現在のノードから未探索の葉がない
                if((int)tmp.size() != 0){//まだtmpに軌跡が残っていれば
                    st[i].comp = cnt;
                    cnt++;
                    //std::cout << "cnt:" << cnt-1 << '\n';
                    i = (int)tmp.back();
                    tmp.pop_back();
                    //std::cout << "tmp.size():" << tmp.size() << '\n';
                    //std::cout << "i:" << i+1 << '\n';
                    j = 0;
                    nexti = Adj[i][j]-1;
                }
                else{//残っていないなら
                    st[i].comp = cnt;
                    cnt++;      //たぶんこれで終わる
                    //std::cout << "cnt:" << cnt-1 << '\n';
                    if(cnt != n*2){//まだ未探索ノードが残ってる
                        i = 0;
                        while(st[i].flag){
                            i++;
                        }
                        newflag = true;
                    }
                    break;
                }
            }
            else{
                nexti = Adj[i][j]-1;
            }
        }
        if(!newflag){
            tmp.push_back(i);
            i = nexti;
        }
    }
}


int main(){
    int n;
    std::cin >> n;
    std::vector<std::vector<int> > Adj;
    Adj.resize(n);
    input_graph(Adj, n);
    DFS(Adj, n);
    result(n);
    return 0;
}

C++: #include <bits/stdc++.h>
using namespace std;
#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--)

int main(){
	int n;
	cin>>n;
	vector<vector<int> > A(n);//????????????????????????-1?????\???????????????
	//??\???
	REP(i,n){
		int u,k;
		cin>>u>>k;
		A[i]=vector<int>(k,0);
		REP(j,k){
			int l;
			cin>>l;
			A[i][j] = l-1;
		}
	}
	//??¢?´¢
	vector<int> s;//??????????????????????????\???
	vector<int> dis(n,0);//??????????????????????????????
	vector<int> fin(n,0);//???????????????????????????
	int time=0;
	while(find(dis.begin(),dis.end(), 0) != dis.end()){
		int saisyo = find(dis.begin(),dis.end(), 0) -  dis.begin();
		//cout<<saisyo<<endl;
		s.push_back(saisyo);//?????????0???????????????
		while(!s.empty()){
		//REP(ss,3){
			int k = s.back();//??????????????????????????????
			if(dis[k]==0){
				time++;
				dis[k]=time;
				//cout<<"dis "<<k<<" / time "<<time<<endl;
			}
			bool isfinish=true;
			for(int i: A[k]){
				//cout<<"?????????"<<i<<endl;
				bool nai = find(s.begin(),s.end(), i) == s.end();
				if(fin[i]==0 && i!=k && nai){
					s.push_back(i);
					isfinish=false;
					break;
				}
			}
			if(isfinish){
				time++;
				fin[k]=time;
				s.pop_back();
				//cout<<"fin "<<k<<" / time "<<time<<endl;
			}
		}
	}
	REP(i,n){
		cout<<i+1<<" "<<dis[i]<<" "<<fin[i]<<endl;
	}
	return 0;
}