Problem:
閉路のない連結な有向グラフが与えられる．(有向グラフが連結であるとは，これを無向グラフとした時に連結であるという事である．)
このグラフに対して一つの頂点を選んで首都
s
を定めたい．
T(v) =
"
v
から全ての点を到達可能にするために必要な「辺の反転」操作の回数の最小値"とする．
ただし，「辺の反転」とは，頂点
v, u
に関して
(v, u)
に張られていた有向辺を削除して
(u, v)
に張り直すことである．
頂点
s
が首都であるとは任意の頂点
v
に対して，
T(s) ≤ T(v)
が成立することである．
首都であるような頂点をすべて列挙して答えよ．
Input
入力は以下のような形式で
M + 1
行で与えられる．
N
M
a
1
b
1
:
a
M
b
M
1 行目には二つの整数
N, M
が与えられ，与えられるグラフは
N
頂点
M
辺であることを表す．
2 行目から
M + 1
行目にはそれぞれ二つの整数
a
i
, b
i
が与えられ，
a
i
から
b
i
に有向辺が張られていることを表す．
Constraints
1 ≤
N
≤ 10,000
0 ≤
M
≤ 100,000
0 ≤
a
i
≤
N − 1
0 ≤
b
i
≤
N − 1
a
i
≠ b
i
i ≠ j
ならば
(a
i
, b
i
) ≠ (a
j
, b
j
)
与えられるグラフは連結で閉路はない．
与えられるグラフに対して，入次数が 0 である頂点の個数は 50 以下である．
Output
以下の形式で2 行で出力せよ．
cnum
cost
c
1
c
2
. . .
c
cnum
1 行目には二つの整数
cnum
,
cost
を空白区切りで出力せよ．
2 行目には
cnum
個の整数
c
i
を空白区切りで出力せよ．
変数の意味は以下の通りである．
−
cnum
: 首都の性質を満たす頂点数
−
cost
: 首都となる頂点
v
に対する
T(v)
の値
−
c
i
: 首都の性質を満たす頂点を番号に関して昇順に並べた時，
i
番目の頂点番号
Sample Input 1
3 2
0 1
2 1
Output for the Sample Input 1
2 1
0 2
頂点 0 を首都とするときには辺 (2,1) を反転すれば，(0,1), (1,2) の辺を持つグラフができるので 1 が答え．
T(0) = 1, T(1) = 2, T(2) = 1
である．
Sample Input 2
5 4
0 1
2 1
2 3
4 3
Output for the Sample Input 2
3 2
0 2 4
Sample Input 3
5 5
0 1
1 2
3 2
3 4
4 1
Output for the Sample Input 3
2 1
0 3

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
      
#define FOR(i,a,b) for( ll i = (a); i < (ll)(b); i++ )
#define REP(i,n) FOR(i,0,n)
#define YYS(x,arr) for(auto& x:arr)
#define ALL(x) (x).begin(),(x).end()
#define SORT(x) sort( (x).begin(),(x).end() )
#define REVERSE(x) reverse( (x).begin(),(x).end() )
#define UNIQUE(x) (x).erase( unique( ALL( (x) ) ) , (x).end() )
#define PW(x) (1LL<<(x))
#define SZ(x) ((ll)(x).size())
#define SHOW(x) cout << #x << " = " << x << endl
#define SHOWA(x,n) for( int yui = 0; yui < n; yui++ ){ cout << x[yui] << " "; } cout << endl

#define pb emplace_back
#define fi first
#define se second

using namespace std;

typedef long double ld;
typedef long long int ll;
typedef pair<int,int> pi;
typedef pair<ll,ll> pl;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<bool> vb;
typedef vector<ld> vd;
typedef vector<pi> vpi;
typedef vector<pl> vpl;
typedef vector<vpl> gr;
typedef vector<vl> ml;
typedef vector<vd> md;
typedef vector<vi> mi;
     
const ll INF = (ll)1e9 + 10;
const ll INFLL = (ll)1e18 + 10;
const ld EPS = 1e-12;
const ll MOD = 1e9+7;
     
template<class T> T &chmin( T &a , const T &b ){ return a = min(a,b); }
template<class T> T &chmax( T &a , const T &b ){ return a = max(a,b); }
template<class T> inline T sq( T a ){ return a * a; }

ll in(){ long long int x; scanf( "%lld" , &x ); return x; }
char yuyushiki[1000010]; string stin(){ scanf( "%s" , yuyushiki ); return yuyushiki; }

// head

// ただの union find です。あとで実装が多少楽になるのでマージテクは使わずにパス圧縮だけ使っています。
struct Unionfind{
  vi par;
  Unionfind(){}
  Unionfind( int n ) :  par(n){
    REP( i , n ) par[i] = i;
  }
  void init( int n ){
    par.resize( n );
    REP( i , n ) par[i] = i;
  }
  int find( int x ){
    if( par[x] == x ) return x;
    return par[x] = find( par[x] );
  }
  bool unite( int x , int y ){
    x = find(x);
    y = find(y);
    if( x == y ) return false;
    par[x] = y;
    return true;
  }
  bool same( int x , int y ){
    return find(x) == find(y);
  }
} uf;

// skew heap です。遅延伝播で全ての要素に定数を加算できるようになっています。あと対応する辺の番号 id も持っています。
struct Heap{
  Heap *l, *r;
  int add, v, id;
  Heap(){}
  Heap( int v , int id ) : l(NULL) , r(NULL) , add(0) , v(v) , id(id) {}
};
void lazy( Heap *a ){
  if( a->l ) a->l->add += a->add;
  if( a->r ) a->r->add += a->add;
  a->v += a->add;
  a->add = 0;
}
Heap* meld( Heap *a , Heap *b ){
  if( !a ) return b;
  if( !b ) return a;
  if( a->v + a->add > b->v + b->add ) swap( a , b );
  lazy( a );
  a->r = meld( a->r , b );
  swap( a->l , a->r );
  return a;
}
Heap* pop( Heap *a ){
  lazy( a );
  return meld( a->l , a->r );
}
Heap pool[10000010];
int it; // pool をどこまで使ったか

struct edge{
  int from, to, cost;
  edge( int from , int to , int cost ) : from(from) , to(to) , cost(cost) {}
};

int n, m;

vector<edge> edges;

Heap* come[10010]; // （圧縮されたグラフ上で）その点に入ってくる辺をコストの小さい順に管理するヒープです。
int used[10010]; // 0 : 未処理, 1 : 処理中, 2 : 完成
int from_cost[10010]; // 作っている木においてその点に入ってくる辺の（圧縮されたグラフ上の）コストです。
int from[10010]; // 作っている木においてその点に入ってくる辺の（圧縮されたグラフ上の） from です。

int MSA( int r ){ // r を根とする最小全域有向木のコストを計算します。
  // 初期化します。
  uf.init( n );
  it = 0;
  REP( i , n ){
    used[i] = 0;
    come[i] = NULL;
  }
  used[r] = 2; // 根だけは完成しています。

  // 最初に各点に入ってくる辺をヒープに追加します。
  REP( i , edges.size() ){
    edge &e = edges[i];
    pool[it] = Heap( e.cost , i );
    come[e.to] = meld( come[e.to] , &pool[it++] );
  }

  int res = 0;
  REP( start , n ){
    if( used[start] != 0 ) continue;
    int cur = start;
    vi processing(0);
    
    while( used[cur] != 2 ){ // パスを伸ばしていきます。ここが本質です。
      used[cur] = 1; // 現在の頂点を処理中にします。
      processing.pb( cur );
      
      if( !come[cur] ) return INF; // 入ってくる辺がなかったら全域有向木は存在しません。おしまい。
      
      from[cur] = uf.find( edges[ come[cur]->id ].from ); // 今の頂点に入って来る辺のうち、一番コストが小さい辺を使います。その辺の from です。 
      from_cost[cur] = come[cur]->v + come[cur]->add; // その辺のコストです。
      come[cur] = pop( come[cur] ); // もう用済みなのでヒープからその辺を取り除きます。
      if( from[cur] == cur ) continue; // 自己ループだったら使うのをやめてやり直しです（頂点を圧縮しているので最初に自己ループがなくても途中で生成されることがあります）
      
      res += from_cost[cur]; // この辺を使うことが確定したので、コストを計上しておきます。
      
      if( used[ from[cur] ] == 1 ){ // サイクルができた場合です。
	int p = cur;
      	do { // サイクルを回ります。現在の頂点は p です。
      	  if( come[p] ) come[p]->add -= from_cost[p]; // その頂点に入ってくる辺のコストを、サイクルの前の辺のコスト分だけ減らします。
      	  if( p != cur ){
      	    uf.unite( p , cur ); // サイクルの頂点を一つの頂点に圧縮していきます。
      	    come[cur] = meld( come[cur] , come[p] ); // ヒープもマージしていきます。
      	  }
      	  p = uf.find( from[p] ); // 一つ前の頂点です。パスを伸ばしていく途中で圧縮されているかもしれないので find する必要があります。
      	} while( p != cur );
      	// 次の頂点ですが、圧縮した頂点からはじめます。unionfind で cur に圧縮されているので cur を変更する必要はありません。（unionfind でマージテクを使った場合は cur を find して、マージしたヒープの場所を古い cur から 新しい cur に移してください。）
      } else { // サイクルができなかった場合です。
	cur = from[cur]; // そのまま次の頂点に移ります。
      }
    }
    // 伸びてきたパスが根につながりました。
    for( int v : processing ){
      used[v] = 2; // 使った頂点を完成させたことにします。
    }
  }
  return res;
}

bool ind[10010];

int main(){

  n = in();
  m = in();
  REP( i , m ){
    int a = in();
    int b = in();
    ind[b] = true;
    edges.pb( a , b , 0 );
    edges.pb( b , a , 1 );
  }

  int minres = INF;
  vi ans(0);
  REP( i , n ){
    if( not ind[i] ){
      int res = MSA( i );
      if( res < minres ){
        ans = { (int)i };
        minres = res;
      } else if( res == minres ){
        ans.pb( i );
      }
    }
  }

  printf( "%lld %d\n", SZ(ans), minres );
  REP( i , SZ(ans) ){
    if( i != 0 ){
      printf( " " );
    }
    printf( "%d" , ans[i] );
  }
  printf( "\n" );
  
  return 0;
}
accuracy: 1
time_ms: 490
memory_kb: 15800
final_rank: 10

code_snippet: // AOJ #2647 The Capital
// 2025.3.20

#include <bits/stdc++.h>
using namespace std;

#define gc() getchar_unlocked()
#define pc(c) putchar_unlocked(c)

int Cin() {
	int n = 0; int c = gc();
	do n = 10*n + (c & 0xf), c = gc(); while (c >= '0');
	return n;
}

void Cout(int n) {
	char b[30];
	if (!n) pc('0');
	else {
		if (n < 0) pc('-'), n = -n;
		int i = 0; while (n) b[i++] = n % 10 + '0', n /= 10;
		while (i--) pc(b[i]);
	}
}

const int MAX = 10005;
const int INF = 1001001001;

vector<int> g[MAX], r[MAX];
int good[MAX], bp[50];
int d[50][50];

bool vis[MAX];
int N, M, G;

void solve(int s) {
    for (int i = 0; i < N; ++i) vis[i] = false;
    deque<pair<int,int>> dq;
    dq.push_back({0, s});
    while (!dq.empty()){
        auto [w, cur] = dq.front(); dq.pop_front();
        if (vis[cur]) continue;
        vis[cur] = true;
        if (good[cur] != -1) d[good[s]][good[cur]] = -w;
        for (int nx : g[cur]) dq.push_front({w, nx});
        for (int nx : r[cur]) dq.push_back({w - 1, nx});
    }
}

int D[50][50], D2[50][50], S, S2, nid[50];
int orig[50];
vector<int> cyc;

bool dfs(int u, int start) {
    if (u == 0) return false;
    if (vis[u]) return u == start;
    cyc.push_back(u);
    vis[u] = true;
    return dfs(orig[u], start);
}

int dmsp() {
    for (;;) {
        int score = 0;
        for (int i = 1; i < S; ++i) {
            pair<int,int> best = {INF, -1};
            for (int j = 0; j < S; ++j)
                if (i != j) best = min(best, {D[j][i], j});
            orig[i] = best.second;
            score += best.first;
        }
        for (int i = 1; i < S; ++i) {
            for (int j = 0; j < S; ++j) vis[j] = false;
            cyc.clear();
            if (!dfs(i, i)) continue;
            int len = cyc.size();
            cyc.push_back(cyc[0]);
            S2 = S - len + 1;
            int nidc = 0;
            for (int j = 0; j < S; ++j) {
                if (!vis[j]) nid[j] = nidc++;
                else nid[j] = -1;
            }
            for (int j = 0; j < S; ++j) {
                if (nid[j] == -1) continue;
                for (int k = 0; k < S; ++k) {
                    if (nid[k] == -1) continue;
                    D2[nid[j]][nid[k]] = D[j][k];
                }
            }
            for (int j = 0; j < S; ++j) {
                if (nid[j] == -1) continue;
                int tmp = INF;
                for (int k = 0; k < S; ++k)
                    if (nid[k] == -1) tmp = min(tmp, D[k][j]);
                D2[S2-1][nid[j]] = tmp;
            }
            int csum = 0;
            for (int j = 0; j < len; ++j) csum += D[cyc[j+1]][cyc[j]];
            for (int j = 0; j < S; ++j) {
                if (nid[j] == -1) continue;
                int tmp = INF;
                for (int k = 0; k < len; ++k) {
                    int u = cyc[k];
                    tmp = min(tmp, csum + D[j][u] - D[cyc[k+1]][u]);
                }
                D2[nid[j]][S2-1] = tmp;
            }
            S = S2;
            for (int j = 0; j < S; ++j)
                for (int k = 0; k < S; ++k) D[j][k] = D2[j][k];
            goto nxt;
        }
        return score;
    nxt:
        continue;
    }
    return -1;
}

int rod(int p, int q) {
    if (q == 0) return p;
    if (p == 0) return q;
    if (p == q) return 0;
    return p;
}

