Go: package main

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

func getScanner(fp *os.File) *bufio.Scanner {
	scanner := bufio.NewScanner(fp)
	scanner.Split(bufio.ScanWords)
	scanner.Buffer(make([]byte, 1000005), 1000005)
	return scanner
}

func getNextString(scanner *bufio.Scanner) string {
	scanner.Scan()
	return scanner.Text()
}

func getNextInt(scanner *bufio.Scanner) int {
	i, _ := strconv.Atoi(getNextString(scanner))
	return i
}

func getNextInt64(scanner *bufio.Scanner) int64 {
	i, _ := strconv.ParseInt(getNextString(scanner), 10, 64)
	return i
}

func getNextUint64(scanner *bufio.Scanner) uint64 {
	i, _ := strconv.ParseUint(getNextString(scanner), 10, 64)
	return i
}

func getNextFloat64(scanner *bufio.Scanner) float64 {
	i, _ := strconv.ParseFloat(getNextString(scanner), 64)
	return i
}

func main() {
	fp := os.Stdin
	wfp := os.Stdout
	cnt := 0

	if os.Getenv("MASPY") == "ますピ" {
		fp, _ = os.Open(os.Getenv("BEET_THE_HARMONY_OF_PERFECT"))
		cnt = 1
	}
	if os.Getenv("MASPYPY") == "ますピッピ" {
		wfp, _ = os.Create(os.Getenv("NGTKANA_IS_GENIUS10"))
	}

	scanner := getScanner(fp)
	writer := bufio.NewWriter(wfp)
	solve(scanner, writer)
	for i := 0; i < cnt; i++ {
		fmt.Fprintln(writer, "-----------------------------------")
		solve(scanner, writer)
	}
	writer.Flush()
}

func solve(scanner *bufio.Scanner, writer *bufio.Writer) {
	n := getNextInt(scanner)
	g := graph{}
	g.ee = make([]Edges, n)
	g.visited = make([]bool, n)
	g.found = make([]int, n)
	g.leave = make([]int, n)
	for i := 0; i < n; i++ {
		u := getNextInt(scanner) - 1
		k := getNextInt(scanner)
		for j := 0; j < k; j++ {
			v := getNextInt(scanner) - 1
			g.ee[u] = append(g.ee[u], Edge{
				to: v,
				id: u,
			})
		}
	}
	for i := 0; i < n; i++ {
		sort.Sort(g.ee[i])
	}
	for i := 0; i < n; i++ {
		if g.visited[i] {
			continue
		}
		g.dfs(i)
	}

	for i := 0; i < n; i++ {
		fmt.Fprintln(writer, fmt.Sprintf("%d %d %d", i+1, g.found[i], g.leave[i]))
	}
}

// Edge ...
type Edge struct {
	to, id int
}

type Edges []Edge

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

type graph struct {
	ee           []Edges
	t            int
	n            int
	visited      []bool
	found, leave []int
}

func (g *graph) dfs(i int) {
	g.visited[i] = true
	g.t++
	g.found[i] = g.t
	for _, e := range g.ee[i] {
		if g.visited[e.to] {
			continue
		}
		g.dfs(e.to)
	}
	g.t++
	g.leave[i] = g.t
}

C++: #include <algorithm>
#include <bitset>
#include <cassert>
#include <cmath>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <string>
#include <vector>

// Acknowledgement: Special thanks to kyomukyomupurin, who developed this
// template.
template <class T, class U>
std::ostream& operator<<(std::ostream& os, const std::pair<T, U>& p) {
  return os << '(' << p.first << ", " << p.second << ')';
}

template <class T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& vec) {
  int n = 0;
  for (auto e : vec) os << (n++ ? ", " : "{") << e;
  return os << (n ? "}" : "{}");
}

template <class T>
std::ostream& operator<<(std::ostream& os, const std::set<T>& st) {
  int n = 0;
  for (auto e : st) os << (n++ ? ", " : "{") << e;
  return os << (n ? "}" : "{}");
}

template <class T, class U>
std::ostream& operator<<(std::ostream& os, const std::map<T, U>& mp) {
  int n = 0;
  for (auto e : mp) os << (n++ ? ", " : "{") << e;
  return os << (n ? "}" : "{}");
}

template <class T>
std::istream& operator>>(std::istream& is, std::vector<T>& vec) {
  for (T& e : vec) is >> e;
  return is;
}

#ifdef LOCAL
#define debug(...) \
  std::cerr << "[" << #__VA_ARGS__ << "]: ", debug_out(__VA_ARGS__)
#else
#define debug(...)
#endif

void debug_out() { std::cerr << '\n'; }

template <class Head, class... Tail>
void debug_out(Head&& head, Tail&&... tail) {
  std::cerr << head;
  if (sizeof...(Tail) != 0) std::cerr << ", ";
  debug_out(std::forward<Tail>(tail)...);
}
using namespace std;
using int64 = long long;

