Problem:
アカ・ベコ捕獲作戦

怪盗アカ・ベコは大胆にも、ツルガジョーから銀のシャチホコを盗み去った。警部であるあなたは、アカ・ベコが仲間のコボウ氏にシャチホコを渡すらしいという情報を手に入れた。ただ、コボウ氏はアカ・ベコのアジトまで出向けないので、アジトの外で渡すらしい。あなたはアカ・ベコを待ち伏せして捕まえることにした。この町は古い城下町なので、道が複雑に入り組んでいて、どの道も一方通行になっている。アカ・ベコがアジトから受け渡し場所までどの経路を通るのかはわからないが、人員不足のため、待ち伏せ場所は１つに設定しなければならない。

あなたは、アジトを含むいくつかの地点を選び、それらをつなぐ道を調べ、地図を作った。地図上の地点のどこかで受け渡しが行われるらしい。受け渡し場所が判明次第、以下のように待ち伏せ場所を選ぶ。

アジトは危険なのでアジト以外の地点。

アカ・ベコがアジトから受け渡し場所までどのような経路を通っても必ず通る地点。

1, 2 の両方を満たす地点のうち、受け渡し場所にたどり着くまでに通過しなければならない地点の数がより少ない地点。ただし、コボウ氏に見つからないようにするために、1, 2 を満たす地点が他にない場合のみ、受け渡し場所を待ち伏せ場所にする。

アジトと待ち伏せ場所の候補からなる地点をつなぐ道の情報のあとに、質問として受け渡し場所が複数入力されたとき、それぞれの受け渡し場所について待ち伏せ場所を出力するプログラムを作成してください。

入力

入力は１つのデータセットからなる。入力データは以下の形式で与えられる。

N M
s1 t1
:
sM tM
Q
r1
:
rQ

１行目は２つの整数からなる。N (3 ≤ N ≤ 100000) は地点の数、M(N-1 ≤ M ≤ 300000) は地図に書いたすべての道の数を表す。続く M 行に隣り合った地点の間を直接つなぐ道が与えられる。si と ti (1 ≤ si ≠ ti ≤ N) は i 番目の道のそれぞれ始点、終点となる地点の番号を表す。ただし、アジトの番号は1とし、アジトからはすべての地点へ到達できる。

続く１行に質問の数 Q(1 ≤ Q < N ) が与えられる。続く Q 行に質問が与えられる。i 番目の質問として、受け渡し場所の番号 ri (2 ≤ ri ≤ N) が与えられる。

出力

質問ごとに、待ち伏せ場所の番号を１行に出力する。

入出力例

入力例 1

6 7
1 2
2 3
1 3
1 4
4 5
5 6
6 1
5
2
3
4
5
6

出力例 1

2
3
4
4
5

入力例 2

11 15
1 2
1 3
1 4
2 5
3 6
3 7
3 9
4 7
4 10
4 11
6 2
6 8
7 9
8 11
9 6
10
6
2
10
8
9
3
5
11
4
7

出力例 2

6
2
4
6
9
3
2
11
4
7

Solution in C (judge verdict: Accepted)

// AOJ 0294 Catch a Thief
// 2018.2.14 
// Lengauer-Tarjan algorithm? 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX 100002
#define MAGIC 150
int par[MAX], m[MAX];
int parent[MAX], vertex[MAX];
int semi[MAX], idom[MAX], U[MAX];
int **b_to, b_hi[MAX];
int *g_to[MAX], g_hi[MAX], _g_hi[MAX];
int *r_to[MAX], r_hi[MAX], _r_hi[MAX];
int tbl[300002][2];

int find(int v) { int r;
	if (par[v] == v) return v;
	r = find(par[v]);
	if (semi[m[v]] > semi[m[par[v]]]) m[v] = m[par[v]];
	return par[v] = r;
}
int eval(int v) { find(v); return m[v]; }
void link(int x, int y) { par[y] = x; }

void tree(int n)
{
	int id, i, j, w, u, v;
	int *q; int top;
	
	for (i = 0; i < n; i++) par[i] = m[i] = i, semi[i] = -1;

	q = malloc(150000*sizeof(int));
	id = 0, q[0] = 0, top = 1;
	while (top) {
		v = q[--top];
		if (semi[v] >= 0) continue;
		semi[v] = id;
		vertex[id++] = v;
		for (i = g_hi[v]-1; i >= 0; i--) {
			u = g_to[v][i];
			if (semi[u] < 0) {
				parent[u] = v;
				q[top++] = u;
			}
		}
	}
	free(q);

	b_to = malloc(n*sizeof(int *));
	b_to[0] = malloc(25000*sizeof(int));
	for (i = 1; i < n; i++) b_to[i] = malloc(MAGIC*sizeof(int));

	b_to[0][0] = 0, u = 25000;
	for (i = 1; i < n; i++) for (j = 0; j < MAGIC; j++) {
		b_to[i][j] = u, u += MAGIC;
	}

	for (i = n-1; i > 0; i--) {
		w = vertex[i];
		for (j = 0; j < r_hi[w]; j++) {
			v = r_to[w][j];
			u = eval(v);
			if (semi[w] > semi[u]) semi[w] = semi[u];
		}
		v = vertex[semi[w]];
		b_to[v][b_hi[v]++] = w;
		u = parent[w];
		for (j = 0; j < b_hi[u]; j++) {
			v = b_to[u][j];
			U[v] = eval(v);
		}
		b_hi[u] = 0;
		link(u, w);
	}
//	free(b_to);

	for (i = 1; i < n; i++) {
		w = vertex[i];
		u = U[w];
		if (semi[w] == semi[u]) idom[w] = semi[w];
		else idom[w] = idom[u];
	}
	for (i = 1; i < n; i++) {
		w = vertex[i];
		idom[w] = vertex[idom[w]];
	}
}

//#define getchar_unlocked()  getchar()
int in()
{
	int n = 0;
	int c = getchar_unlocked();
	do n = (n<<3)+(n<<1) + (c & 0xf), c = getchar_unlocked();
	while (c >= '0');
	return n;
}

int main()
{
	int n, m, i, s, t, q, r;
	
	n = in(), m = in();
	for (i = 0; i < m; i++) {
		s = in()-1, t = in()-1;
		tbl[i][0] = s, tbl[i][1] = t;
		_g_hi[s]++, _r_hi[t]++;
	}
	for (i = 0; i < n; i++) {
		g_to[i] = malloc(_g_hi[i] << 2);
		r_to[i] = malloc(_r_hi[i] << 2);
	}
	for (i = 0; i < m; i++) {
		s = tbl[i][0], t = tbl[i][1];
		g_to[s][g_hi[s]++] = t;
		r_to[t][r_hi[t]++] = s;
	}

	tree(n);

	q = in();
	while (q--) {
		r = in()-1;
		if (!idom[r]) printf("%d\n", r+1);
		else          printf("%d\n", idom[r]+1);
	}
	return 0;
}