int main(){
    N = Cin(), M = Cin();
    for (int i = 0; i < M; i++){
        int a = Cin(), b = Cin();
        g[a].push_back(b);
        r[b].push_back(a);
    }
    G = 0;
    for (int i = 0; i < N; i++){
        if (r[i].empty()){
            bp[G] = i;
            good[i] = G++;
        } else good[i] = -1;
    }
    for (int i = 0; i < G; i++) solve(bp[i]);

    vector<pair<int,int>> sol;
    for (int i = 0; i < G; i++){
        for (int j = 0; j < G; j++)
            for (int k = 0; k < G; k++) D[j][k] = d[rod(j,i)][rod(k,i)];
        S = G;
        sol.push_back({bp[i], dmsp()});
    }

    int mn = INF;
    for (auto p : sol) mn = min(mn, p.second);

    vector<int> ans;
    for (auto p : sol) if (p.second == mn) ans.push_back(p.first);
    sort(ans.begin(), ans.end());

    Cout(ans.size()), pc(' '), Cout(mn), pc('\n');
    for (int i = 0; i < ans.size(); i++){
        if (i) pc(' ');
        Cout(ans[i]);
    }
    pc('\n');
    return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 6076
final_rank: 1

code_snippet: //最小全域有向木 https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_2_B
//
#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <algorithm>
#include <set>
#include <sstream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <climits>
#include <time.h>
#include <assert.h>
#include <numeric>
#include <functional>
#include <random>
#include <iterator>
#include <bitset>
#include<valarray>
#include<fstream>
#include<unordered_map>
#include<unordered_set>
#include <filesystem>
#include <optional>
//#include<compare>
//#include <ranges>
//#define AIZU
//#define ATCODER
#ifdef ATCODER

#include<atcoder/all>
using namespace atcoder;
#endif
using namespace std;
typedef long long ll;

#define FOR(i, min, max) for (int i = (min); i < (max); ++i) 
#define FORE(i, min, max) for (int i = (min); i <= (max); ++i)
#define DFOR(i,max,min) for(int i=(max);i>(min);--i)
#define DFORE(i,max,min) for(int i=(max);i>=(min);--i)
#define REP(i, n) for (int i = 0; i < (n); ++i)
#define REPE(i, n) for (int i = 0; i <= (n); ++i)
#define DREP(i, n) for (int i = (n); i >=0; --i) 
#define REPV(vec, i) for (int i = 0; i < (int)(vec.size()); ++i) 
#define V(type) vector<type> 
#define VV(type) vector<vector<type>>
#define VVV(type) vector<vector<vector<type>>>
#define VVVV(type) vector<vector<vector<vector<type>>>>
#define VVVVV(type) vector<vector<vector<vector<vector<type>>>>>
#define VI(type,i,n) V(type)(i,n)
#define VVI(type,i,j,n) VV(type)(i,VI(type,j,n))
#define VVVI(type,i,j,k,n) VVV(type)(i,VVI(type,j,k,n))
#define VVVVI(type,i,j,k,l,n) VVVV(type)(i,VVVI(type,j,k,l,n))
#define VVVVVI(type,i,j,k,l,m,n) VVVVV(type)(i,VVVVI(type,j,k,l,m,n))
#define ALL(v) v.begin(),v.end()
#define _S(VariableName) # VariableName
#define _D(var) cerr<<#var<<"="<<var<<endl;

void stop();
string CONTEST;
string PROBLEM;
int pnum;
class Answer {
public:
	char problemc;
	void answer(istream& cin, ostream& cout);
	static int static_constructor();  // 静的コンストラクタ
};

int main() {
	cin.tie(nullptr);//出力後に必ずendl or flushすれば問題ない。
	ios::sync_with_stdio(false);//scanf printfと混ぜなければ問題ない。
	Answer::static_constructor();
	Answer A;
	A.answer(cin, cout);
#ifdef _LOCAL
	stop();
#endif
	return 0;
}
////////////////////////////////////////////////////////////////////////////

int Answer::static_constructor() {
	CONTEST = "abc238";
	PROBLEM = "abc238_g";//問題に合わせて変える
	pnum = 0;//0ならすべて1,2,3ならそれぞれ
	return 0;
}
struct Edge {
	int from, to;
	ll cost;	
	Edge(int from, int to, ll c) :from(from), to(to), cost(c) {}
};
bool operator < (const Edge& e0, const Edge e1) {
	return e0.cost < e1.cost;
}
struct dsu {
public:
	dsu() : _n(0) {}
	dsu(int n) : _n(n), parent_or_size(n, -1) {}

	int merge(int a, int b) {
		assert(0 <= a && a < _n);
		assert(0 <= b && b < _n);
		int x = leader(a), y = leader(b);
		if (x == y) return x;
		if (-parent_or_size[x] < -parent_or_size[y]) std::swap(x, y);
		parent_or_size[x] += parent_or_size[y];
		parent_or_size[y] = x;
		return x;
	}

	bool same(int a, int b) {
		assert(0 <= a && a < _n);
		assert(0 <= b && b < _n);
		return leader(a) == leader(b);
	}

	int leader(int a) {
		assert(0 <= a && a < _n);
		if (parent_or_size[a] < 0) return a;
		return parent_or_size[a] = leader(parent_or_size[a]);
	}

	int size(int a) {
		assert(0 <= a && a < _n);
		return -parent_or_size[leader(a)];
	}

	std::vector<std::vector<int>> groups() {
		std::vector<int> leader_buf(_n), group_size(_n);
		for (int i = 0; i < _n; i++) {
			leader_buf[i] = leader(i);
			group_size[leader_buf[i]]++;
		}
		std::vector<std::vector<int>> result(_n);
		for (int i = 0; i < _n; i++) {
			result[i].reserve(group_size[i]);
		}
		for (int i = 0; i < _n; i++) {
			result[leader_buf[i]].push_back(i);
		}
		result.erase(
			std::remove_if(result.begin(), result.end(),
				[&](const std::vector<int>& v) { return v.empty(); }),
			result.end());
		return result;
	}

private:
	int _n;
	// root node: -1 * component size
	// otherwise: parent
	std::vector<int> parent_or_size;
};

ll chuLiuEdmonds(int V, const vector<vector<Edge>>& G, int root) {
	vector<vector<Edge>> g(V);
	REP(i, V) {
		for (auto e : G[i]) {
			g[e.to].push_back({ e.to,e.from,e.cost });
		}
	}
	if (root != -1) {
		g[root].clear();
	}
	dsu uf(V);
	vector<int> tos(V);
	vector<ll> mincost(V, LLONG_MAX);
	ll allcost = 0;
	vector<bool> isvisited(V);
	auto findmin = [&](int l) ->optional<Edge> {
		int minf = -1;
		int mint = -1;
		ll mincc = LLONG_MAX;
		for (int i = 0; i < g[l].size(); i++) {
			auto [f, t, c] = g[l][i];
			int lf = uf.leader(f);
			int lt = uf.leader(t);
			if (lf == lt)continue;
			if (c < mincc) {
				minf = lf;
				mint = lt;
				mincc = c;
			}
		}
		if (minf == -1) {
			return nullopt;
		}
		else {
			return Edge(minf, mint, mincc);
		}
		};
	auto findcycle = [&](int l) ->vector<int> {
		set<int> memo;
		int now = l;
		while (memo.find(now) == memo.end()) {
			memo.insert(now);
			now = uf.leader(tos[uf.leader(now)]);
		}
		vector<int> ret;
		for (auto p : memo) {
			ret.push_back(p);
		}
		return ret;
		};
	auto compress = [&](vector<int> cycle) {
		//leaderの変更
		for (int i = 1; i < cycle.size(); i++) {
			uf.merge(cycle[0], cycle[i]);
		}
		int l = uf.leader(cycle[0]);
		//cycle[0]の変換
		vector<Edge> c0;
		for (auto e : g[l]) {
			e.cost -= mincost[l];
			e.from = uf.leader(e.from);
			assert(e.from == l);
			e.to = uf.leader(e.to);
			if (e.to == e.from)continue;
			c0.push_back(e);
		}
		g[l] = c0;

		//edge		
		for (int i = 0; i < cycle.size(); i++) {
			int from = cycle[i];
			if (from == l)continue;
			for (auto e : g[from]) {
				e.cost -= mincost[from];
				e.from = uf.leader(e.from);
				assert(e.from == l);
				e.to = uf.leader(e.to);
				if (e.to == e.from)continue;
				g[l].push_back(e);
			}
			g[from].clear();
		}
		};
	set<int> memo;
	function<void(int)> dfs = [&](int from)->void {
		//cerr << "from:" << from << endl;
		int lf = uf.leader(from);
		auto minedge = findmin(lf);
		if (!minedge.has_value())return;
		Edge e = minedge.value();
		int lt = uf.leader(e.to);
		assert(lf != lt);
		if (memo.find(lt) != memo.end()) {
			//print(lf, lt, e.cost);
			allcost += e.cost;
			mincost[lf] = e.cost;
			isvisited[lf] = true;
			tos[lf] = lt;
			memo.insert(lf);
			auto cycle = findcycle(lt);
			compress(cycle);
			int cf = uf.leader(cycle[0]);
			isvisited[cf] = false;
			memo.erase(cf);
			dfs(cf);
		}
		else {
			//print(lf, lt, e.cost);
			allcost += e.cost;
			mincost[lf] = e.cost;
			isvisited[lf] = true;
			tos[lf] = lt;
			memo.insert(lf);
			if (!isvisited[lt])dfs(lt);
		}
		};
	for (int i = 0; i < V; i++) {
		if (isvisited[uf.leader(i)])continue;
		memo.clear();
		dfs(i);
	}

	//int cyclenum = 0;
	//int leader = 0;
	REP(i, V) {
		if (i != root && !isvisited[uf.leader(i)]) {
			return -1;
		}
	}
	//if (cyclenum == 1&&mincost[leader]!=LLONG_MAX) {
	//}
	//
	return allcost;
}
// skew heap です。遅延伝播で全ての要素に定数を加算できるようになっています。あと対応する辺の番号 id も持っています。
struct Heap {
	Heap* l, * r;
	ll add;
	ll v;
	int id;
	Heap() {}
	Heap(ll v, int id) : l(NULL), r(NULL), add(0), v(v), id(id) {}
};
void lazy(Heap* a) {
	if (a->l) a->l->add += a->add;
	if (a->r) a->r->add += a->add;
	a->v += a->add;
	a->add = 0;
}
Heap* meld(Heap* a, Heap* b) {
	if (!a) return b;
	if (!b) return a;
	if (a->v + a->add > b->v + b->add) swap(a, b);
	lazy(a);
	a->r = meld(a->r, b);
	swap(a->l, a->r);
	return a;
}
Heap* pop(Heap* a) {
	lazy(a);
	return meld(a->l, a->r);
}
Heap pool[10000010];
int it; // pool をどこまで使ったか



// ただの union find です。あとで実装が多少楽になるのでマージテクは使わずにパス圧縮だけ使っています。
struct Unionfind {
	vector<int> par;
	Unionfind() {}
	Unionfind(int n) : par(n) {
		REP(i, n) par[i] = i;
	}
	void init(int n) {
		par.resize(n);
		REP(i, n) par[i] = i;
	}
	int find(int x) {
		if (par[x] == x) return x;
		return par[x] = find(par[x]);
	}
	bool unite(int x, int y) {
		x = find(x);
		y = find(y);
		if (x == y) return false;
		par[x] = y;
		return true;
	}
	bool same(int x, int y) {
		return find(x) == find(y);
	}
};


ll MSA(int n,const vector<Edge>& edges,int r) { // r を根とする最小全域有向木のコストを計算します。
	// 初期化します。
	Unionfind uf;
	uf.init(n);
	it = 0;
	vector<Heap*> come(n,0); // （圧縮されたグラフ上で）その点に入ってくる辺をコストの小さい順に管理するヒープです。
	vector<int> used(n,0); // 0 : 未処理, 1 : 処理中, 2 : 完成
	vector<ll> from_cost(n,0); // 作っている木においてその点に入ってくる辺の（圧縮されたグラフ上の）コストです。
	vector<int> from(n,0); // 作っている木においてその点に入ってくる辺の（圧縮されたグラフ上の） from です。

	REP(i, n) {
		used[i] = 0;
		come[i] = NULL;
	}
	used[r] = 2; // 根だけは完成しています。

	// 最初に各点に入ってくる辺をヒープに追加します。
	REP(i, edges.size()) {
		const Edge& e = edges[i];
		pool[it] = Heap(e.cost, i);
		come[e.to] = meld(come[e.to], &pool[it++]);
	}

	ll res = 0;
	REP(start, n) {
		if (used[start] != 0) continue;
		int cur = start;
		vector<int> processing(0);

		while (used[cur] != 2) { // パスを伸ばしていきます。ここが本質です。
			used[cur] = 1; // 現在の頂点を処理中にします。
			processing.push_back(cur);

			if (!come[cur]) return -1; // 入ってくる辺がなかったら全域有向木は存在しません。おしまい。

			from[cur] = uf.find(edges[come[cur]->id].from); // 今の頂点に入って来る辺のうち、一番コストが小さい辺を使います。その辺の from です。 
			from_cost[cur] = come[cur]->v + come[cur]->add; // その辺のコストです。
			come[cur] = pop(come[cur]); // もう用済みなのでヒープからその辺を取り除きます。
			if (from[cur] == cur) continue; // 自己ループだったら使うのをやめてやり直しです（頂点を圧縮しているので最初に自己ループがなくても途中で生成されることがあります）

			res += from_cost[cur]; // この辺を使うことが確定したので、コストを計上しておきます。

			if (used[from[cur]] == 1) { // サイクルができた場合です。
				int p = cur;
				do { // サイクルを回ります。現在の頂点は p です。
					if (come[p]) come[p]->add -= from_cost[p]; // その頂点に入ってくる辺のコストを、サイクルの前の辺のコスト分だけ減らします。
					if (p != cur) {
						uf.unite(p, cur); // サイクルの頂点を一つの頂点に圧縮していきます。
						come[cur] = meld(come[cur], come[p]); // ヒープもマージしていきます。
					}
					p = uf.find(from[p]); // 一つ前の頂点です。パスを伸ばしていく途中で圧縮されているかもしれないので find する必要があります。
				} while (p != cur);
				// 次の頂点ですが、圧縮した頂点からはじめます。unionfind で cur に圧縮されているので cur を変更する必要はありません。（unionfind でマージテクを使った場合は cur を find して、マージしたヒープの場所を古い cur から 新しい cur に移してください。）
			}
			else { // サイクルができなかった場合です。
				cur = from[cur]; // そのまま次の頂点に移ります。
			}
		}
		// 伸びてきたパスが根につながりました。
		for (int v : processing) {
			used[v] = 2; // 使った頂点を完成させたことにします。
		}
	}
	return res;
}
////TODO https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_2_B
//void Answer::answer(istream& cin, ostream& cout) {
//	int V, E, root;
//	cin >> V >> E >> root;
//	vector<vector<Edge>> g(V);
//	for (int i = 0; i < E; ++i) {
//		int u, v;
//		cin >> u >> v;
//		ll c;
//		cin >> c;
//		
//		g[u].push_back({ u,v,c });
//	}
//	cout << chuLiuEdmonds(V, g, root) << endl;
//
//}
//TODO https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_2_B
void Answer::answer(istream& cin, ostream& cout) {
	int V, E;
	cin >> V >> E;
	vector<Edge> g;
	vector<bool> kouho(V, true);
	for (int i = 0; i < E; ++i) {
		int u, v;
		cin >> u >> v;
		kouho[v] = false;
		g.push_back({ u,v,0 });
		g.push_back({ v,u,1 });
	}
	ll ansc = LLONG_MAX;
	vector<int> ansv;
	REP(i, V) {
		if (kouho[i]) {
			ll res = MSA(V, g, i);//chuLiuEdmonds(V, g, i);
			if (res < ansc) {
				ansc = res;
				ansv = { i };
			}
			else if (res == ansc) {
				ansv.push_back(i);
			}
		}
	}
	cout << ansv.size() << " " << ansc << endl;
	for (int i = 0; i < ansv.size();i++){
		int v = ansv[i];
		cout << v;
		if (i != ansv.size() - 1) {
			cout << " ";
		}
	}
	cout << endl;

}
//////////////////////////////////////////////////////////
void stop() {

	cin.get();
}
accuracy: 1
time_ms: 530
memory_kb: 14744
final_rank: 12

code_snippet: // -*- coding: utf-8-unix -*-
// https://onlinejudge.u-aizu.ac.jp/challenges/search/titles/2647
#include <bits/stdc++.h>
using std::cin, std::cout, std::endl;
using i32 = std::int32_t;
using u32 = std::uint32_t;
using i64 = std::int64_t;
using u64 = std::uint64_t;
#define REP(i, n) for (std::int64_t i=0; i<(n); ++i)

// 木の高さを考慮しないUnionFind木
class UnionFind
{
private:
  std::vector<i32> par;
public:
  explicit UnionFind(i32 n) : par(n)
  {
    std::iota(par.begin(), par.end(), 0);
  }
  i32 leader(i32 x)
  {
    if (par[x] == x) return x;
    par[x] = leader(par[x]);
    return par[x];
  }
  void merge(i32 x, i32 y)
  {
    // 必ずyを親にする
    x = leader(x);
    y = leader(y);
    par[x] = y;
  }
  bool same(i32 x, i32 y)
  {
    return (leader(x) == leader(y));
  }
};

template<class key_type, class value_type>
class SkewHeap
{
public:
  class Node;
  using ptr_type = Node*;

  class Node
  {
    friend class SkewHeap;
  public:
    Node() = default;

  private:
    ptr_type   left;
    ptr_type   right;
    key_type   key;
    key_type   delta;
    value_type value;
  
    Node(const key_type& key, const value_type& value)
      : left(nullptr) , right(nullptr), key(key), delta(), value(value) {}

    static void _add(ptr_type a, const key_type& x)
    {
      a->delta += x;
    }
  
    static void _propagate(ptr_type a)
    {
      if (a->left  != nullptr) a->left->delta  += a->delta;
      if (a->right != nullptr) a->right->delta += a->delta;
      a->key += a->delta;
      a->delta = key_type();
    }
    static ptr_type _merge(ptr_type a, ptr_type b)
    {
      if (a == nullptr) return b;
      if (b == nullptr) return a;
      std::vector<ptr_type> nodes;
      while (a != nullptr) {
        _propagate(a);
        ptr_type tmp = a->right;
        a->right = nullptr;
        nodes.push_back(a);
        a = tmp;
      }
      while (b != nullptr) {
        _propagate(b);
        ptr_type tmp = b->right;
        b->right = nullptr;
        nodes.push_back(b);
        b = tmp;
      }
      std::sort(nodes.begin(), nodes.end(),
                [](ptr_type a, ptr_type b) {
                  return a->key < b->key;
                });
      a = nodes.back();
      nodes.pop_back();
      for (auto it=nodes.rbegin(); it!=nodes.rend(); ++it) {
        b = *it;
        b->right = b->left;
        b->left  = a;
        a = b;
      }
      return a;
    }
  };

private:
  Node *root;
  
public:
  using node_type = Node;
  using item_type = std::pair<key_type, value_type>;
  
  SkewHeap() : root(nullptr) {}
  
  void push(ptr_type memory,
            const key_type& key,
            const value_type& value)
  {
    *memory = node_type(key, value);
    root = Node::_merge(root, memory);
  }
  item_type pop()
  {
    assert(root != nullptr);
    Node::_propagate(root);
    auto retval = std::make_pair(std::move(root->key), std::move(root->value));
    root = Node::_merge(root->left, root->right);
    return retval;
  }
  void add(const key_type& x)
  {
    if (root != nullptr) {
      Node::_add(root, x);
    }
  }
  void merge(SkewHeap other)
  {
    root = Node::_merge(root, other.root);
  }
  bool empty() const
  {
    return (root == nullptr);
  }
};

struct Edge
{
  i32 from;
  i32 to;
  i32 cost;
  Edge() = default;
  Edge(i32 from, i32 to, i32 cost) : from(from), to(to), cost(cost) {}
};
struct DirectedGraph
{
  i32 num_vertices;
  std::vector<Edge> edges;
  
  DirectedGraph(i32 n) : num_vertices(n), edges() {}
  
  void add_edge(i32 from, i32 to, i32 cost)
  {
    edges.emplace_back(from, to, cost);
  }
  void add_edge(const Edge& e)
  {
    edges.push_back(e);
  }
};

// Minimum Spanning Arborescenceのコストの計算
i32 compute_MSA(const DirectedGraph& graph, i32 r)
{
  const i32 N = graph.num_vertices;
  const i32 M = graph.edges.size();

  using Heap = SkewHeap<i32, Edge>;
  std::vector<Heap> incoming_edges(2*N);
  std::vector<Heap::node_type> heap_memory(M);
  REP(i, M) {
    const auto& e = graph.edges[i];
    incoming_edges[e.to].push(&heap_memory[i], e.cost, e);
  }

  UnionFind components(2*N);
  std::vector<i32> seen(2*N, -1);
  std::vector<i32> parent(2*N, -1);
  std::vector< std::vector<i32> > children(2*N);
  std::vector<Edge> min_incoming_edges(2*N);
  i32 new_id = N;

  seen[r] = r;
  
  REP(s, N) {
    std::vector<i32> path;

    i32 u = s;
    while (seen[u] < 0) {
      seen[u] = s;
      path.push_back(u);

      i32 v = -1;
      while (!incoming_edges[u].empty()) {
        auto [cost, e] = incoming_edges[u].pop();
        if (!components.same(u, e.from)) {
          v = components.leader(e.from);
          incoming_edges[u].add(-cost);
          min_incoming_edges[u] = e;
          break;
        }
      }
      if (v == -1) {
        break;
      }
      if (seen[v] == s) {
        components.merge(v, new_id);
        while (true) {
          i32 w = path.back();
          path.pop_back();
          incoming_edges[new_id].merge(incoming_edges[w]);
          parent[w] = new_id;
          children[new_id].push_back(w);
          if (components.same(w, new_id)) {
            break;
          } else {
            components.merge(w, new_id);
          }
        }
        new_id += 1;
      }
      u = components.leader(v);
    }
  }

  std::vector<i32> root_list;
  std::vector<bool> used(2*N, false);
  REP(i, N) {
    if (i == r) continue;
    i32 s = components.leader(i);
    if (!used[s]) {
      used[s] = true;
      root_list.push_back(s);
    }
  }
  
  i32 total_cost = 0;
  while (!root_list.empty()) {
    i32 s = root_list.back();
    root_list.pop_back();
    const auto& e = min_incoming_edges[s];
    total_cost += e.cost;
    s = e.to;
    while (parent[s] >= 0) {
      for (i32 t : children[parent[s]]) {
        if (t == s) continue;
        parent[t] = -1;
        root_list.push_back(t);
      }
      s = parent[s];
    }
  }
  return total_cost;
}

int main()
{
  i32 N, M; std::cin >> N >> M;
  DirectedGraph graph(N);

  std::vector<bool> kouho(N, true);
  REP(i, M) {
    i32 a, b; cin >> a >> b;
    graph.add_edge(a, b, 0);
    graph.add_edge(b, a, 1);
    kouho[b] = false;
  }

  std::vector< std::pair<i32, i32> > results; // cost, index
  REP(i, N) {
    if (kouho[i]) {
      i32 c = compute_MSA(graph, i);
      results.emplace_back(c, i);
    }
  }
  auto [cmin, _] = *std::min_element(results.begin(), results.end());
  std::vector<i32> capitals;
  for (auto [c, i] : results) {
    if (c == cmin) capitals.push_back(i);
  }
  std::cout << capitals.size() << " " << cmin << "\n";
  i32 K = capitals.size();
  REP(i, K) {
    std::cout << capitals[i];
    if (i == (K - 1)) {
      std::cout << std::endl;
    } else {
      std::cout << " ";
    }
  }
  
  return 0;
}
accuracy: 1
time_ms: 1160
memory_kb: 14760
final_rank: 14

code_snippet: // -*- coding: utf-8-unix -*-
// https://onlinejudge.u-aizu.ac.jp/challenges/search/titles/2647
#include <bits/stdc++.h>
using std::cin, std::cout, std::endl;
using i32 = std::int32_t;
using u32 = std::uint32_t;
using i64 = std::int64_t;
using u64 = std::uint64_t;
#define REP(i, n) for (std::int64_t i=0; i<(n); ++i)

// 木の高さを考慮しないUnionFind木
class UnionFind
{
private:
  std::vector<i32> par;
public:
  explicit UnionFind(i32 n) : par(n)
  {
    std::iota(par.begin(), par.end(), 0);
  }
  i32 leader(i32 x)
  {
    if (par[x] == x) return x;
    par[x] = leader(par[x]);
    return par[x];
  }
  void merge(i32 x, i32 y)
  {
    // 必ずyを親にする
    x = leader(x);
    y = leader(y);
    par[x] = y;
  }
  bool same(i32 x, i32 y)
  {
    return (leader(x) == leader(y));
  }
};

template<class key_type, class value_type>
class SkewHeap
{
public:
  class Node;
  using ptr_type = Node*;

  class Node
  {
    friend class SkewHeap;
  public:
    Node() = default;

  private:
    ptr_type   left;
    ptr_type   right;
    key_type   key;
    key_type   delta;
    value_type value;
  
    Node(const key_type& key, const value_type& value)
      : left(nullptr) , right(nullptr), key(key), delta(), value(value) {}

    static void _add(ptr_type a, const key_type& x)
    {
      a->delta += x;
    }
  
    static void _propagate(ptr_type a)
    {
      if (a->left  != nullptr) a->left->delta  += a->delta;
      if (a->right != nullptr) a->right->delta += a->delta;
      a->key += a->delta;
      a->delta = key_type();
    }
    static ptr_type _merge(ptr_type a, ptr_type b)
    {
      if (a == nullptr) return b;
      if (b == nullptr) return a;
      if ( (a->key + a->delta) > (b->key + b->delta) ) std::swap(a, b);
      _propagate(a);
      a->right = _merge(a->right, b);
      std::swap(a->right, a->left);
      return a;
    }
  };

private:
  Node *root;
  
public:
  using node_type = Node;
  using item_type = std::pair<key_type, value_type>;
  
  SkewHeap() : root(nullptr) {}
  
  void push(ptr_type memory,
            const key_type& key,
            const value_type& value)
  {
    *memory = node_type(key, value);
    root = Node::_merge(root, memory);
  }
  item_type pop()
  {
    assert(root != nullptr);
    Node::_propagate(root);
    auto retval = std::make_pair(std::move(root->key), std::move(root->value));
    root = Node::_merge(root->left, root->right);
    return retval;
  }
  void add(const key_type& x)
  {
    if (root != nullptr) {
      Node::_add(root, x);
    }
  }
  void merge(SkewHeap other)
  {
    root = Node::_merge(root, other.root);
  }
  bool empty() const
  {
    return (root == nullptr);
  }
};

struct Edge
{
  i32 from;
  i32 to;
  i32 cost;
  Edge() = default;
  Edge(i32 from, i32 to, i32 cost) : from(from), to(to), cost(cost) {}
};
struct DirectedGraph
{
  i32 num_vertices;
  std::vector<Edge> edges;
  
  DirectedGraph(i32 n) : num_vertices(n), edges() {}
  
  void add_edge(i32 from, i32 to, i32 cost)
  {
    edges.emplace_back(from, to, cost);
  }
  void add_edge(const Edge& e)
  {
    edges.push_back(e);
  }
};

// Minimum Spanning Arborescenceのコストの計算
i32 compute_MSA(const DirectedGraph& graph, i32 r)
{
  const i32 N = graph.num_vertices;
  const i32 M = graph.edges.size();

  using Heap = SkewHeap<i32, Edge>;
  std::vector<Heap> incoming_edges(2*N);
  std::vector<Heap::node_type> heap_memory(M);
  REP(i, M) {
    const auto& e = graph.edges[i];
    incoming_edges[e.to].push(&heap_memory[i], e.cost, e);
  }

  UnionFind components(2*N);
  std::vector<i32> seen(2*N, -1);
  std::vector<i32> parent(2*N, -1);
  std::vector< std::vector<i32> > children(2*N);
  std::vector<Edge> min_incoming_edges(2*N);
  i32 new_id = N;

  seen[r] = r;
  
  REP(s, N) {
    std::vector<i32> path;

    i32 u = s;
    while (seen[u] < 0) {
      seen[u] = s;
      path.push_back(u);

      i32 v = -1;
      while (!incoming_edges[u].empty()) {
        auto [cost, e] = incoming_edges[u].pop();
        if (!components.same(u, e.from)) {
          v = components.leader(e.from);
          incoming_edges[u].add(-cost);
          min_incoming_edges[u] = e;
          break;
        }
      }
      if (v == -1) {
        break;
      }
      if (seen[v] == s) {
        components.merge(v, new_id);
        while (true) {
          i32 w = path.back();
          path.pop_back();
          incoming_edges[new_id].merge(incoming_edges[w]);
          parent[w] = new_id;
          children[new_id].push_back(w);
          if (components.same(w, new_id)) {
            break;
          } else {
            components.merge(w, new_id);
          }
        }
        new_id += 1;
      }
      u = components.leader(v);
    }
  }

  std::vector<i32> root_list;
  std::vector<bool> used(2*N, false);
  REP(i, N) {
    if (i == r) continue;
    i32 s = components.leader(i);
    if (!used[s]) {
      used[s] = true;
      root_list.push_back(s);
    }
  }
  
  i32 total_cost = 0;
  while (!root_list.empty()) {
    i32 s = root_list.back();
    root_list.pop_back();
    const auto& e = min_incoming_edges[s];
    total_cost += e.cost;
    s = e.to;
    while (parent[s] >= 0) {
      for (i32 t : children[parent[s]]) {
        if (t == s) continue;
        parent[t] = -1;
        root_list.push_back(t);
      }
      s = parent[s];
    }
  }
  return total_cost;
}

int main()
{
  i32 N, M; std::cin >> N >> M;
  DirectedGraph graph(N);

  std::vector<bool> kouho(N, true);
  REP(i, M) {
    i32 a, b; cin >> a >> b;
    graph.add_edge(a, b, 0);
    graph.add_edge(b, a, 1);
    kouho[b] = false;
  }

  std::vector< std::pair<i32, i32> > results; // cost, index
  REP(i, N) {
    if (kouho[i]) {
      i32 c = compute_MSA(graph, i);
      results.emplace_back(c, i);
    }
  }
  auto [cmin, _] = *std::min_element(results.begin(), results.end());
  std::vector<i32> capitals;
  for (auto [c, i] : results) {
    if (c == cmin) capitals.push_back(i);
  }
  std::cout << capitals.size() << " " << cmin << "\n";
  i32 K = capitals.size();
  REP(i, K) {
    std::cout << capitals[i];
    if (i == (K - 1)) {
      std::cout << std::endl;
    } else {
      std::cout << " ";
    }
  }
  
  return 0;
}
accuracy: 1
time_ms: 540
memory_kb: 14400
final_rank: 13

code_snippet: // -*- coding: utf-8-unix -*-
// https://onlinejudge.u-aizu.ac.jp/challenges/search/titles/2647
#include <bits/stdc++.h>
using std::cin, std::cout, std::endl;
using i32 = std::int32_t;
using u32 = std::uint32_t;
using i64 = std::int64_t;
using u64 = std::uint64_t;
#define REP(i, n) for (std::int64_t i=0; i<(n); ++i)

// 木の高さを考慮したUnionFind木
class UnionFind
{
private:
  std::vector<i32> par;
  std::vector<i32> rank;
public:
  explicit UnionFind(i32 n) : par(n), rank(n, 0)
  {
    std::iota(par.begin(), par.end(), 0);
  }
  i32 leader(i32 x)
  {
    if (par[x] == x) return x;
    par[x] = leader(par[x]);
    return par[x];
  }
  void merge(i32 x, i32 y)
  {
    x = leader(x);
    y = leader(y);
    if (x == y) return;
    if (rank[x] < rank[y]) {
      par[x] = y;
    } else {
      par[y] = x;
      if (rank[x] == rank[y]) rank[x] += 1;
    }
  }
  bool same(i32 x, i32 y)
  {
    return (leader(x) == leader(y));
  }
};

template<class key_type, class value_type>
class SkewHeap
{
public:
  class Node;
  using ptr_type = Node*;

  class Node
  {
    friend class SkewHeap;
  public:
    Node() = default;

  private:
    ptr_type   left;
    ptr_type   right;
    key_type   key;
    key_type   delta;
    value_type value;
  
    Node(const key_type& key, const value_type& value)
      : left(nullptr) , right(nullptr), key(key), delta(), value(value) {}

    static void _add(ptr_type a, const key_type& x)
    {
      a->delta += x;
    }
  
    static void _propagate(ptr_type a)
    {
      if (a->left  != nullptr) a->left->delta  += a->delta;
      if (a->right != nullptr) a->right->delta += a->delta;
      a->key += a->delta;
      a->delta = key_type();
    }
    static ptr_type _merge(ptr_type a, ptr_type b)
    {
      if (a == nullptr) return b;
      if (b == nullptr) return a;
      if ( (a->key + a->delta) > (b->key + b->delta) ) std::swap(a, b);
      _propagate(a);
      a->right = _merge(a->right, b);
      std::swap(a->right, a->left);
      return a;
    }
  };

private:
  Node *root;
  
public:
  using node_type = Node;
  using item_type = std::pair<key_type, value_type>;
  
  SkewHeap() : root(nullptr) {}
  
  void push(ptr_type memory,
            const key_type& key,
            const value_type& value)
  {
    *memory = node_type(key, value);
    root = Node::_merge(root, memory);
  }
  item_type pop()
  {
    assert(root != nullptr);
    Node::_propagate(root);
    auto retval = std::make_pair(std::move(root->key), std::move(root->value));
    root = Node::_merge(root->left, root->right);
    return retval;
  }
  void add(const key_type& x)
  {
    if (root != nullptr) {
      Node::_add(root, x);
    }
  }
  void merge(SkewHeap other)
  {
    root = Node::_merge(root, other.root);
  }
  bool empty() const
  {
    return (root == nullptr);
  }
};

struct Edge
{
  i32 from;
  i32 to;
  i32 cost;
  Edge() = default;
  Edge(i32 from, i32 to, i32 cost) : from(from), to(to), cost(cost) {}
};
struct DirectedGraph
{
  i32 num_vertices;
  std::vector<Edge> edges;
  
  DirectedGraph(i32 n) : num_vertices(n), edges() {}
  
  void add_edge(i32 from, i32 to, i32 cost)
  {
    edges.emplace_back(from, to, cost);
  }
  void add_edge(const Edge& e)
  {
    edges.push_back(e);
  }
};

// Minimum Spanning Arborescenceのコストの計算
i32 compute_MSA(const DirectedGraph& graph, i32 r)
{
  constexpr i32 INF = 1000000000;
  const i32 N = graph.num_vertices;
  const i32 M = graph.edges.size();

  using Heap = SkewHeap<i32, Edge>;
  std::vector<Heap> come_edge_heap(N);
  std::vector<Heap::node_type> heap_memory(M);
  REP(i, M) {
    const auto& e = graph.edges[i];
    come_edge_heap[e.to].push(&heap_memory[i], e.cost, e);
  }

  i32 total_cost = 0;
  UnionFind dsu(N);
  std::vector<i32> seen(N, -1);
  seen[r] = r;
  std::vector<Edge> accepted_edges;
  
  REP(s, N) {
    std::vector<i32> path;

    i32 u = s;
    while (seen[u] < 0) {
      seen[u] = s;
      path.push_back(u);

      i32 v;
      while (true) {
        if (come_edge_heap[u].empty()) return INF;
        auto [cost, e] = come_edge_heap[u].pop();
        v = dsu.leader(e.from);
        if (u != v) {
          total_cost += cost;
          come_edge_heap[u].add(-cost);
          accepted_edges.push_back(e);
          break;
        }
      }
      if (seen[v] == s) {
        Heap new_heap;
        while (true) {
          i32 w = path.back();
          path.pop_back();
          new_heap.merge(come_edge_heap[w]);
          if (dsu.same(w, v)) {
            break;
          } else {
            dsu.merge(w, v);
          }
        }
        come_edge_heap[dsu.leader(v)] = new_heap;
        seen[dsu.leader(v)] = -1;
      }
      u = dsu.leader(v);
    }
  }
  
  // i32 verification = 0;
  // std::vector<bool> used(N, false);
  // for (auto it=accepted_edges.rbegin(); it!=accepted_edges.rend(); ++it) {
  //   const auto& e = *it;
  //   if (!used[e.to]) {
  //     used[e.to] = true;
  //     verification += e.cost;
  //   }
  // }
  // if (total_cost != verification) {
  //   std::abort();
  // }
  
  return total_cost;
}

int main()
{
  i32 N, M; std::cin >> N >> M;
  DirectedGraph graph(N);

  std::vector<bool> kouho(N, true);
  REP(i, M) {
    i32 a, b; cin >> a >> b;
    graph.add_edge(a, b, 0);
    graph.add_edge(b, a, 1);
    kouho[b] = false;
  }

  std::vector< std::pair<i32, i32> > results; // cost, index
  REP(i, N) {
    if (kouho[i]) {
      i32 c = compute_MSA(graph, i);
      results.emplace_back(c, i);
    }
  }
  auto [cmin, _] = *std::min_element(results.begin(), results.end());
  std::vector<i32> capitals;
  for (auto [c, i] : results) {
    if (c == cmin) capitals.push_back(i);
  }
  std::cout << capitals.size() << " " << cmin << "\n";
  i32 K = capitals.size();
  REP(i, K) {
    std::cout << capitals[i];
    if (i == (K - 1)) {
      std::cout << std::endl;
    } else {
      std::cout << " ";
    }
  }
  
  return 0;
}
accuracy: 1
time_ms: 530
memory_kb: 14032
final_rank: 11

code_snippet: // -*- coding: utf-8-unix -*-
// https://onlinejudge.u-aizu.ac.jp/challenges/search/titles/2647
#include <bits/stdc++.h>
using std::cin, std::cout, std::endl;
using i32 = std::int32_t;
using u32 = std::uint32_t;
using i64 = std::int64_t;
using u64 = std::uint64_t;
#define REP(i, n) for (std::int64_t i=0; i<(n); ++i)

// 木の高さを考慮したUnionFind木
class UnionFind
{
private:
  std::vector<i32> par;
  std::vector<i32> rank;
public:
  explicit UnionFind(i32 n) : par(n), rank(n, 0)
  {
    std::iota(par.begin(), par.end(), 0);
  }
  i32 leader(i32 x)
  {
    if (par[x] == x) return x;
    par[x] = leader(par[x]);
    return par[x];
  }
  void merge(i32 x, i32 y)
  {
    x = leader(x);
    y = leader(y);
    if (x == y) return;
    if (rank[x] < rank[y]) {
      par[x] = y;
    } else {
      par[y] = x;
      if (rank[x] == rank[y]) rank[x] += 1;
    }
  }
  bool same(i32 x, i32 y)
  {
    return (leader(x) == leader(y));
  }
};

static constexpr i32 MAX_EDGES = 200000 + 10;

template<class key_type, class value_type>
class LeftistHeap
{
private:
  // sは子を巡ってNULLにたどり着くまでの最小回数
  // 常に右側にマージするが、
  // 左の子のs >= 右の子のs
  // という条件が常に満たされるようにすることで、
  // 木の高さをノード数の対数オーダーに抑える
  struct Node
  {
    using ptr_type = Node*;
    ptr_type   left;
    ptr_type   right;
    key_type   key;
    key_type   delta;
    value_type value;
    i32        s;

    Node() = default;
  
    Node(const key_type& key, const value_type& value)
      : left(nullptr) , right(nullptr), key(key), delta(), value(value), s(0) {}

    static void _add(ptr_type a, const key_type& x)
    {
      a->delta += x;
    }
  
    static void _propagate(ptr_type a)
    {
      if (a->left  != nullptr) a->left->delta  += a->delta;
      if (a->right != nullptr) a->right->delta += a->delta;
      a->key += a->delta;
      a->delta = key_type();
    }
    static ptr_type _merge(ptr_type a, ptr_type b)
    {
      if (a == nullptr) return b;
      if (b == nullptr) return a;
      if ( (a->key + a->delta) > (b->key + b->delta) ) std::swap(a, b);
      _propagate(a);
      a->right = _merge(a->right, b);
      if ((a->left == nullptr) || (a->left->s < a->right->s)) {
          std::swap(a->right, a->left);
      }
      a->s = ((a->right == nullptr) ? 0 : a->right->s) + 1;
      return a;
    }
  };
  Node *root;

  static Node pool[MAX_EDGES];
  static i32 pool_it;
  
  static Node*
  _get_new_node(const key_type& key, const value_type& value)
  {
    pool[pool_it] = Node(key, value);
    return &pool[pool_it++];
  }
  
public:
  using item_type = std::pair<key_type, value_type>;
  
  LeftistHeap() : root(nullptr) {}

  static void init()
  {
    pool_it = 0;
  }
  
  void push(const key_type& key, const value_type& value)
  {
    root = Node::_merge(root, _get_new_node(key, value));
  }
  item_type pop()
  {
    assert(root != nullptr);
    Node::_propagate(root);
    auto retval = std::make_pair(std::move(root->key), std::move(root->value));
    root = Node::_merge(root->left, root->right);
    return retval;
  }
  void add(const key_type& x)
  {
    if (root != nullptr) {
      Node::_add(root, x);
    }
  }
  void merge(LeftistHeap other)
  {
    root = Node::_merge(root, other.root);
  }
  bool empty() const
  {
    return (root == nullptr);
  }
};

template <class key_type, class value_type>
typename LeftistHeap<key_type, value_type>::Node
LeftistHeap<key_type, value_type>::pool[MAX_EDGES];

template <class key_type, class value_type>
i32 LeftistHeap<key_type, value_type>::pool_it;

struct DirectedGraph
{
  struct Edge
  {
    i32 to;
    i32 cost;
    Edge(i32 to, i32 cost) : to(to), cost(cost) {}
  };
  using WeightedAdjacencyList = std::vector< std::vector<Edge> >;

  i32 num_vertices;
  i32 num_edges;
  WeightedAdjacencyList adj_list;
  
  DirectedGraph(i32 n)
    : num_vertices(n)
    , num_edges(0)
    , adj_list(n)
  {}
  
  void add_edge(i32 from, i32 to, i32 cost)
  {
    num_edges += 1;
    adj_list[from].emplace_back(to, cost);
  }
};

// Minimum Spanning Arborescenceのコストの計算
i32 compute_MSA(const DirectedGraph& graph, i32 r)
{
  constexpr i32 INF = 1000000000;
  const i32 N = graph.num_vertices;
  
  using Heap = LeftistHeap<i32, i32>;
  Heap::init();
  std::vector<Heap> come(N);
  REP (from, N) {
    for (const auto& e : graph.adj_list[from]) {
      come[e.to].push(e.cost, from);
    }
  }

  i32 total_cost = 0;
  UnionFind dsu(N);
  std::vector<i32> seen(N, -1);
  seen[r] = r;
  
  REP(start, N) {
    std::vector<i32> path;

    i32 cur = start;
    while (seen[cur] < 0) {
      seen[cur] = start;
      path.push_back(cur);

      i32 prev;
      while (true) {
        if (come[cur].empty()) return INF;
        auto [cost, from] = come[cur].pop();
        prev = dsu.leader(from);
        if (cur != prev) {
          total_cost += cost;
          come[cur].add(-cost);
          break;
        }
      }
      if (seen[prev] == start) {
        Heap new_heap;
        while (true) {
          i32 p = path.back();
          path.pop_back();
          new_heap.merge(come[p]);
          if (dsu.same(p, prev)) {
            break;
          } else {
            dsu.merge(p, prev);
          }
        }
        come[dsu.leader(prev)] = new_heap;
        seen[dsu.leader(prev)] = -1;
      }
      cur = dsu.leader(prev);
    }
  }
  return total_cost;
}

int main()
{
  i32 N, M; std::cin >> N >> M;
  DirectedGraph graph(N);

  std::vector<bool> kouho(N, true);
  REP(i, M) {
    i32 a, b; cin >> a >> b;
    graph.add_edge(a, b, 0);
    graph.add_edge(b, a, 1);
    kouho[b] = false;
  }

  std::vector< std::pair<i32, i32> > results; // cost, index
  REP(i, N) {
    if (kouho[i]) {
      i32 c = compute_MSA(graph, i);
      results.emplace_back(c, i);
    }
  }
  auto [cmin, _] = *std::min_element(results.begin(), results.end());
  std::vector<i32> capitals;
  for (auto [c, i] : results) {
    if (c == cmin) capitals.push_back(i);
  }
  std::cout << capitals.size() << " " << cmin << "\n";
  i32 K = capitals.size();
  REP(i, K) {
    std::cout << capitals[i];
    if (i == (K - 1)) {
      std::cout << std::endl;
    } else {
      std::cout << " ";
    }
  }
  
  return 0;
}
accuracy: 1
time_ms: 400
memory_kb: 12388
final_rank: 8

code_snippet: // -*- coding: utf-8-unix -*-
// https://onlinejudge.u-aizu.ac.jp/challenges/search/titles/2647
#include <bits/stdc++.h>
using std::cin, std::cout, std::endl;
using i32 = std::int32_t;
using u32 = std::uint32_t;
using i64 = std::int64_t;
using u64 = std::uint64_t;
#define REP(i, n) for (std::int64_t i=0; i<(n); ++i)

// 木の高さを考慮したUnionFind木
class UnionFind
{
private:
  std::vector<i32> par;
  std::vector<i32> rank;
public:
  explicit UnionFind(i32 n) : par(n), rank(n, 0)
  {
    std::iota(par.begin(), par.end(), 0);
  }
  i32 leader(i32 x)
  {
    if (par[x] == x) return x;
    par[x] = leader(par[x]);
    return par[x];
  }
  void merge(i32 x, i32 y)
  {
    x = leader(x);
    y = leader(y);
    if (x == y) return;
    if (rank[x] < rank[y]) {
      par[x] = y;
    } else {
      par[y] = x;
      if (rank[x] == rank[y]) rank[x] += 1;
    }
  }
  bool same(i32 x, i32 y)
  {
    return (leader(x) == leader(y));
  }
};

static constexpr i32 MAX_EDGES = 200000 + 10;

template<class key_type, class value_type>
class SkewHeap
{
private:
  struct SkewHeapNode
  {
    using ptr_type  = SkewHeapNode*;
    ptr_type   left;
    ptr_type   right;
    key_type   key;
    key_type   delta;
    value_type value;

    SkewHeapNode() = default;
  
    SkewHeapNode(const key_type& key, const value_type& value)
      : left(nullptr) , right(nullptr), key(key), delta(), value(value) {}

    static void _add(ptr_type& a, const key_type& x)
    {
      a->delta += x;
    }
  
    static void _propagate(ptr_type& a)
    {
      if (a->left  != nullptr) a->left->delta  += a->delta;
      if (a->right != nullptr) a->right->delta += a->delta;
      a->key += a->delta;
      a->delta = key_type();
    }
    static ptr_type _merge(ptr_type a, ptr_type b)
    {
      if (a == nullptr) return b;
      if (b == nullptr) return a;
      if ( (a->key + a->delta) > (b->key + b->delta) ) std::swap(a, b);
      _propagate(a);
      a->right = _merge(a->right, b);
      std::swap(a->right, a->left);
      return a;
    }
  };
  SkewHeapNode *root;

  static SkewHeapNode pool[MAX_EDGES];
  static i32 pool_it;
  
  static SkewHeapNode*
  _get_new_node(const key_type& key, const value_type& value)
  {
    pool[pool_it] = SkewHeapNode(key, value);
    return &pool[pool_it++];
  }
  
public:
  using item_type = std::pair<key_type, value_type>;
  
  SkewHeap() : root(nullptr) {}

  static void init()
  {
    pool_it = 0;
  }
  
  void push(const key_type& key, const value_type& value)
  {
    root = SkewHeapNode::_merge(root, _get_new_node(key, value));
  }
  item_type pop()
  {
    assert(root != nullptr);
    SkewHeapNode::_propagate(root);
    auto retval = std::make_pair(std::move(root->key), std::move(root->value));
    root = SkewHeapNode::_merge(root->left, root->right);
    return retval;
  }
  void add(const key_type& x)
  {
    if (root != nullptr) {
      SkewHeapNode::_add(root, x);
    }
  }
  void merge(SkewHeap other)
  {
    root = SkewHeapNode::_merge(root, other.root);
  }
  bool empty() const
  {
    return (root == nullptr);
  }
};

template <class key_type, class value_type>
typename SkewHeap<key_type, value_type>::SkewHeapNode
SkewHeap<key_type, value_type>::pool[MAX_EDGES];

template <class key_type, class value_type>
i32 SkewHeap<key_type, value_type>::pool_it;

struct DirectedGraph
{
  struct Edge
  {
    i32 to;
    i32 cost;
    Edge(i32 to, i32 cost) : to(to), cost(cost) {}
  };
  using WeightedAdjacencyList = std::vector< std::vector<Edge> >;

  i32 num_vertices;
  i32 num_edges;
  WeightedAdjacencyList adj_list;
  
  DirectedGraph(i32 n)
    : num_vertices(n)
    , num_edges(0)
    , adj_list(n)
  {}
  
  void add_edge(i32 from, i32 to, i32 cost)
  {
    num_edges += 1;
    adj_list[from].emplace_back(to, cost);
  }
};

// Minimum Spanning Arborescenceのコストの計算
i32 compute_MSA(const DirectedGraph& graph, i32 r)
{
  constexpr i32 INF = 1000000000;
  const i32 N = graph.num_vertices;
  
  using Heap = SkewHeap<i32, i32>;
  Heap::init();
  std::vector<Heap> come(N);
  REP (from, N) {
    for (const auto& e : graph.adj_list[from]) {
      come[e.to].push(e.cost, from);
    }
  }

  i32 total_cost = 0;
  UnionFind dsu(N);
  std::vector<i32> seen(N, -1);
  seen[r] = r;
  
  REP(start, N) {
    std::vector<i32> path;

    i32 cur = start;
    while (seen[cur] < 0) {
      seen[cur] = start;
      path.push_back(cur);

      i32 prev;
      while (true) {
        if (come[cur].empty()) return INF;
        auto [cost, from] = come[cur].pop();
        prev = dsu.leader(from);
        if (cur != prev) {
          total_cost += cost;
          come[cur].add(-cost);
          break;
        }
      }
      if (seen[prev] == start) {
        Heap new_heap;
        while (true) {
          i32 p = path.back();
          path.pop_back();
          new_heap.merge(come[p]);
          if (dsu.same(p, prev)) {
            break;
          } else {
            dsu.merge(p, prev);
          }
        }
        come[dsu.leader(prev)] = new_heap;
        seen[dsu.leader(prev)] = -1;
      }
      cur = dsu.leader(prev);
    }
  }
  return total_cost;
}

int main()
{
  i32 N, M; std::cin >> N >> M;
  DirectedGraph graph(N);

  std::vector<bool> kouho(N, true);
  REP(i, M) {
    i32 a, b; cin >> a >> b;
    graph.add_edge(a, b, 0);
    graph.add_edge(b, a, 1);
    kouho[b] = false;
  }

  std::vector< std::pair<i32, i32> > results; // cost, index
  REP(i, N) {
    if (kouho[i]) {
      i32 c = compute_MSA(graph, i);
      results.emplace_back(c, i);
    }
  }
  auto [cmin, _] = *std::min_element(results.begin(), results.end());
  std::vector<i32> capitals;
  for (auto [c, i] : results) {
    if (c == cmin) capitals.push_back(i);
  }
  std::cout << capitals.size() << " " << cmin << "\n";
  i32 K = capitals.size();
  REP(i, K) {
    std::cout << capitals[i];
    if (i == (K - 1)) {
      std::cout << std::endl;
    } else {
      std::cout << " ";
    }
  }
  
  return 0;
}
accuracy: 1
time_ms: 410
memory_kb: 12280
final_rank: 9

code_snippet: // -*- coding: utf-8-unix -*-
// https://onlinejudge.u-aizu.ac.jp/challenges/search/titles/2647
#include <bits/stdc++.h>
using std::cin, std::cout, std::endl;
using i32 = std::int32_t;
using u32 = std::uint32_t;
using i64 = std::int64_t;
using u64 = std::uint64_t;
#define REP(i, n) for (std::int64_t i=0; i<(n); ++i)

// 木の高さを考慮したUnionFind木
class UnionFind
{
private:
  std::vector<i32> par;
  std::vector<i32> rank;
public:
  explicit UnionFind(i32 n) : par(n), rank(n, 0)
  {
    std::iota(par.begin(), par.end(), 0);
  }
  i32 leader(i32 x)
  {
    if (par[x] == x) return x;
    par[x] = leader(par[x]);
    return par[x];
  }
  void merge(i32 x, i32 y)
  {
    x = leader(x);
    y = leader(y);
    if (x == y) return;
    if (rank[x] < rank[y]) {
      par[x] = y;
    } else {
      par[y] = x;
      if (rank[x] == rank[y]) rank[x] += 1;
    }
  }
  bool same(i32 x, i32 y)
  {
    return (leader(x) == leader(y));
  }
};

static constexpr i32 MAX_EDGES = 100000 + 10;

template<class key_type, class value_type>
class SkewHeap
{
private:
  struct SkewHeapNode
  {
    using ptr_type  = SkewHeapNode*;
    ptr_type   left;
    ptr_type   right;
    key_type   key;
    key_type   delta;
    value_type value;

    SkewHeapNode() = default;
  
    SkewHeapNode(const key_type& key, const value_type& value)
      : left(nullptr) , right(nullptr), key(key), delta(), value(value) {}

    static void _add(ptr_type& a, const key_type& x)
    {
      a->delta += x;
    }
  
    static void _propagate(ptr_type& a)
    {
      if (a->left  != nullptr) a->left->delta  += a->delta;
      if (a->right != nullptr) a->right->delta += a->delta;
      a->key += a->delta;
      a->delta = key_type();
    }
    static ptr_type _merge(ptr_type a, ptr_type b)
    {
      if (a == nullptr) return b;
      if (b == nullptr) return a;
      if ( (a->key + a->delta) > (b->key + b->delta) ) std::swap(a, b);
      _propagate(a);
      a->right = _merge(a->right, b);
      std::swap(a->right, a->left);
      return a;
    }
  };
  SkewHeapNode *root;

  static SkewHeapNode pool[MAX_EDGES];
  static i32 pool_it;
  
  static SkewHeapNode*
  _get_new_node(const key_type& key, const value_type& value)
  {
    pool[pool_it] = SkewHeapNode(key, value);
    return &pool[pool_it++];
  }
  
public:
  using item_type = std::pair<key_type, value_type>;
  
  SkewHeap() : root(nullptr) {}

  static void init()
  {
    pool_it = 0;
  }
  
  void push(const key_type& key, const value_type& value)
  {
    root = SkewHeapNode::_merge(root, _get_new_node(key, value));
  }
  item_type pop()
  {
    assert(root != nullptr);
    SkewHeapNode::_propagate(root);
    auto retval = std::make_pair(std::move(root->key), std::move(root->value));
    root = SkewHeapNode::_merge(root->left, root->right);
    return retval;
  }
  void add(const key_type& x)
  {
    if (root != nullptr) {
      SkewHeapNode::_add(root, x);
    }
  }
  void merge(SkewHeap other)
  {
    root = SkewHeapNode::_merge(root, other.root);
  }
  bool empty() const
  {
    return (root == nullptr);
  }
};

template <class key_type, class value_type>
typename SkewHeap<key_type, value_type>::SkewHeapNode
SkewHeap<key_type, value_type>::pool[MAX_EDGES];

template <class key_type, class value_type>
i32 SkewHeap<key_type, value_type>::pool_it;

struct DirectedGraph
{
  struct Edge
  {
    i32 to;
    i32 cost;
    Edge(i32 to, i32 cost) : to(to), cost(cost) {}
  };
  using WeightedAdjacencyList = std::vector< std::vector<Edge> >;

  i32 num_vertices;
  i32 num_edges;
  WeightedAdjacencyList adj_list;
  
  DirectedGraph(i32 n)
    : num_vertices(n)
    , num_edges(0)
    , adj_list(n)
  {}
  
  void add_edge(i32 from, i32 to, i32 cost)
  {
    num_edges += 1;
    adj_list[from].emplace_back(to, cost);
  }
};

// Minimum Spanning Arborescenceのコストの計算
i32 compute_MSA(const DirectedGraph& graph, i32 r)
{
  constexpr i32 INF = 1000000000;
  const i32 N = graph.num_vertices;
  
  using Heap = SkewHeap<i32, i32>;
  Heap::init();
  std::vector<Heap> come(N);
  REP (from, N) {
    for (const auto& e : graph.adj_list[from]) {
      come[e.to].push(e.cost, from);
    }
  }

  i32 total_cost = 0;
  UnionFind dsu(N);
  std::vector<i32> seen(N, -1);
  seen[r] = r;
  
  REP(start, N) {
    std::vector<i32> path;

    i32 cur = start;
    while (seen[cur] < 0) {
      seen[cur] = start;
      path.push_back(cur);

      i32 prev;
      while (true) {
        if (come[cur].empty()) return INF;
        auto [cost, from] = come[cur].pop();
        prev = dsu.leader(from);
        if (cur != prev) {
          total_cost += cost;
          come[cur].add(-cost);
          break;
        }
      }
      if (seen[prev] == start) {
        Heap new_heap;
        while (true) {
          i32 p = path.back();
          path.pop_back();
          new_heap.merge(come[p]);
          if (dsu.same(p, prev)) {
            break;
          } else {
            dsu.merge(p, prev);
          }
        }
        come[dsu.leader(prev)] = new_heap;
        seen[dsu.leader(prev)] = -1;
      }
      cur = dsu.leader(prev);
    }
  }
  return total_cost;
}

int main()
{
  i32 N, M; std::cin >> N >> M;
  DirectedGraph graph(N);

  std::vector<bool> kouho(N, true);
  REP(i, M) {
    i32 a, b; cin >> a >> b;
    graph.add_edge(a, b, 0);
    graph.add_edge(b, a, 1);
    kouho[b] = false;
  }

  std::vector< std::pair<i32, i32> > results; // cost, index
  REP(i, N) {
    if (kouho[i]) {
      i32 c = compute_MSA(graph, i);
      results.emplace_back(c, i);
    }
  }
  auto [cmin, _] = *std::min_element(results.begin(), results.end());
  std::vector<i32> capitals;
  for (auto [c, i] : results) {
    if (c == cmin) capitals.push_back(i);
  }
  std::cout << capitals.size() << " " << cmin << "\n";
  i32 K = capitals.size();
  REP(i, K) {
    std::cout << capitals[i];
    if (i == (K - 1)) {
      std::cout << std::endl;
    } else {
      std::cout << " ";
    }
  }
  
  return 0;
}
accuracy: 0.8928571428571429
time_ms: 40
memory_kb: 4720
final_rank: 19

code_snippet: // -*- coding: utf-8-unix -*-
// https://onlinejudge.u-aizu.ac.jp/challenges/search/titles/2647
#include <bits/stdc++.h>
using std::cin, std::cout, std::endl;
using i32 = std::int32_t;
using u32 = std::uint32_t;
using i64 = std::int64_t;
using u64 = std::uint64_t;
#define REP(i, n) for (std::int64_t i=0; i<(n); ++i)

// 木の高さを考慮したUnionFind木
class UnionFind
{
private:
  std::vector<i32> par;
  std::vector<i32> rank;
public:
  explicit UnionFind(i32 n) : par(n), rank(n, 0)
  {
    std::iota(par.begin(), par.end(), 0);
  }
  i32 leader(i32 x)
  {
    if (par[x] == x) return x;
    par[x] = leader(par[x]);
    return par[x];
  }
  void merge(i32 x, i32 y)
  {
    x = leader(x);
    y = leader(y);
    if (x == y) return;
    if (rank[x] < rank[y]) {
      par[x] = y;
    } else {
      par[y] = x;
      if (rank[x] == rank[y]) rank[x] += 1;
    }
  }
  bool same(i32 x, i32 y)
  {
    return (leader(x) == leader(y));
  }
};

template<class key_type, class value_type>
class SkewHeap
{
private:
  struct SkewHeapNode
  {
    using ptr_type  = std::unique_ptr<SkewHeapNode>;
    ptr_type   left;
    ptr_type   right;
    key_type   key;
    key_type   delta;
    value_type value;
  
    SkewHeapNode(const key_type& key, const value_type& value)
      : left(nullptr) , right(nullptr), key(key), delta(), value(value) {}

    static void _add(ptr_type& a, const key_type& x)
    {
      a->delta += x;
    }
  
    static void _propagate(ptr_type& a)
    {
      if (a->left  != nullptr) a->left->delta  += a->delta;
      if (a->right != nullptr) a->right->delta += a->delta;
      a->key += a->delta;
      a->delta = key_type();
    }
    static ptr_type _merge(ptr_type a, ptr_type b)
    {
      if (a == nullptr) return b;
      if (b == nullptr) return a;
      if ( (a->key + a->delta) > (b->key + b->delta) ) std::swap(a, b);
      _propagate(a);
      a->right = _merge(std::move(a->right), std::move(b));
      std::swap(a->right, a->left);
      return a;
    }
  };
  std::unique_ptr<SkewHeapNode> root;
  
public:
  using item_type = std::pair<key_type, value_type>;
  
  SkewHeap() : root(nullptr) {}
  
  void push(const key_type& key, const value_type& value)
  {
    root = SkewHeapNode::_merge(std::move(root),
                                std::make_unique<SkewHeapNode>(key, value));
  }
  item_type pop()
  {
    assert(root != nullptr);
    SkewHeapNode::_propagate(root);
    auto retval = std::make_pair(std::move(root->key), std::move(root->value));
    root = SkewHeapNode::_merge(std::move(root->left), std::move(root->right));
    return retval;
  }
  void add(const key_type& x)
  {
    if (root != nullptr) {
      SkewHeapNode::_add(root, x);
    }
  }
  void merge(SkewHeap&& other)
  {
    root = SkewHeapNode::_merge(std::move(root), std::move(other.root));
  }
  bool empty() const
  {
    return (root == nullptr);
  }
};

struct DirectedGraph
{
  struct Edge
  {
    i32 to;
    i32 cost;
    Edge(i32 to, i32 cost) : to(to), cost(cost) {}
  };
  using WeightedAdjacencyList = std::vector< std::vector<Edge> >;

  i32 num_vertices;
  i32 num_edges;
  WeightedAdjacencyList adj_list;
  
  DirectedGraph(i32 n)
    : num_vertices(n)
    , num_edges(0)
    , adj_list(n)
  {}
  
  void add_edge(i32 from, i32 to, i32 cost)
  {
    num_edges += 1;
    adj_list[from].emplace_back(to, cost);
  }
};

// Minimum Spanning Arborescenceのコストの計算
i32 compute_MSA(const DirectedGraph& graph, i32 r)
{
  constexpr i32 INF = 1000000000;
  const i32 N = graph.num_vertices;
  
  using Heap = SkewHeap<i32, i32>;
  std::vector<Heap> come(N);
  REP (from, N) {
    for (const auto& e : graph.adj_list[from]) {
      come[e.to].push(e.cost, from);
    }
  }

  i32 total_cost = 0;
  UnionFind dsu(N);
  std::vector<i32> seen(N, -1);
  seen[r] = r;
  
  REP(start, N) {
    std::vector<i32> path;

    i32 cur = start;
    while (seen[cur] < 0) {
      seen[cur] = start;
      path.push_back(cur);

      i32 prev;
      while (true) {
        if (come[cur].empty()) return INF;
        auto [cost, from] = come[cur].pop();
        prev = dsu.leader(from);
        if (cur != prev) {
          total_cost += cost;
          come[cur].add(-cost);
          break;
        }
      }
      if (seen[prev] == start) {
        Heap new_heap;
        while (true) {
          i32 p = path.back();
          path.pop_back();
          new_heap.merge(std::move(come[p]));
          if (dsu.same(p, prev)) {
            break;
          } else {
            dsu.merge(p, prev);
          }
        }
        come[dsu.leader(prev)] = std::move(new_heap);
        seen[dsu.leader(prev)] = -1;
      }
      cur = dsu.leader(prev);
    }
  }
  return total_cost;
}

int main()
{
  i32 N, M; std::cin >> N >> M;
  DirectedGraph graph(N);

  std::vector<bool> kouho(N, true);
  REP(i, M) {
    i32 a, b; cin >> a >> b;
    graph.add_edge(a, b, 0);
    graph.add_edge(b, a, 1);
    kouho[b] = false;
  }

  std::vector< std::pair<i32, i32> > results; // cost, index
  REP(i, N) {
    if (kouho[i]) {
      i32 c = compute_MSA(graph, i);
      results.emplace_back(c, i);
    }
  }
  auto [cmin, _] = *std::min_element(results.begin(), results.end());
  std::vector<i32> capitals;
  for (auto [c, i] : results) {
    if (c == cmin) capitals.push_back(i);
  }
  std::cout << capitals.size() << " " << cmin << "\n";
  i32 K = capitals.size();
  REP(i, K) {
    std::cout << capitals[i];
    if (i == (K - 1)) {
      std::cout << std::endl;
    } else {
      std::cout << " ";
    }
  }
  
  return 0;
}
accuracy: 1
time_ms: 1430
memory_kb: 15204
final_rank: 16

code_snippet: // -*- coding: utf-8-unix -*-
// https://onlinejudge.u-aizu.ac.jp/challenges/search/titles/2647
#include <bits/stdc++.h>
using std::cin, std::cout, std::endl;
using i32 = std::int32_t;
using u32 = std::uint32_t;
using i64 = std::int64_t;
using u64 = std::uint64_t;
#define REP(i, n) for (std::int64_t i=0; i<(n); ++i)

// 木の高さを考慮しないUnionFind木
class UnionFind
{
private:
  std::vector<i32> par;
public:
  explicit UnionFind(i32 n) : par(n)
  {
    std::iota(par.begin(), par.end(), 0);
  }
  i32 leader(i32 x)
  {
    if (par[x] == x) return x;
    par[x] = leader(par[x]);
    return par[x];
  }
  void merge(i32 x, i32 y)
  {
    x = leader(x);
    y = leader(y);
    par[x] = y;
  }
  bool same(i32 x, i32 y)
  {
    return (leader(x) == leader(y));
  }
};

template<class key_type, class value_type>
struct PriorityQueue
{
  using item_type = std::pair<key_type, value_type>;
  struct Compare
  {
    bool operator()(const item_type& a, const item_type& b) const
    {
      // 値が小さい要素を優先
      return a.first > b.first;
    };
  };
  std::priority_queue<item_type, std::vector<item_type>, Compare> que;
  key_type offset;
  
  PriorityQueue() : que(), offset() {}

  void push(const key_type& key, const value_type& value)
  {
    que.emplace(key, value);
  }
  void push(const item_type& item)
  {
    que.push(item);
  }
  item_type top() const
  {
    item_type x = que.top();
    x.first += offset;
    return x;
  }
  void pop()
  {
    que.pop();
  }
  bool empty() const
  {
    return que.empty();
  }
  std::size_t size() const
  {
    return que.size();
  }
  void add(const key_type& x)
  {
    offset += x;
  }
};

struct DirectedGraph
{
  struct Edge
  {
    i32 to;
    i32 cost;
    Edge(i32 to, i32 cost) : to(to), cost(cost) {}
  };
  using WeightedAdjacencyList = std::vector< std::vector<Edge> >;

  i32 num_vertices;
  i32 num_edges;
  WeightedAdjacencyList adj_list;
  
  DirectedGraph(i32 n)
    : num_vertices(n)
    , num_edges(0)
    , adj_list(n)
  {}
  
  void add_edge(i32 from, i32 to, i32 cost)
  {
    num_edges += 1;
    adj_list[from].emplace_back(to, cost);
  }
};

PriorityQueue<i32, std::pair<i32, i32>>
merge_queue(PriorityQueue<i32, std::pair<i32, i32>>&& a,
            PriorityQueue<i32, std::pair<i32, i32>>&& b,
            UnionFind& dsu)
{
  using Que = PriorityQueue<i32, std::pair<i32, i32>>;
  if (a.size() < b.size()) {
    while (!a.empty()) {
      auto t = a.top();
      a.pop();
      auto [from, to] = t.second;
      if (!dsu.same(from, to)) {
        t.first -= b.offset;
        b.push(t);
      }
    }
    a = Que();
    return b;
  } 
  while (!b.empty()) {
    auto t = b.top();
    b.pop();
    auto [from, to] = t.second;
    if (!dsu.same(from, to)) {
      t.first -= a.offset;
      a.push(t);
    }
  }
  b = Que();
  return a;
}

// Minimum Spanning Arborescenceのコストの計算
i32 compute_MSA(const DirectedGraph& graph, i32 r)
{
  const i32 N = graph.num_vertices;
  UnionFind dsu(N);
  using Heap = PriorityQueue<i32, std::pair<i32, i32>>; // cost, {from, to}
  std::vector<Heap> come(N);
  std::vector<i32> used(N, 0); // 0 : 未処理, 1 : 処理中, 2 : 完了
  std::vector<i32> from_vertices(N); // 作成する全域木の頂点に入ってくる辺のfrom
  std::vector<i32> from_cost(N);     // 作成する全域木の頂点に入ってくる辺のcost
  used[r] = 2;

  // 各頂点に入ってくるエッジをヒープに追加
  REP (from, N) {
    for (const auto& e : graph.adj_list[from]) {
      come[e.to].push(e.cost, std::make_pair(from, e.to));
    }
  }
  constexpr i32 INF = 1000000000;

  i32 total_cost = 0;
  
  REP(start, N) {
    if (used[start] != 0) continue;
    int cur = start;
    std::vector<i32> processing;
    
    while (used[cur] != 2) {
      used[cur] = 1;
      processing.push_back(cur);

      while (true) {
        // 入ってくるエッジがない => 有向全域木が存在しない
        if (come[cur].empty()) return INF;
        // 入ってくるエッジの内、最もコストが小さいエッジを選ぶ
        auto [cost, value] = come[cur].top();
        come[cur].pop();
        i32 from = value.first;
        from_vertices[cur] = from;
        from_cost[cur]     = cost;
        // 自己ループならやり直し (頂点を圧縮しているので、自己ループが発生する場合がある)
        if (cur != from) break;
      }

      total_cost += from_cost[cur];

      if (used[from_vertices[cur]] == 1) {
        // サイクルができた場合
        i32 p = cur;
        do {
          // 頂点pに入るエッジのコストから現在使用しているエッジのコストを引く
          come[p].add(- from_cost[p]);
          // 頂点を圧縮する
          if (p != cur) {
            dsu.merge(p, cur); // curにpをマージ
            come[cur] = merge_queue(std::move(come[cur]), std::move(come[p]), dsu);
          }
          p = dsu.leader(from_vertices[p]);
        } while (p != cur);
        // 次に処理する頂点は圧縮された頂点
      } else {
        // サイクルができなかった場合、エッジのfromに移動
        cur = from_vertices[cur];
      }
    }
    // 処理完了
    for( int v : processing ) {
      used[v] = 2;
    }
  }
  return total_cost;
}

int main()
{
  i32 N, M; std::cin >> N >> M;
  DirectedGraph graph(N);

  std::vector<bool> kouho(N, true);
  REP(i, M) {
    i32 a, b; cin >> a >> b;
    graph.add_edge(a, b, 0);
    graph.add_edge(b, a, 1);
    kouho[b] = false;
  }

  std::vector< std::pair<i32, i32> > results; // cost, index
  REP(i, N) {
    if (kouho[i]) {
      i32 c = compute_MSA(graph, i);
      results.emplace_back(c, i);
    }
  }
  auto [cmin, _] = *std::min_element(results.begin(), results.end());
  std::vector<i32> capitals;
  for (auto [c, i] : results) {
    if (c == cmin) capitals.push_back(i);
  }
  std::cout << capitals.size() << " " << cmin << "\n";
  i32 K = capitals.size();
  REP(i, K) {
    std::cout << capitals[i];
    if (i == (K - 1)) {
      std::cout << std::endl;
    } else {
      std::cout << " ";
    }
  }
  
  return 0;
}
accuracy: 1
time_ms: 820
memory_kb: 115096
final_rank: 18

code_snippet: // -*- coding: utf-8-unix -*-
// https://onlinejudge.u-aizu.ac.jp/challenges/search/titles/2647
#include <bits/stdc++.h>
using std::cin, std::cout, std::endl;
using i32 = std::int32_t;
using u32 = std::uint32_t;
using i64 = std::int64_t;
using u64 = std::uint64_t;
#define REP(i, n) for (std::int64_t i=0; i<(n); ++i)

// 木の高さを考慮しないUnionFind木
class UnionFind
{
private:
  std::vector<i32> par;
public:
  explicit UnionFind(i32 n) : par(n)
  {
    std::iota(par.begin(), par.end(), 0);
  }
  i32 leader(i32 x)
  {
    if (par[x] == x) return x;
    par[x] = leader(par[x]);
    return par[x];
  }
  void merge(i32 x, i32 y)
  {
    x = leader(x);
    y = leader(y);
    par[x] = y;
  }
  bool same(i32 x, i32 y)
  {
    return (leader(x) == leader(y));
  }
};

class SkewHeap
{
private:
  struct SkewHeapNode
  {
    using ptr_type = std::unique_ptr<SkewHeapNode>;
    ptr_type left;
    ptr_type right;
    i32 v;
    i32 add;
    i32 id;
  
    SkewHeapNode(i32 v, i32 id)
      : left(nullptr) , right(nullptr), v(v), add(0), id(id) {}

    static void _add(ptr_type& a, i32 x)
    {
      a->add += x;
    }
  
    static void _propagate(ptr_type& a)
    {
      if (a->left  != nullptr) a->left->add  += a->add;
      if (a->right != nullptr) a->right->add += a->add;
      a->v += a->add;
      a->add = 0;
    }
    static ptr_type _merge(ptr_type a, ptr_type b)
    {
      if (a == nullptr) return b;
      if (b == nullptr) return a;
      if ( (a->v + a->add) > (b->v + b->add) ) std::swap(a, b);
      _propagate(a);
      a->right = _merge(std::move(a->right), std::move(b));
      std::swap(a->right, a->left);
      return a;
    }
  };
  std::unique_ptr<SkewHeapNode> root;
  
public:
  SkewHeap() : root(nullptr) {}
  
  void push(i32 v, i32 id)
  {
    root = SkewHeapNode::_merge(std::move(root), std::make_unique<SkewHeapNode>(v, id));
  }
  std::pair<i32, i32> pop()
  {
    assert(root != nullptr);
    SkewHeapNode::_propagate(root);
    auto retval = std::make_pair(root->v, root->id);
    root = SkewHeapNode::_merge(std::move(root->left), std::move(root->right));
    return retval;
  }
  void add(i32 x)
  {
    if (root != nullptr) {
      SkewHeapNode::_add(root, x);
    }
  }
  void merge(SkewHeap&& other)
  {
    root = SkewHeapNode::_merge(std::move(root), std::move(other.root));
  }
  bool empty() const
  {
    return (root == nullptr);
  }
};

struct DirectedGraph
{
  struct Edge
  {
    i32 to;
    i32 cost;
    Edge(i32 to, i32 cost) : to(to), cost(cost) {}
  };
  using WeightedAdjacencyList = std::vector< std::vector<Edge> >;

  i32 num_vertices;
  i32 num_edges;
  WeightedAdjacencyList adj_list;
  
  DirectedGraph(i32 n)
    : num_vertices(n)
    , num_edges(0)
    , adj_list(n)
  {}
  
  void add_edge(i32 from, i32 to, i32 cost)
  {
    num_edges += 1;
    adj_list[from].emplace_back(to, cost);
  }
};

// Minimum Spanning Arborescenceのコストの計算
i32 compute_MSA(const DirectedGraph& graph, i32 r)
{
  const i32 N = graph.num_vertices;
  UnionFind dsu(N);
  std::vector<SkewHeap> come(N);
  std::vector<i32> used(N, 0); // 0 : 未処理, 1 : 処理中, 2 : 完了
  std::vector<i32> from_vertices(N); // 作成する全域木の頂点に入ってくる辺のfrom
  std::vector<i32> from_cost(N);     // 作成する全域木の頂点に入ってくる辺のcost
  used[r] = 2;

  // 各頂点に入ってくるエッジをヒープに追加
  REP (from, N) {
    for (const auto& e : graph.adj_list[from]) {
      come[e.to].push(e.cost, from);
    }
  }
  constexpr i32 INF = 1000000000;

  i32 total_cost = 0;
  
  REP(start, N) {
    if (used[start] != 0) continue;
    int cur = start;
    std::vector<i32> processing;
    
    while (used[cur] != 2) {
      used[cur] = 1;
      processing.push_back(cur);

      while (true) {
        // 入ってくるエッジがない => 有効全域木が存在しない
        if (come[cur].empty()) return INF;
        // 入ってくるエッジの内、最もコストが小さいエッジを選ぶ
        auto [cost, from]  = come[cur].pop();
        from_vertices[cur] = from;
        from_cost[cur]     = cost;
        // 自己ループならやり直し (頂点を圧縮しているので、自己ループが発生する場合がある)
        if (cur != from) break;
      }

      total_cost += from_cost[cur];

      if (used[from_vertices[cur]] == 1) {
        // サイクルができた場合
        i32 p = cur;
        do {
          // 頂点pに入るエッジのコストから現在使用しているエッジのコストを引く
          come[p].add(- from_cost[p]);
          // 頂点を圧縮する
          if (p != cur) {
            dsu.merge(p, cur); // curにpをマージ
            come[cur].merge(std::move(come[p]));
          }
          p = dsu.leader(from_vertices[p]);
        } while (p != cur);
        // 次に処理する頂点は圧縮された頂点
      } else {
        // サイクルができなかった場合、エッジのfromに移動
        cur = from_vertices[cur];
      }
    }
    // 処理完了
    for( int v : processing ) {
      used[v] = 2;
    }
  }
  return total_cost;
}

int main()
{
  i32 N, M; std::cin >> N >> M;
  DirectedGraph graph(N);

  std::vector<bool> kouho(N, true);
  REP(i, M) {
    i32 a, b; cin >> a >> b;
    graph.add_edge(a, b, 0);
    graph.add_edge(b, a, 1);
    kouho[b] = false;
  }

  std::vector< std::pair<i32, i32> > results; // cost, index
  REP(i, N) {
    if (kouho[i]) {
      i32 c = compute_MSA(graph, i);
      results.emplace_back(c, i);
    }
  }
  auto [cmin, _] = *std::min_element(results.begin(), results.end());
  std::vector<i32> capitals;
  for (auto [c, i] : results) {
    if (c == cmin) capitals.push_back(i);
  }
  std::cout << capitals.size() << " " << cmin << "\n";
  i32 K = capitals.size();
  REP(i, K) {
    std::cout << capitals[i];
    if (i == (K - 1)) {
      std::cout << std::endl;
    } else {
      std::cout << " ";
    }
  }
  
  return 0;
}
accuracy: 1
time_ms: 1340
memory_kb: 15252
final_rank: 15

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define REP(i,n) for(int i=0;i<(n);i++)

class UnionFind{
  int n,num;
  vector<int> sz,parent;
public:
  UnionFind()=default;
  UnionFind(int n):n(n),num(n),sz(n,1),parent(n,0){iota(parent.begin(),parent.end(),0);}
  
  int leader(int x){ 
    assert(0<=x and x<n);
    return (x==parent[x]? x : parent[x]=leader(parent[x])); 
  }
  
  bool same(int x,int y){
    assert(0<=x and x<n and 0<=y and y<n);
    return leader(x)==leader(y); 
  }
  
  bool merge(int x,int y){
    assert(0<=x and x<n and 0<=y and y<n);
    x=leader(x);y=leader(y);
    if(x==y)return false;
    if(sz[x]<sz[y])swap(x,y);
    sz[x]+=sz[y];
    parent[y]=x;
    num--;
    return true;
  }
  
  int size(const int x){
    assert(0<=x and x<n);
    return sz[leader(x)];
  }
  
  int count()const{
    return num;
  }
};

template<typename T>
struct WeightedEdge{
  WeightedEdge()=default;
  WeightedEdge(int from,int to,T weight):from(from),to(to),weight(weight){}
  int from,to;
  T weight;
};

template<typename T>
struct WeightedGraph{
  int n;
  using weight_type=T;
  using edge_type=WeightedEdge<T>;
  vector<edge_type> edges;
protected:
  vector<int> in_deg;
  bool comepared;
  class OutgoingEdges{
    WeightedGraph* g;
    int l,r;
  public:
    OutgoingEdges(WeightedGraph* g,int l,int r):g(g),l(l),r(r){}
    edge_type* begin(){ return &(g->edges[l]); }
    edge_type* end(){ return &(g->edges[r]); }
    edge_type& operator[](int i){ return g->edges[l+i]; }
    int size()const{ return r-l; }
  };
public:
  OutgoingEdges operator[](int v){
    assert(comepared);
    return { this,in_deg[v],in_deg[v+1] };
  }

  bool is_comepared()const{ return comepared; }

  WeightedGraph():n(0),in_deg(1,0),comepared(false){}
  WeightedGraph(int n):n(n),in_deg(n+1,0),comepared(false){}
  WeightedGraph(int n,int m,bool directed=false,int indexed=1):
    n(n),in_deg(n+1,0),comepared(false){ scan(m,directed,indexed); }

  void resize(int n){n=n;}

  void add_arc(int from,int to,T weight){
    assert(!comepared);
    assert(0<=from and from<n and 0<=to and to<n);
    edges.emplace_back(from,to,weight);
    in_deg[from+1]++;
  }
  void add_edge(int u,int v,T weight){
    add_arc(u,v,weight);
    add_arc(v,u,weight);
  }

  void scan(int m,bool directed=false,int indexed=1){
    edges.reserve(directed?m:2*m);
    while(m--){
      int u,v;cin>>u>>v;u-=indexed;v-=indexed;
      T weight;cin>>weight;
      if(directed)add_arc(u,v,weight);
      else add_edge(u,v,weight);
    }
    build();
  }

  void build(){
    assert(!comepared);comepared=true;
    for(int v=0;v<n;v++)in_deg[v+1]+=in_deg[v];
    vector<edge_type> new_edges(in_deg.back());
    auto counter=in_deg;
    for(auto&&e:edges)new_edges[ counter[e.from]++ ]=e;
    edges=new_edges;
  }

  void graph_debug()const{
  #ifndef __LOCAL
    return;
  #endif
    assert(comepared);
    for(int from=0;from<n;from++){
      cerr<<from<<";";
      for(int i=in_deg[from];i<in_deg[from+1];i++)
        cerr<<"("<<edges[i].to<<","<<edges[i].weight<<")";
      cerr<<"\n";
    }
  }
};

template<typename WG,typename E=typename WG::edge_type,typename W=typename WG::weight_type>
optional< pair<W,vector<int>> > minimum_spanning_arborescence(WG g,int r=0){
  int n=g.n;
  W res=0;
  vector<W> new_add(n,0);
  vector<int> tree(n);
  vector<int> state(n,0);
  vector<int> pre(n);
  UnionFind uf(n);
  state[r]=2;

  auto compare=[&](const int&a,const int&b){return g.edges[a].weight>g.edges[b].weight;};
  using PQ=priority_queue<int,vector<int>,decltype(compare)>;
  vector< pair<PQ,W> > pq_add(n,{PQ{compare},0});
  for(int i=0;i<g.edges.size();i++)
    pq_add[g.edges[i].to].first.push(i);
  vector<int> pq_id(n);
  iota(pq_id.begin(),pq_id.end(),0);
  
  auto merge=[&](int u,int v){
    u=uf.leader(u);v=uf.leader(v);
    if(u==v)return;
    uf.merge(u,v);
    auto&[pq1,add1]=pq_add[pq_id[u]];
    auto&[pq2,add2]=pq_add[pq_id[v]];
    if(pq1.size()>pq2.size()){
      while(pq2.size()){
        int edge_id=pq2.top();pq2.pop();
        g.edges[edge_id].weight-=add2-add1;
        pq1.push(edge_id);
      }
      pq_id[uf.leader(v)]=pq_id[u];
    }
    else{
      while(pq1.size()){
        int edge_id=pq1.top();pq1.pop();
        g.edges[edge_id].weight-=add1-add2;
        pq2.push(edge_id);
      }
      pq_id[uf.leader(v)]=pq_id[v];
    }
  };
  
  for(int i=0;i<n;i++){
    int now=uf.leader(i);
    if(state[now])continue;
    vector<int> processing;
    while(state[now]!=2){
      processing.push_back(now);
      state[now]=1;
      auto&[pq,add]=pq_add[pq_id[now]];
      if(!pq.size())return nullopt;
      int edge_id=pq.top();pq.pop();
      auto&e=g.edges[edge_id];
      res+=e.weight-add;
      tree[e.to]=edge_id;
      pre[now]=uf.leader(e.from);
      new_add[now]=e.weight;
      if(state[pre[now]]==1){
        int v=now;
        do{
          pq_add[pq_id[v]].second=new_add[v];
          merge(v,now);
          v=uf.leader(pre[v]);
        }while(!uf.same(v,now));
        now=uf.leader(now);
      }
      else
        now=uf.leader(pre[now]);
    }
    for(int v:processing)state[v]=2;
  }
  tree.erase(tree.begin()+r);
  return make_pair(res,tree);
}

int main(){
  int n,m;cin>>n>>m;
  vector<bool> koho(n,true);
  WeightedGraph<int> G(n);
  REP(_,m){
    int a,b;cin>>a>>b;
    koho[b]=false;
    G.add_arc(a,b,0);
    G.add_arc(b,a,1);
  }

  int mn=1e9;
  vector<int> ans;
  REP(i,n)if(koho[i]){
    auto res=minimum_spanning_arborescence(G,i);
    assert(res.has_value());
    const auto&[val,tree]=res.value();
    if(mn==val)ans.push_back(i);
    if(mn>val){
      mn=val;
      ans={i};
    }
  }
  cout<<ans.size()<<" "<<mn<<"\n";
  REP(i,ans.size())cout<<ans[i]<<"\n "[i+1<ans.size()];
}
accuracy: 1
time_ms: 320
memory_kb: 11328
final_rank: 7

code_snippet: #pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
#include<array>
#include<chrono>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
constexpr ll mod = 998244353;
const ll INF = mod * mod;
typedef pair<int, int>P;

#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;

template<typename T>
void chmin(T& a, T b) {
	a = min(a, b);
}
template<typename T>
void chmax(T& a, T b) {
	a = max(a, b);
}
template<typename T>
void cinarray(vector<T>& v) {
	rep(i, v.size())cin >> v[i];
}
template<typename T>
void coutarray(vector<T>& v) {
	rep(i, v.size()) {
		if (i > 0)cout << " "; cout << v[i];
	}
	cout << "\n";
}
ll mod_pow(ll x, ll n, ll m = mod) {
	if (n < 0) {
		ll res = mod_pow(x, -n, m);
		return mod_pow(res, m - 2, m);
	}
	if (abs(x) >= m)x %= m;
	if (x < 0)x += m;
	if (x == 0)return 0;
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	int n;
	modint() :n(0) { ; }
	modint(ll m) {
		if (m < 0 || mod <= m) {
			m %= mod; if (m < 0)m += mod;
		}
		n = m;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, ll n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }
modint operator/=(modint& a, modint b) { a = a / b; return a; }
const int max_n = 1 << 20;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
modint combP(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[a - b];
}

ll gcd(ll a, ll b) {
	a = abs(a); b = abs(b);
	if (a < b)swap(a, b);
	while (b) {
		ll r = a % b; a = b; b = r;
	}
	return a;
}
typedef long double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-8;
const ld pi = acosl(-1.0);
int dx[4] = { 1,0,-1,0 };
int dy[4] = { 0,1,0,-1 };

using mP = pair<modint, modint>;
//-----------------------------------

struct uf {
private:
	vector<int> par, ran;
public:
	uf(int n) {
		par.resize(n, 0);
		ran.resize(n, 0);
		rep(i, n) {
			par[i] = i;
		}
	}
	int find(int x) {
		if (par[x] == x)return x;
		else return par[x] = find(par[x]);
	}
	void unite(int x, int y) {
		x = find(x), y = find(y);
		if (x == y)return;
		if (ran[x] < ran[y]) {
			par[x] = y;
		}
		else {
			par[y] = x;
			if (ran[x] == ran[y])ran[x]++;
		}
	}
	bool same(int x, int y) {
		return find(x) == find(y);
	}
};

using tval = ll;
struct edge {
	int to; tval cost;
};

vector<P> chu_liu_edmonds(vector<vector<edge>>& G, vector<bool> exi, int root = -1) {
	int n = G.size();
	if (root < 0) {
		root = n;
		G.push_back({});
		rep(i, n)G[root].push_back({ n,INF / 1000000 });
		n++;
	}
	vector<vector<edge>> rG(n);
	rep(i, n)if (exi[i])for (edge e : G[i]) {
		rG[e.to].push_back({ i,e.cost });
	}
	vector<int> par(n);
	vector<tval> memo(n);
	rep(i, n)if (exi[i] && i != root) {
		tval mi = INF;
		for (edge e : rG[i]) {
			if (e.cost < mi) {
				mi = e.cost;
				par[i] = e.to;
			}
		}
		memo[i] = mi;

	}
	vector<bool> used(n);
	vector<bool> cused(n);
	vector<int> ts;
	used[root] = true;
	rep(i, n)if (exi[i] && i != root) {
		if (used[i])continue;
		vector<int> ids;
		int cur = i;
		cused[i] = true;
		ids.push_back(i);
		bool f = false;
		while (true) {
			cur = par[cur];
			if (used[cur]) {
				for (int id : ids) {
					cused[id] = false;
					used[id] = true;
				}
				break;
			}
			else if (cused[cur]) {
				f = true;
				rep(j, ids.size())if (ids[j] == cur) {
					ids.erase(ids.begin(), ids.begin() + j);
					break;
				}
				break;
			}
			else {
				cused[cur] = true;
				ids.push_back(cur);
			}
		}
		if (f) {
			ts = ids; break;
		}
	}
	if (ts.empty()) {
		vector<P> res; rep(i, n)if (exi[i] && i != root)res.push_back({ par[i],i });
		return res;
	}
	else {
		int cr = ts[0];
		vector<tval> mifr(n, INF), mito(n, INF);
		vector<int> idfr(n, -1), idto(n, -1);

		for (int id : ts) {
			for (edge e : G[id]) {
				if (e.cost < mito[e.to]) {
					mito[e.to] = e.cost;
					idto[e.to] = id;
				}
			}
			for (edge e : rG[id]) {
				if (e.cost - memo[id] < mifr[e.to]) {
					mifr[e.to] = e.cost - memo[id];
					idfr[e.to] = id;
				}
			}
		}

		vector<bool> nexi = exi;
		for (int id : ts) {
			nexi[id] = false;
			G[id].clear();
		}
		nexi[cr] = true;
		rep(i, n)if (i != cr && nexi[i]) {
			if (idfr[i] >= 0) {
				G[i].push_back({ cr,mifr[i] });
			}
			if (idto[i] >= 0) {
				G[cr].push_back({ i,mito[i] });
			}
		}
		vector<P> np = chu_liu_edmonds(G, nexi, root);
		int chk = -1;
		rep(i, np.size()) {
			if (np[i].second == cr) {
				chk = idfr[np[i].first];
				np[i].second = chk;
			}
			else if (np[i].first == cr) {
				np[i].first = idto[np[i].second];
			}
		}
		ts.push_back(ts[0]);
		rep(i, ts.size() - 1) {
			if (ts[i] != chk) {
				np.push_back({ ts[i + 1], ts[i] });
			}
		}
		return np;
	}
}
void solve() {
	int n, m; cin >> n >> m;
	vector<vector<edge>> G(n);
	vector<int> d(n);
	rep(i, m) {
		int a, b; cin >> a >> b;
		G[a].push_back({ b,0 });
		G[b].push_back({ a,1 });
		d[b]++;
	}
	vector<int> v0;
	rep(i, n)if (d[i] == 0)v0.push_back(i);
	vector<vector<int>> cost(v0.size(), vector<int>(v0.size()));
	vector<int> trans(n,-1);
	rep(i, v0.size())trans[v0[i]] = i;
	rep(i, v0.size()) {
		vector<int> dist(n,mod);
		priority_queue<P, vector<P>, greater<P>> q;
		dist[v0[i]] = 0; q.push({ 0,v0[i] });
		while (!q.empty()) {
			P p = q.top(); q.pop();
			int id = p.second;
			if (dist[id] < p.first)continue;
			for (edge e : G[id]) {
				int nd = p.first + e.cost;
				if (nd < dist[e.to]) {
					dist[e.to] = nd;
					q.push({ nd,e.to });
				}
			}
		}
		rep(j, v0.size())cost[i][j] = dist[v0[j]];
	}
	int ans = mod;
	vector<int> anss;
	
	rep(i, v0.size()) {
		vector<vector<edge>> nG(v0.size());
		rep(i, v0.size())rep(j, v0.size())if (i != j) {
			nG[i].push_back({ j,cost[i][j] });
			//cout << i << " " << j << " " << cost[i][j] << "\n";
		}
		vector<bool> exi(v0.size(), true);
		//cout << "? " << i << "\n";
		vector<P> vp = chu_liu_edmonds(nG, exi, i);
		int sum = 0;
		for (P p : vp) {
			sum += cost[p.first][p.second];
		}
		if (ans > sum) {
			ans = sum;
			anss = { v0[i] };
		}
		else if (ans == sum) {
			anss.push_back(v0[i]);
		}
	}
	cout << anss.size() << " " << ans << "\n";
	coutarray(anss);
}


signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(10);
	//init_f();
	//init();
	//while(true)
	//expr();
	//int t; cin >> t; rep(i, t)
	//while (cin >> n >> k,n)
	solve();
	return 0;
}
accuracy: 1
time_ms: 90
memory_kb: 18348
final_rank: 6

code_snippet: #include<bits/stdc++.h>
using namespace std;

#define rep(i,n) for(int i=0;i<(n);i++)
#define pb push_back
#define eb emplace_back
#define all(v) (v).begin(),(v).end()
#define fi first
#define se second
typedef vector<int>vint;
typedef pair<int,int>pint;
typedef vector<pint>vpint;

template<typename A,typename B>inline void chmin(A &a,B b){if(a>b)a=b;}
template<typename A,typename B>inline void chmax(A &a,B b){if(a<b)a=b;}

template<class A,class B>
ostream& operator<<(ostream& ost,const pair<A,B>&p){
	ost<<"{"<<p.first<<","<<p.second<<"}";
	return ost;
}

template<class T>
ostream& operator<<(ostream& ost,const vector<T>&v){
	ost<<"{";
	for(int i=0;i<v.size();i++){
		if(i)ost<<",";
		ost<<v[i];
	}
	ost<<"}";
	return ost;
}


using W=int;
using E=pair<W,int>;
struct Node{
	E e; 
	W put;
	Node *l,*r;
	Node(const E e=E()):e(e),put(0),l(nullptr),r(nullptr){}
	Node* push(){
		e.first+=put;
		if(l)l->put+=put;
		if(r)r->put+=put;
		put=0;
		return this;
	}
};
Node* merge(Node *a,Node *b){
	if(!a)return b;
	if(!b)return a;
	a->push();b->push();
	if(a->e>b->e)swap(a,b);
	a->r=merge(a->r,b);
	swap(a->l,a->r);
	return a;
}
Node pool[2222222];
int tail;

struct EHeap{
	Node* root;
	EHeap():root(nullptr){}
	void pop(){
		root->push();
		root=merge(root->l,root->r);
	}
	void push(E e){
		pool[tail]=Node(e);
		Node *p=&pool[tail++];
		root=merge(root,p);
	}
	void add(W a){
		if(root)root->put+=a;
	}
	E top(){
		return root->push()->e;
	}
	void meld(EHeap &eh){
		root=merge(root,eh.root);
	}
};


struct MinimumWeightArborescence{
	int n;
	vector<vector<E>>G;
	MinimumWeightArborescence(int n):n(n),G(n){}

	void addEdge(int a,int b,W c){
		G[a].emplace_back(c,b);
	}

	W calc(int r){
		tail=0;
		vector<int>par(n);iota(par.begin(),par.end(),0);
		function<int(int)>find=[&](int x){return x==par[x]?x:par[x]=find(par[x]);};
		
		vector<int>st(n);
		vector<EHeap>eh(n);
		
		for(int v=0;v<n;v++)for(auto &e:G[v])eh[e.second].push(E(e.first,v));
		
		st[r]=2;
		W ans=0;
		for(int i=0;i<n;i++){
			if(st[i])continue;
			int v=i;
			vector<E>es;
			
			while(st[v]!=2){
				st[v]=1;
				int u;W c;
				tie(c,u)=eh[v].top();eh[v].pop();
				u=find(u);
				if(u==v)continue;
				ans+=c;
				if(st[u]!=1){
					es.push_back(E(c,v));
					v=u;
					continue;
				}

				eh[v].add(-c);
				while(v!=u){
					int w;
					tie(c,w)=es.back();es.pop_back();
					eh[w].add(-c);
					eh[w].meld(eh[v]);	
					par[v]=u;
					v=w;
				}
			}
			for(auto &e:es)st[e.second]=2;
		}
		return ans;
	}
};


signed main(){
	int N,M;
	scanf("%d%d",&N,&M);
	MinimumWeightArborescence mwa(N);
	vint in(N);
	rep(i,M){
		int a,b;
		scanf("%d%d",&a,&b);
		mwa.addEdge(a,b,0);
		mwa.addEdge(b,a,1);
		in[b]++;
	}
	
	vpint lis;
	rep(i,N){
		if(in[i])continue;
		int tmp=mwa.calc(i);
		lis.eb(tmp,i);
	}
	sort(all(lis));
	vint ans;
	rep(i,lis.size())if(lis[i].fi==lis[0].fi)ans.pb(lis[i].se);
	printf("%d %d\n",(int)ans.size(),lis[0].fi);
	rep(i,ans.size()){
		if(i)printf(" ");
		printf("%d",ans[i]);
	}puts("");
	return 0;
}
accuracy: 1
time_ms: 1010
memory_kb: 75280
final_rank: 17

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}

