#include <stdio.h>
#include <string.h>
#include <vector>
#include <algorithm>
using namespace std;
#define CLEAR(x) memset(x, 0, sizeof(x))
#define NMax 32768
int N, M, uz[NMax], timp[NMax], t, ctc, comp[NMax], rad;
int up[16][NMax], nivel[NMax], lg[NMax], bst;
int get_high[16][NMax], highest[NMax], dep[NMax], t_in[NMax], t_out[NMax];
vector<int> G[NMax], GT[NMax];
int cmp_nodes(const int& a, const int& b)//Functia pentru sortarea listelor de adiacenta in functie de sortarea topologica
{ return t_out[a] > t_out[b]; }
void df1(int nod)// Primul DFS (Kosaraju) pentru determinarea CTC
{
int i, sz, x;
uz[nod] = 1;
for (sz = G[nod].size(), i = 0; i < sz; ++i)
if (!uz[x = G[nod][i]])
df1(x);
timp[++t] = nod;
}
void df2(int nod)// Al doilea DFS (Kosaraju) pentru determinarea CTC
{
int i, size, x;
uz[nod] = 1; comp[nod] = ctc;
for (size = GT[nod].size(), i = 0; i < size; ++i)
if (!uz[x = GT[nod][i]])
df2(x);
}
int det_root(void)//Determinarea radacinii lui G* (nodul cu gradul de intrare 0)
{
int i, j, sz;
CLEAR(uz);
for (i = 1; i <= N; ++i)
for (sz = GT[i].size(), j = 0; j < sz; ++j)
uz[GT[i][j]] = 1;
for (i = 1; i <= N; ++i)
if (!uz[i])
return i;
return -1; // should never arrive here
}
void df_time(int nod)//Sortarea Topologica a lui G*
{
int i, sz, x;
uz[nod] = 1;
for (sz = GT[nod].size(), i = 0; i < sz; ++i)
if (!uz[x = GT[nod][i]])
df_time(x);
t_out[nod] = (++t);
}
void df3(int nod)//Se construieste vectorul de nivel si vectorul de tati(puteri a lui 2) pentru fiecare nod
{
int i, sz, x;
uz[nod] = 1;
for (i = 0; ; ++i)
{
if (!up[i][ up[i][nod] ]) break;
up[i+1][nod] = up[i][ up[i][nod] ];
}
for (sz = GT[nod].size(), i = 0; i < sz; ++i)
if (!uz[x = GT[nod][i]])
{
up[0][x] = nod;
nivel[x] = nivel[nod] + 1;
df3(x);
}
}
int LCA(int x, int y)
{
for (; nivel[x] > nivel[y]; x = up[ lg[nivel[x]-nivel[y]] ][x]);
for (; nivel[y] > nivel[x]; y = up[ lg[nivel[y]-nivel[x]] ][y]);
if (x == y) return x;
int log;
for (log = lg[nivel[x]]; log >= 0; --log)
if (up[log][x] != up[log][y])
x = up[log][x],
y = up[log][y];
if (x != y) x = up[0][x];
return x;
}
void df4(int nod)
{
int i, sz, x;
uz[nod] = 1;
for (sz = GT[nod].size(), i = 0; i < sz; ++i)
if (!uz[x = GT[nod][i]])
{
df4(x);
if (nivel[ highest[x] ] < nivel[ highest[nod] ])
highest[nod] = highest[x];
}
}
void df5(int nod)
{
int i, sz, x;
for (i = 0; ; ++i)
{
if (!get_high[i][ get_high[i][nod] ]) break;
get_high[i+1][nod] = get_high[i][ get_high[i][nod] ];
}
uz[nod] = 1;
for (sz = G[nod].size(), i = 0; i < sz; ++i)
if (!uz[x = G[nod][i]])
{
get_high[0][x] = nod;
dep[x] = dep[nod] + 1;
df5(x);
}
}
void df6(int nod)
{
int i, sz, x;
uz[nod] = 1; t_in[nod] = (++t);
for (sz = GT[nod].size(), i = 0; i < sz; ++i)
if (!uz[x = GT[nod][i]])
df6(x);
t_out[nod] = (++t);
}
int stramos(int x, int y)
{ return t_in[x] <= t_in[y] && t_out[y] <= t_out[x]; }
int main(void)
{
int T, i, j, k, sz, log;
freopen("obiective.in", "r", stdin);
freopen("obiective.out", "w", stdout);
//Citire
scanf("%d %d", &N, &M);
for (; M; --M)
{
scanf("%d %d", &i, &j);
G[i].push_back(j);//Construire Graf
GT[j].push_back(i);//Construire Graf Transpus (pentru Kosaraju)
}
//Primul DFS pentru CTC (Kosaraju) Se construieste vectorul de timpi timp[i] pentru DFS 2
for (i = 1; i <= N; ++i)
if (!uz[i])
df1(i);
//Al doilea DFS pentru CTC (Kosaraju) Se stabileste pentru fiecare nod carei componente conexe ii apartine comp[nod]
CLEAR(uz);// Componentele conexe sunt in ordinea sortarii topologice datorita DFS 1
for (i = N; i; --i)
if (!uz[j = timp[i]])
{
++ctc;
df2(j);
}
for (i = 1; i <= N; ++i)//Se refoloseste GT pentru a forma graful G* (graful componentelor tare conexe)
GT[i].clear();
for (i = 1; i <= N; ++i)
for (sz = G[i].size(), j = 0; j < sz; ++j)//GT va contine doar muchiile dintre componentele tare conexe
if (comp[i] != comp[G[i][j]])//Fiecarui nod x din G ii corespunde nodul comp[x] din GT
GT[comp[i]].push_back( comp[G[i][j]] );//Astfel GT are N=ctc noduri
N = ctc;
//rad = det_root(); //Se afla radacina lui G* (nodul care are gradul de intrare 0)
rad=1;
t = 0;
CLEAR(uz);
df_time(rad);//Sortarea Topologica a lui G(G este aciclic) pornind din radacina rad
for (i = 1; i <= N; ++i)//Se sorteaza listele de adiacenta conform sortarii topologice DF_TIME
sort(GT[i].begin(), GT[i].end(), cmp_nodes);
CLEAR(uz);
df3(rad);//Se construieste vectorul up (tatii puteri ai lui 2) pentru fiecare nod
for (i = 2; i< NMax; ++i)
lg[i] = lg[i/2]+1;
for (i = 1; i <= N; ++i)//Se initializeaza vectorul highest cu vectorul de tati
highest[i] = up[0][i];
for (i = 1; i <= N; ++i)
for (sz = GT[i].size(), j = 0; j < sz; ++j)
if (up[0][ GT[i][j] ] != i)
{
if (nivel[i] < nivel[ highest[ GT[i][j] ] ])
highest[ GT[i][j] ] = i;
}
CLEAR(uz);
df4(rad);
for (i = 1; i <= N; ++i)//Refolosesc G pentru a construi arborele final
G[i].clear();
for (i = 1; i <= N; ++i)
{
if (!highest[i]) continue;
G[highest[i]].push_back(i);//Vectorul highest este vectorul de tati pentru arbore
}
CLEAR(uz);
df5(rad);
t = 0;
CLEAR(uz);
CLEAR(t_out);
df6(rad);
for (scanf("%d", &T); T; --T)
{
scanf("%d %d", &i, &j);
i = comp[i]; j = comp[j];
if (i == j)
{
printf("0\n");
continue;
}
k = LCA(i, j);
if (i == k)
{
printf("0\n");
continue;
}
j = i;
if(dep[i]==dep[k]+1)
printf("1\n");
else
printf("%d\n",dep[j]-dep[k]);
}
return 0;
}