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 <iostream>
#include <stack>
using namespace std;
#define N 100
#define WHITE 0
#define GRAY 1
#define 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++: #if 0
time: 15min
using e[] as a indicator to find whether a node has been searched.						
#endif
#include <iostream>
#include <queue>

using namespace std;

int p[100+10][100+10];
int D[100+10],e[100+10],f[100+10];
int n,a,b,c,t;

void dfs(int cur){
	D[cur] = 1;
	t += 1;
	for (int i=1; i<=n; i++){
		if (p[cur][i]>0 && !D[i]){
			f[i] = t+1;
			dfs(i);
		}
	}
	t += 1;
	e[cur] = t;
}

int main(){
	cin >> n;
	for (int i=1; i<=n; i++){
		cin >> a >> b;
		for (int j=1; j<=b; j++){
			cin >> c;
			p[a][c] = 1;
		}
	}
	f[1] = 1;
	for (int i=1; i<=n; i++){
		if (!D[i]){
			f[i] = !f[i] ? t+1 : f[i];
			dfs(i);
		} 	
	}
	

	for (int i=1; i<=n; i++){
		cout << i << ' ' << f[i] << ' ' << e[i] << endl;
	}
}

C++: #include<bits/stdc++.h>
using namespace std;
#define rep(i,n) for(ll i=0;i<n;i++)
#define repl(i,l,r) for(ll i=(l);i<(r);i++)
#define per(i,n) for(ll i=n-1;i>=0;i--)
#define lper(i,r,l) for(ll i=r-1;i>=l;i--)
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define ins insert
#define all(x) (x).begin(),(x).end()
#define CST(x) cout<<fixed<<setprecision(x)
using ll=long long;
using vl=vector<ll>;
using vvl=vector<vector<ll>>;
using pl=pair<ll,ll>;
using vpl=vector<pl>;
const ll MOD=1000000007;
const ll MOD9=998244353;
const int inf=1e9+10;
const ll INF=4e18;
const ll dy[4]={1,0,-1,0};
const ll dx[4]={0,-1,0,1};
ll modfac(ll a){
    ll ans=1;
    while(a>1){
        ans*=a;
        ans%=1000000007;
        a--;
    }
    return ans;
}
ll modinv(ll a,ll m) {
    ll b = m, u = 1, v = 0;
    while (b) {
        ll t = a / b;
        a -= t * b; swap(a, b);
        u -= t * v; swap(u, v);
    }
    u %= m; 
    if (u < 0) u += m;
    return u;
}
struct UnionFind {
    vector<int> par;
    
    UnionFind(int n) : par(n, -1) {}

    int root(int x) {
        if (par[x] < 0) return x;
        else return par[x] = root(par[x]);
    }
    
    bool same(int x, int y) {
        return root(x) == root(y);
    }
    
    bool merge(int x, int y) {
        x = root(x); y = root(y);
        if (x == y) return false;
        if (par[x] > par[y]) swap(x, y);
        par[x] += par[y];
        par[y] = x;
        return true;
    }
    
    int size(int x) {
        return -par[root(x)];
    }
};
ll modpow(ll a, ll n, ll mod) {
    ll res = 1;
    while (n > 0) {
        if (n & 1) res = res * a % mod;
        a = a * a % mod;
        n >>= 1;
    }
    return res;
}
template<class T> inline bool chmin(T& a, T b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}
template<class T> inline bool chmax(T& a, T b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}
void dfs(ll v, const vvl &g,vector<bool> &seen,vl &fir,vl &last,ll &time){
    fir[v]=time++;
    seen[v]=true;
    for(auto nv:g[v]){
        if(seen[nv])continue;
        dfs(nv,g,seen,fir,last,time);
    }
    last[v]=time++;
}
int main(){
    ll n;cin >> n;
    vvl g(n);
    rep(i,n){
        ll x;cin >> x;x--;
        ll k;cin >> k;
        rep(j,k){
            ll y;cin >> y;y--;
            g[x].pb(y);
        }
    }
    vector<bool> seen(n,false);
    vl fir(n),last(n);
    ll time=1;
    ll x=0;
    while(x<n){
        dfs((ll)x,g,seen,fir,last,time);
        while(seen[x])x++;
    }
    rep(i,n)cout <<i+1<<" "<< fir[i]<< " "<<last[i] <<endl;
}

C++: // -*- mode:c++; coding:utf-8; c-basic-offset:2; -*-
// ALDS1_11_B: Depth First Search

#include <algorithm>
#include <cstdio>
#include <stack>
#include <utility>

using uint = unsigned int;

class Graph {
  const uint n_;
  uint* const g_;
  std::pair<uint, uint>* const visited_;
  
public:
  Graph(uint n) : n_(n),
                  g_(new uint[n_*n_]),
                  visited_(new std::pair<uint, uint>[n_])
  {
    init_graph();
  }

  ~Graph()
  {
    delete[] g_;
    delete[] visited_;
  }
  
  uint* operator [](uint i) const { return g_+(n_*i); }

  std::pair<uint, uint>* visited() const { return visited_; }

  void dfs()
  {
    std::stack<uint> s;
    auto time = 0u;
    init_visited();
    auto last_visited = 0u;
    s.push(0);
    visited_[0].first = time;
  outer_loop:
    while (!s.empty()) {
      auto i = s.top();
      for (auto j = last_visited+1; j < n_; ++j) {
        if ((*this)[i][j] && !visited_[j].first) {
          s.push(j);
          visited_[j].first = ++time;
          goto outer_loop;
        }
      }
      s.pop();
      visited_[i].second = ++time;
      last_visited = i;
    }
  }

private:
  void init_graph() { std::fill(g_, g_+(n_*n_), 0u); }

  void init_visited()
  {
    for (auto i = 0u; i < n_; ++i) {
      visited_[i].first = 0u;
    }
  }
};

int main()
{
  uint n;
  std::scanf("%u", &n);

  Graph g(n);

  uint u, k, v;
  for (auto i = 0u; i < n; ++i) {
    std::scanf("%u %u", &u, &k);
    for (auto j = 0u; j < k; ++j) {
      std::scanf("%u", &v);
      g[u-1][v-1] = 1;
    }
  }

  g.dfs();
  auto visited = g.visited();
  for (auto i = 0u; i < n; ++i) {
    std::printf("%u %u %u\n", i+1, visited[i].first+1, visited[i].second+1);
  }
}

// eof