struct SCC{
  vector<vector<int> > G,R;
  vector<int> vs,used,blg;
  SCC(){}
  SCC(int n):G(n),R(n),used(n),blg(n){}

  void add_edge(int u,int v){
    G[u].emplace_back(v);
    R[v].emplace_back(u);
  }

  void dfs(int v){
    used[v]=1;
    for(int u:G[v])
      if(!used[u]) dfs(u);
    vs.emplace_back(v);
  }

  void rdfs(int v,int k){
    used[v]=1;
    blg[v]=k;
    for(int u:R[v])
      if(!used[u]) rdfs(u,k);
  }

  int build(){
    int n=G.size();
    for(int v=0;v<n;v++)
      if(!used[v]) dfs(v);

    fill(used.begin(),used.end(),0);
    int k=0;
    for(int i=n-1;i>=0;i--)
      if(!used[vs[i]]) rdfs(vs[i],k++);
    return k;
  }

  int operator[](int i) const{return blg[i];};
};
//BEGIN CUT HERE
template<typename T>
struct Arborescence{
  struct edge{
    int to;
    T cost;
    edge(int to,T cost):to(to),cost(cost){}
  };
  vector<vector<edge>> B;

  Arborescence(int n):B(n){}

  void add_edge(int u,int v,T cost){
    assert(u!=v);
    B[u].emplace_back(v,cost);
  }