void dfs(int start_node_id, vector<vector<int>>& g, vector<int>& visit_status,
         vector<int>& first_visit, vector<int>& last_visit, int& time) {
  visit_status[start_node_id] = 1;
  first_visit[start_node_id] = ++time;
  for (int i = 0; i < (int)g[start_node_id].size(); i++) {
    int node_id = g[start_node_id][i];
    if (visit_status[node_id] == 0) {
      dfs(node_id, g, visit_status, first_visit, last_visit, time);
    }
  }
  visit_status[start_node_id] = 2;
  last_visit[start_node_id] = ++time;
}

int main() {
  int n, k, u, v;
  cin >> n;
  vector<vector<int>> g(n);
  for (int i = 0; i < n; i++) {
    cin >> u >> k;
    for (int j = 0; j < k; j++) {
      cin >> v;
      g[i].push_back(v - 1);
      // g[v - 1].push_back(i);
    }
  }
  debug(g);
  vector<int> visit_status(n), first_visit(n), last_visit(n);
  int time = 0;
  for (int i = 0; i < n; i++) {
    if (visit_status[i] == 0) {
      dfs(i, g, visit_status, first_visit, last_visit, time);
    }
  }
  for (int i = 0; i < n; i++) {
    cout << i + 1 << ' ' << first_visit[i] << ' ' << last_visit[i] << endl;
  }
  return 0;
}

C++: #include <stdio.h>
#include <iostream>
using namespace std;

class Adjl{
private:
	int u;
	int k;
	Adjl **next;
protected:
	int d;
	int f;
public:
	Adjl(int u);
	~Adjl(){ if (next != NULL) delete[] next; }
	void setV(int k, Adjl *vk);
	int depthFirstSearch(int time);
	void print();
};

Adjl::Adjl(int u)
{
	this->u = u;
	k = 0;
	next = NULL;
	d = 0;
	f = 0;
}

void Adjl::setV(int k, Adjl *vk)
{
	if (this->k == 0) next = new Adjl*[k];
	next[this->k] = vk;
	(this->k)++;
}

int Adjl::depthFirstSearch(int time)
{
	time++;
	d = time;
	for (int i = 0; i < k; i++) {
		if (next[i]->d == 0) {
			time = next[i]->depthFirstSearch(time);
		}
	}
	time++;
	f = time;
	return time;
}

void Adjl::print()
{
	cout << u << " " << d << " " << f << endl;
}

int main(void)
{
	int n;
	cin >> n;
	
	Adjl **adjl = new Adjl*[n];
	int check[100] = {0};

	for (int i = 0; i < n; i++) {
		int u, k;
		cin >> u >> k;
		if (check[i] == 0) {
			adjl[i] = new Adjl(u);
			check[i] = 1;
		}
		check[i] = 1;
		for (int j = 0; j < k; j++) {
			int vk;
			cin >> vk;
			if (check[vk - 1] == 0) {
				adjl[vk - 1] = new Adjl(vk);
				check[vk - 1] = 1;
			}
			adjl[i]->setV(k, adjl[vk - 1]);
		}
	}

	adjl[0]->depthFirstSearch(0);

	for (int i = 0; i < n; i++) {
		adjl[i]->print();
	}

	delete[] adjl;
	return 0;
}

C++: #if 0

#endif

#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;

vector<int> E[110];
int N;
int D[110], F[110];

int tim = 0;
void dfs(int cur) {
  tim += 1;
  D[cur] = tim;
  for (auto it = E[cur].begin(); it != E[cur].end(); ++it) {
    if (D[*it] == 0) {
      dfs(*it);
    }
  }
  tim += 1;
  F[cur] = tim;
}

int main() {
  cin >> N;
  int c, k;
  for (int i = 1; i <= N; i++) {
    cin >> c >> k;
    int t;
    for (int j = 0; j < k; j++) {
      cin >> t; E[i].push_back(t);
    }
  }
  for (int i = 1; i <= N; i++) {
    D[i] = 0; F[i] = 0;
  }
  for (int i = 1; i <= N; i++) {
    if (D[i] == 0)
      dfs(i);
  }
  for (int i = 1; i <= N; i++)
    cout << i << ' ' << D[i] << ' ' << F[i] << endl;
}

C++: #include<bits/stdc++.h>

using namespace std;
#define fordebug int hoge;cin>>hoge;
#define DEKAI 1000000007
#define INF (1<<28)
#define lp(i,n) for(int i=0;i<n;i++)
#define lps(i,j,n) for(int i=j;i<n;i++)
#define floot10 cout<<fixed<<setprecision(10);
#define int long long
vector<int> v[200];
int n,t=1;
int d[200],f[200],done[200];

void dfs(int now){
	//cout<<now<<endl;
	d[now]=t;
	t++;
	done[now]=1;
	lp(i,v[now].size()){
		if(done[v[now][i]]==1) continue;
		dfs(v[now][i]);
	}
	f[now]=t;
	t++;
}

signed main(){
	cin>>n;
	lp(z,n){
		int i,c;
		cin>>i>>c;
		lp(j,c){
			int hoge;
			cin>>hoge;
			v[i].push_back(hoge);
		}
	}
	lps(i,1,n+1){
		if(done[i]==0)
			dfs(i);
	}
	lps(i,1,1+n){
		cout<<i<<" "<<d[i]<<" "<<f[i]<<endl;
	}
	return 0;
}