  T build(int r){
    T res=0;
    auto G=B;
    const T INF = numeric_limits<T>::max()/2;
    while(1){
      int n=G.size();
      vector<T> ws(n,INF);
      vector<int> rs(n,-1);
      for(int v=0;v<n;v++){
        for(edge &e:G[v]){
          if(e.cost<ws[e.to]){
            ws[e.to]=e.cost;
            rs[e.to]=v;
          }
        }
      }
      SCC scc(n);
      for(int i=0;i<n;i++){
        if(i==r) continue;
        scc.add_edge(rs[i],i);
        res+=ws[i];
      }
      int m=scc.build();
      if(m==n) break;
      vector<vector<edge>> H(m);
      for(int v=0;v<n;v++){
        for(auto &e:G[v]){
          if(scc[v]==scc[e.to]) continue;
          H[scc[v]].emplace_back(scc[e.to],e.cost-ws[e.to]);
        }
      }
      r=scc[r];
      G=H;
    }
    return res;
  }
};
//END CUT HERE

//INSERT ABOVE HERE
signed AOJ_GRL_2B(){
  int n,m,r;
  cin>>n>>m>>r;
  Arborescence<int> G(n);
  for(int i=0;i<m;i++){
    int s,t,w;
    cin>>s>>t>>w;
    G.add_edge(s,t,w);
  }
  cout<<G.build(r)<<endl;
  return 0;
}
/*
  verified on 2019/06/20
  http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_2_B&lang=jp
*/

signed AOJ_2309(){
  double v[111][111];
  double c[111][111];

  Int n,m;
  cin>>n>>m;
  for(Int i=0;i<m;i++)
    for(Int j=0;j<n;j++)
      cin>>v[i][j];

  for(Int i=0;i<m;i++){
    c[i][i]=0;
    for(Int j=0;j<n;j++) c[i][i]+=v[i][j]*v[i][j];
  }

  for(Int i=0;i<m;i++){
    for(Int j=0;j<m;j++){
      if(i==j) continue;
      if(c[j][j]==0){
        c[i][j]=c[i][i];
        continue;
      }
      double r=0;
      for(Int k=0;k<n;k++)
        r+=v[i][k]*v[j][k];
      r/=c[j][j];
      c[i][j]=0;
      for(Int k=0;k<n;k++)
        c[i][j]+=(v[i][k]-r*v[j][k])*(v[i][k]-r*v[j][k]);
    }
  }

  Arborescence<double> G(m+1);
  for(Int i=0;i<m;i++){
    G.add_edge(m,i,c[i][i]);
    for(Int j=0;j<m;j++){
      if(i==j) continue;
      G.add_edge(j,i,c[i][j]);
    }
  }
  cout<<fixed<<setprecision(12)<<G.build(m)<<endl;
  return 0;
}
/*
  verified on 2019/06/20
  http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2309
*/

signed AOJ_2647(){
  int n,m;
  cin>>n>>m;

  vector<vector<int>> G(n),R(n);
  for(int i=0;i<m;i++){
    int a,b;
    cin>>a>>b;
    G[a].emplace_back(b);
    R[b].emplace_back(a);
  }

  vector<int> vs;
  for(int i=0;i<n;i++)
    if(R[i].empty()) vs.emplace_back(i);

  int sz=vs.size();
  map<int, int> rev;
  for(int i=0;i<sz;i++) rev[vs[i]]=i;

  const int INF = 1e9;
  vector<vector<int>> H;
  for(int r:vs){
    vector<int> dp(n,INF);

    using P = pair<int, int>;
    deque<P> deq;

    dp[r]=0;
    deq.emplace_back(r,0);

    while(!deq.empty()){
      int v,d;
      tie(v,d)=deq.front();deq.pop_front();
      if(dp[v]<d) continue;
      for(int u:G[v]){
        if(dp[u]<=dp[v]) continue;
        dp[u]=dp[v];
        deq.emplace_front(u,dp[u]);
      }
      for(int u:R[v]){
        if(dp[u]<=dp[v]+1) continue;
        dp[u]=dp[v]+1;
        deq.emplace_back(u,dp[u]);
      }
    }

    vector<int> di(sz);
    for(int i=0;i<sz;i++) di[i]=dp[vs[i]];
    H.emplace_back(di);
  }

  int cost=INF;
  vector<int> ans;

  for(int i=0;i<sz;i++){
    Arborescence<int> arb(sz);
    for(int j=0;j<sz;j++)
      for(int k=0;k<sz;k++)
        if(j!=k) arb.add_edge(j,k,H[j][k]);

    int res=arb.build(i);
    if(res<cost) cost=res,ans.clear();
    if(res==cost) ans.emplace_back(vs[i]);
  }

  cout<<ans.size()<<" "<<cost<<endl;
  for(int i=0;i<(int)ans.size();i++){
    if(i) cout<<" ";
    cout<<ans[i];
  }
  cout<<endl;
  return 0;
}
/*
  verified on 2019/06/20
  http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2647
*/


signed main(){
  //AOJ_GRL_2B();
  //AOJ_2309();
  AOJ_2647();
  return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 4728
final_rank: 3

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}

struct SCC{
  int n;
  vector<vector<int> > G,R;
  vector<int> vs,used,blg;
  SCC(){}
  SCC(int n):G(n),R(n),used(n),blg(n){}

  void add_edge(int u,int v){
    G[u].emplace_back(v);
    R[v].emplace_back(u);
  }

  void dfs(int v){
    used[v]=1;
    for(int u:G[v])
      if(!used[u]) dfs(u);
    vs.emplace_back(v);
  }

  void rdfs(int v,int k){
    used[v]=1;
    blg[v]=k;
    for(int u:R[v])
      if(!used[u]) rdfs(u,k);
  }

  int build(){
    int n=G.size();
    for(int v=0;v<n;v++)
      if(!used[v]) dfs(v);

    fill(used.begin(),used.end(),0);
    int k=0;
    for(int i=n-1;i>=0;i--)
      if(!used[vs[i]]) rdfs(vs[i],k++);
    return k;
  }

  int operator[](int i) const{return blg[i];};
};
//BEGIN CUT HERE
template<typename T>
struct Arborescence{
  struct edge{
    int to;
    T cost;
    edge(int to,T cost):to(to),cost(cost){}
  };
  vector<vector<edge>> B;

  Arborescence(int n):B(n){}

  void add_edge(int u,int v,T cost){
    assert(u!=v);
    B[u].emplace_back(v,cost);
  }

  T build(int r){
    T res=0;
    auto G=B;
    const T INF = numeric_limits<T>::max()/2;
    while(1){
      int n=G.size();
      vector<T> ws(n,INF);
      vector<int> rs(n,-1);
      for(int v=0;v<n;v++){
        for(edge &e:G[v]){
          if(e.cost<ws[e.to]){
            ws[e.to]=e.cost;
            rs[e.to]=v;
          }
        }
      }
      SCC scc(n);
      for(int i=0;i<n;i++){
        if(i==r) continue;
        scc.add_edge(rs[i],i);
        res+=ws[i];
      }
      int m=scc.build();
      if(m==n) break;
      vector<vector<edge>> H(m);
      for(int v=0;v<n;v++){
        for(auto &e:G[v]){
          if(scc[v]==scc[e.to]) continue;
          H[scc[v]].emplace_back(scc[e.to],e.cost-ws[e.to]);
        }
      }
      r=scc[r];
      G=H;
    }
    return res;
  }
};
//END CUT HERE

//INSERT ABOVE HERE
signed AOJ_GRL_2B(){
  int n,m,r;
  cin>>n>>m>>r;
  Arborescence<int> G(n);
  for(int i=0;i<m;i++){
    int s,t,w;
    cin>>s>>t>>w;
    G.add_edge(s,t,w);
  }
  cout<<G.build(r)<<endl;
  return 0;
}
/*
  verified on 2019/06/20
  http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_2_B&lang=jp
*/

signed AOJ_2309(){
  double v[111][111];
  double c[111][111];

  Int n,m;
  cin>>n>>m;
  for(Int i=0;i<m;i++)
    for(Int j=0;j<n;j++)
      cin>>v[i][j];

  for(Int i=0;i<m;i++){
    c[i][i]=0;
    for(Int j=0;j<n;j++) c[i][i]+=v[i][j]*v[i][j];
  }

  for(Int i=0;i<m;i++){
    for(Int j=0;j<m;j++){
      if(i==j) continue;
      if(c[j][j]==0){
        c[i][j]=c[i][i];
        continue;
      }
      double r=0;
      for(Int k=0;k<n;k++)
        r+=v[i][k]*v[j][k];
      r/=c[j][j];
      c[i][j]=0;
      for(Int k=0;k<n;k++)
        c[i][j]+=(v[i][k]-r*v[j][k])*(v[i][k]-r*v[j][k]);
    }
  }

  Arborescence<double> G(m+1);
  for(Int i=0;i<m;i++){
    G.add_edge(m,i,c[i][i]);
    for(Int j=0;j<m;j++){
      if(i==j) continue;
      G.add_edge(j,i,c[i][j]);
    }
  }
  cout<<fixed<<setprecision(12)<<G.build(m)<<endl;
  return 0;
}
/*
  verified on 2019/06/20
  http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2309
*/

signed AOJ_2647(){
  int n,m;
  cin>>n>>m;

  vector<vector<int>> G(n),R(n);
  for(int i=0;i<m;i++){
    int a,b;
    cin>>a>>b;
    G[a].emplace_back(b);
    R[b].emplace_back(a);
  }

  vector<int> vs;
  for(int i=0;i<n;i++)
    if(R[i].empty()) vs.emplace_back(i);

  int sz=vs.size();
  map<int, int> rev;
  for(int i=0;i<sz;i++) rev[vs[i]]=i;

  const int INF = 1e9;
  vector<vector<int>> H;
  for(int r:vs){
    vector<int> dp(n,INF);

    using P = pair<int, int>;
    deque<P> deq;

    dp[r]=0;
    deq.emplace_back(r,0);

    while(!deq.empty()){
      int v,d;
      tie(v,d)=deq.front();deq.pop_front();
      if(dp[v]<d) continue;
      for(int u:G[v]){
        if(dp[u]<=dp[v]) continue;
        dp[u]=dp[v];
        deq.emplace_front(u,dp[u]);
      }
      for(int u:R[v]){
        if(dp[u]<=dp[v]+1) continue;
        dp[u]=dp[v]+1;
        deq.emplace_back(u,dp[u]);
      }
    }

    vector<int> di(sz);
    for(int i=0;i<sz;i++) di[i]=dp[vs[i]];
    H.emplace_back(di);
  }

  int cost=INF;
  vector<int> ans;

  for(int i=0;i<sz;i++){
    Arborescence<int> arb(sz);
    for(int j=0;j<sz;j++)
      for(int k=0;k<sz;k++)
        if(j!=k) arb.add_edge(j,k,H[j][k]);

    int res=arb.build(i);
    if(res<cost) cost=res,ans.clear();
    if(res==cost) ans.emplace_back(vs[i]);
  }

  cout<<ans.size()<<" "<<cost<<endl;
  for(int i=0;i<(int)ans.size();i++){
    if(i) cout<<" ";
    cout<<ans[i];
  }
  cout<<endl;
  return 0;
}
/*
  verified on 2019/06/20
  http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2647
*/


signed main(){
  //AOJ_GRL_2B();
  //AOJ_2309();
  AOJ_2647();
  return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 4672
final_rank: 2

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}

struct SCC{
  int n;
  vector<vector<int> > G,rG,T,C;
  vector<int> vs,used,blg;
  SCC(){}
  SCC(int n):n(n),G(n),rG(n),used(n),blg(n){}

  void add_edge(int from,int to){
    G[from].emplace_back(to);
    rG[to].emplace_back(from);
  }

  void dfs(int v){
    used[v]=1;
    for(int u:G[v])
      if(!used[u]) dfs(u);
    vs.emplace_back(v);
  }

  void rdfs(int v,int k){
    used[v]=1;
    blg[v]=k;
    C[k].emplace_back(v);
    for(int u:rG[v])
      if(!used[u]) rdfs(u,k);
  }

  int build(){
    for(int v=0;v<n;v++)
      if(!used[v]) dfs(v);

    fill(used.begin(),used.end(),0);
    int k=0;
    for(int i=vs.size()-1;i>=0;i--){
      if(!used[vs[i]]){
        T.emplace_back();
        C.emplace_back();
        rdfs(vs[i],k++);
      }
    }
    for(int v=0;v<n;v++)
      for(int u:G[v])
        if(blg[v]!=blg[u])
          T[blg[v]].push_back(blg[u]);

    for(int i=0;i<k;i++){
      sort(T[i].begin(),T[i].end());
      T[i].erase(unique(T[i].begin(),T[i].end()),T[i].end());
    }
    return k;
  }
  int operator[](int i) const{return blg[i];};
};
//BEGIN CUT HERE
template<typename T>
struct Arborescence{
  struct edge{
    int to;
    T cost;
    edge(int to,T cost):to(to),cost(cost){}
  };
  vector<vector<edge>> B;

  Arborescence(int n):B(n){}

  void add_edge(int u,int v,T cost){
    assert(u!=v);
    B[u].emplace_back(v,cost);
  }

  T build(int r){
    T res=0;
    auto G=B;
    const T INF = numeric_limits<T>::max()/2;
    while(1){
      int n=G.size();
      vector<T> ws(n,INF);
      vector<int> rs(n,-1);
      for(int v=0;v<n;v++){
        for(edge &e:G[v]){
          if(e.cost<ws[e.to]){
            ws[e.to]=e.cost;
            rs[e.to]=v;
          }
        }
      }
      SCC scc(n);
      for(int i=0;i<n;i++){
        if(i==r) continue;
        scc.add_edge(rs[i],i);
        res+=ws[i];
      }
      int m=scc.build();
      if(m==n) break;
      vector<vector<edge>> H(m);
      for(int v=0;v<n;v++){
        for(auto &e:G[v]){
          if(scc[v]==scc[e.to]) continue;
          H[scc[v]].emplace_back(scc[e.to],e.cost-ws[e.to]);
        }
      }
      r=scc[r];
      G=H;
    }
    return res;
  }
};
//END CUT HERE

//INSERT ABOVE HERE
signed AOJ_GRL_2B(){
  int n,m,r;
  cin>>n>>m>>r;
  Arborescence<int> G(n);
  for(int i=0;i<m;i++){
    int s,t,w;
    cin>>s>>t>>w;
    G.add_edge(s,t,w);
  }
  cout<<G.build(r)<<endl;
  return 0;
}
/*
  verified on 2019/06/20
  http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_2_B&lang=jp
*/

signed AOJ_2309(){
  double v[111][111];
  double c[111][111];

  Int n,m;
  cin>>n>>m;
  for(Int i=0;i<m;i++)
    for(Int j=0;j<n;j++)
      cin>>v[i][j];

  for(Int i=0;i<m;i++){
    c[i][i]=0;
    for(Int j=0;j<n;j++) c[i][i]+=v[i][j]*v[i][j];
  }

  for(Int i=0;i<m;i++){
    for(Int j=0;j<m;j++){
      if(i==j) continue;
      if(c[j][j]==0){
        c[i][j]=c[i][i];
        continue;
      }
      double r=0;
      for(Int k=0;k<n;k++)
        r+=v[i][k]*v[j][k];
      r/=c[j][j];
      c[i][j]=0;
      for(Int k=0;k<n;k++)
        c[i][j]+=(v[i][k]-r*v[j][k])*(v[i][k]-r*v[j][k]);
    }
  }

  Arborescence<double> G(m+1);
  for(Int i=0;i<m;i++){
    G.add_edge(m,i,c[i][i]);
    for(Int j=0;j<m;j++){
      if(i==j) continue;
      G.add_edge(j,i,c[i][j]);
    }
  }
  cout<<fixed<<setprecision(12)<<G.build(m)<<endl;
  return 0;
}
/*
  verified on 2019/06/20
  http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2309
*/

signed AOJ_2647(){
  int n,m;
  cin>>n>>m;

  vector<vector<int>> G(n),R(n);
  for(int i=0;i<m;i++){
    int a,b;
    cin>>a>>b;
    G[a].emplace_back(b);
    R[b].emplace_back(a);
  }

  vector<int> vs;
  for(int i=0;i<n;i++)
    if(R[i].empty()) vs.emplace_back(i);

  int sz=vs.size();
  map<int, int> rev;
  for(int i=0;i<sz;i++) rev[vs[i]]=i;

  const int INF = 1e9;
  vector<vector<int>> H;
  for(int r:vs){
    vector<int> dp(n,INF);

    using P = pair<int, int>;
    deque<P> deq;

    dp[r]=0;
    deq.emplace_back(r,0);

    while(!deq.empty()){
      int v,d;
      tie(v,d)=deq.front();deq.pop_front();
      if(dp[v]<d) continue;
      for(int u:G[v]){
        if(dp[u]<=dp[v]) continue;
        dp[u]=dp[v];
        deq.emplace_front(u,dp[u]);
      }
      for(int u:R[v]){
        if(dp[u]<=dp[v]+1) continue;
        dp[u]=dp[v]+1;
        deq.emplace_back(u,dp[u]);
      }
    }

    vector<int> di(sz);
    for(int i=0;i<sz;i++) di[i]=dp[vs[i]];
    H.emplace_back(di);
  }

  int cost=INF;
  vector<int> ans;

  for(int i=0;i<sz;i++){
    Arborescence<int> arb(sz);
    for(int j=0;j<sz;j++)
      for(int k=0;k<sz;k++)
        if(j!=k) arb.add_edge(j,k,H[j][k]);

    int res=arb.build(i);
    if(res<cost) cost=res,ans.clear();
    if(res==cost) ans.emplace_back(vs[i]);
  }

  cout<<ans.size()<<" "<<cost<<endl;
  for(int i=0;i<(int)ans.size();i++){
    if(i) cout<<" ";
    cout<<ans[i];
  }
  cout<<endl;
  return 0;
}
/*
  verified on 2019/06/20
  http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2647
*/


signed main(){
  //AOJ_GRL_2B();
  //AOJ_2309();
  AOJ_2647();
  return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 4736
final_rank: 4

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}



//Without merge technique
struct UnionFind{
  Int n;
  vector<Int> r,p;
  UnionFind(){}
  UnionFind(Int sz):n(sz),r(sz,1),p(sz,0){iota(p.begin(),p.end(),0);}
  Int find(Int x){
    return (x==p[x]?x:p[x]=find(p[x]));
  }
  bool same(Int x,Int y){
    return find(x)==find(y);
  }
  void unite(Int x,Int y){
    x=find(x);y=find(y);
    if(x==y) return;
    r[x]+=r[y];
    p[y]=x;
  }
};

template<typename T, typename E>
struct SkewHeap{
  using G = function<T(T,E)>;
  using H = function<E(E,E)>;
  using C = function<bool(T,T)>;
  G g;
  H h;
  C c;
  T INF;
  E ei;
  SkewHeap(G g,H h,C c,T INF,E ei):g(g),h(h),c(c),INF(INF),ei(ei){}
  
  struct Node{
    Node *l,*r;
    T val;
    E add;
    Node(T val,E add):val(val),add(add){l=r=nullptr;}
  };

  void eval(Node *a){
    if(a==nullptr) return;
    if(a->add==ei) return;
    if(a->l) a->l->add=h(a->l->add,a->add);
    if(a->r) a->r->add=h(a->r->add,a->add);
    a->val=g(a->val,a->add);
    a->add=ei;
  }
  
  T top(Node *a){
    return a!=nullptr?g(a->val,a->add):INF;
  }

  T snd(Node *a){
    eval(a);
    return a!=nullptr?min(top(a->l),top(a->r)):INF;
  }

  Node* add(Node *a,E d){
    if(a!=nullptr) a->add=h(a->add,d);
    return a;
  }
  
  Node* push(T v){
    return new Node(v,ei);
  }
  
  Node* meld(Node *a,Node *b){
    if(!a||!b) return a?a:b;
    if(c(top(a),top(b))) swap(a,b);
    eval(a);
    a->r=meld(a->r,b);
    swap(a->l,a->r);
    return a;
  }
  
  Node* pop(Node* a){
    eval(a);
    auto res=meld(a->l,a->r);
    delete a;
    return res;
  }
  
};

//INSERT ABOVE HERE
template<typename T>
struct Arborescence{
  typedef pair<T, Int> P;
  using Heap = SkewHeap<P, T>;
  
  struct edge{
    Int from,to;
    T cost;
    edge(){}
    edge(Int from,Int to,T cost):from(from),to(to),cost(cost){}
  };
  
  Int n;
  P INF;
  UnionFind uf;
  vector<edge> edges;
  vector<typename Heap::Node*> come;
  vector<Int> used,from;
  vector<T> cost;
  
  Arborescence(Int n,T INF):n(n),INF(INF,-1),uf(n),come(n,NULL),
                            used(n,0),from(n,-1),cost(n,-1){};

  void add_edge(Int from,Int to,T cost){
    edges.emplace_back(from,to,cost);
  }
  
  T build(Int r){
    typename Heap::G g=[](P a,T b){return P(a.first+b,a.second);};
    typename Heap::H h=[](T a,T b){return a+b;};
    typename Heap::C c=[](P a,P b){return a>b;};
    Heap heap(g,h,c,INF,0);
  
    used[r]=2;
    for(Int i=0;i<(Int)edges.size();i++){
      edge &e=edges[i];
      come[e.to]=heap.meld(come[e.to],heap.push(P(e.cost,i)));
    }
    
    T res=0;
    for(Int i=0;i<n;i++){
      if(used[i]) continue;
      Int v=i;
      vector<Int> l;
      while(used[v]!=2){
        used[v]=1;
        l.emplace_back(v);
        if(!come[v]) return T(-1);
        from[v]=uf.find(edges[come[v]->val.second].from);
        cost[v]=heap.top(come[v]).first;
        come[v]=heap.pop(come[v]);
        if(from[v]==v) continue;
	
        res+=cost[v];
        if(used[from[v]]==1){
          Int p=v;
          do{
            if(come[p]!=nullptr) heap.add(come[p],-cost[p]);
            if(p!=v){
              uf.unite(v,p);
              come[v]=heap.meld(come[v],come[p]);
            }
            p=uf.find(from[p]);
          }while(p!=v);
        }else{
          v=from[v];
        }
      }
      for(Int u:l) used[u]=2;
    }
    return res;
  }
  
};

//INSERT ABOVE HERE
signed main(){
  Int n,m;
  cin>>n>>m;
  
  vector<vector<Int> > G(n),R(n);
  for(Int i=0;i<m;i++){
    Int a,b;
    cin>>a>>b;
    G[a].emplace_back(b);
    R[b].emplace_back(a);
  }

  vector<Int> vs;
  for(Int i=0;i<n;i++)
    if(R[i].empty()) vs.emplace_back(i);

  Int sz=vs.size();
  map<Int, Int> rev;
  for(Int i=0;i<sz;i++) rev[vs[i]]=i;

  const Int INF = 1e15;
  vector<vector<Int> > H;
  for(Int r:vs){
    vector<Int> dp(n,INF);
    
    using P = pair<Int, Int>;
    deque<P> deq;
    
    dp[r]=0;
    deq.emplace_back(r,0);
    
    while(!deq.empty()){
      Int v,d;
      tie(v,d)=deq.front();deq.pop_front();
      if(dp[v]<d) continue;
      for(Int u:G[v]){
        if(dp[u]<=dp[v]) continue;
        dp[u]=dp[v];
        deq.emplace_front(u,dp[u]);        
      }
      for(Int u:R[v]){
        if(dp[u]<=dp[v]+1) continue;
        dp[u]=dp[v]+1;
        deq.emplace_back(u,dp[u]);        
      }
    }
    
    vector<Int> di(sz);
    for(Int i=0;i<sz;i++) di[i]=dp[vs[i]];
    H.emplace_back(di);
  }  

  Int cost=INF;
  vector<Int> ans;

  for(Int i=0;i<sz;i++){
    Arborescence<Int> arb(sz,INF);
    for(Int j=0;j<sz;j++)
      for(Int k=0;k<sz;k++)
        arb.add_edge(j,k,H[j][k]);
    
    Int res=arb.build(i);
    if(res<cost) cost=res,ans.clear();    
    if(res==cost) ans.emplace_back(vs[i]);
  }  
  
  cout<<ans.size()<<" "<<cost<<endl;
  for(Int i=0;i<(Int)ans.size();i++){
    if(i) cout<<" ";
    cout<<ans[i];
  }
  cout<<endl;
  return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 9816
final_rank: 5

code_snippet: #include<iomanip>
#include<limits>
#include<thread>
#include<utility>
#include<iostream>
#include<string>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<queue>
#include<cmath>
#include<numeric>
#include<cassert>
#include<random>
#include<chrono>
#include<unordered_set>
#include<unordered_map>
#include<fstream>
#include<list>
#include<functional>
#include<bitset>
#include<complex>
#include<tuple>
using namespace std;
typedef unsigned long long int ull;
typedef long long int ll;
typedef pair<ll,ll> pll;
typedef long double D;
#define F first
#define S second
const ll E=1e18+7;
const ll MOD=1000000007;

int main(){
    ll n,m;
    cin>>n>>m;
    vector<vector<ll>> Edge(n);
    vector<vector<ll>> Rev(n);
    vector<ll> A;
    queue<ll> Q;
    vector<ll> cnt(n,0);
    unordered_map<ll,ll> M;
    for(int i=0;i<m;i++){
        ll a,b;
        cin>>a>>b;
        Edge[a].push_back(b);
        Rev[b].push_back(a);
        cnt[b]++;
    }
    for(int i=0;i<n;i++){
        if(cnt[i]==0){Q.push(i);}
    }
    while(!Q.empty()){
        ll w=Q.front(); Q.pop();
        A.push_back(w);
        for(auto &I:Edge[w]){
            cnt[I]--;
            if(cnt[I]==0){Q.push(I);}
        }
    }
    assert(A.size()==n);
    for(int i=0;i<n;i++){M[A[i]]=i;}
    vector<ll> ans(n,E);
    ll mi=E;
    for(int i=0;i<n;i++){
        if(Rev[i].empty()){
            ans[i]=0;
            vector<bool> used(n,false);
            vector<bool> in(n,false);
            priority_queue<pll,vector<pll>,greater<pll>> Q;
            function<void(ll)> dfs=[&](ll w){
                used[w]=true;
                for(auto &I:Edge[w]){
                    if(!used[I]){dfs(I);}
                }
                for(auto &I:Rev[w]){
                    if(!used[I] && !in[I]){in[I]=true; Q.push({M[I],I});}
                }
            };
            dfs(i);
            while(!Q.empty()){
                pll W=Q.top(); Q.pop();
                if(!used[W.S]){used[W.S]=true; ans[i]++; dfs(W.S);}
            }
            mi=min(mi,ans[i]);
            for(int i=0;i<n;i++){assert(used[i]);}
        }
    }
    assert(mi!=E);
    vector<ll> node;
    for(int i=0;i<n;i++){
        if(ans[i]==mi){node.push_back(i);}
    }
    cout<<node.size()<<" "<<mi<<endl;
    for(int i=0;i<node.size();i++){cout<<node[i]<<(i+1==node.size()?"\n":" ");}
    
    
    
    
    return 0;
}
accuracy: 0.5
time_ms: 20
memory_kb: 4752
final_rank: 20