#define _CRT_SECURE_NO_WARNINGS
//#define _GLIBCXX_DEBUG
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef pair<int,int> pii;
#define all(c) (c).begin(), (c).end()
#define loop(i,a,b) for(ll i=a; i<ll(b); i++)
#define rep(i,b) loop(i,0,b)
#define pb push_back
#define eb emplace_back
#define mp make_pair
#define mt make_tuple
template<class T> istream& operator>>(istream& is, vector<T>& v);
template<class T> ostream& operator<<(ostream& os, vector<T> const& v);
template<int n, class...T> typename enable_if<(n>=sizeof...(T))>::type _ot(ostream&, const tuple<T...>&){}
template<int n, class...T> typename enable_if<(n< sizeof...(T))>::type _ot(ostream& os, const tuple<T...>& t){ os << (n==0?"":" ") << get<n>(t); _ot<n+1>(os, t); }
template<class...T> ostream& operator<<(ostream& os, const tuple<T...>& t){ _ot<0>(os, t); return os; }
template<int n, class...T> typename enable_if<(n>=sizeof...(T))>::type _it(istream&, tuple<T...>&){}
template<int n, class...T> typename enable_if<(n< sizeof...(T))>::type _it(istream& is, tuple<T...>& t){ is >> get<n>(t); _it<n+1>(is, t); }
template<class...T> istream& operator>>(istream& is, tuple<T...>& t){ _it<0>(is, t); return is; }
template<class T> istream& operator>>(istream& is, vector<T>& v){ rep(i,v.size()) is >> v[i]; return is; }
template<class T> ostream& operator<<(ostream& os, vector<T> const& v){ rep(i,v.size()) os << v[i] << (i+1==(int)v.size()?"":" "); return os; }
#ifdef DEBUG
#define dump(...) (cerr<<#__VA_ARGS__<<" = "<<mt(__VA_ARGS__)<<" ["<<__LINE__<<"]"<<endl)
#else
#define dump(...)
#endif

typedef int Weight;
struct Edge {
    int src, dst;
    Weight weight;
    Edge(int src, int dst, Weight weight) :
        src(src), dst(dst), weight(weight) { }
};
bool operator < (const Edge &e, const Edge &f) {
    return e.weight != f.weight ? e.weight > f.weight : // !!INVERSE!!
        e.src != f.src ? e.src < f.src : e.dst < f.dst;
}
typedef vector<Edge> Edges;
typedef vector<Edges> Graph;
typedef vector<Weight> Array;
typedef vector<Array> Matrix;

/*
  Kosaraju 法で強連結成分分解(SCC)
  gは隣接リスト表現のグラフ, sccs の各要素に連結成分が入る
*/
int const MAX_N = 100000;
void visit(Graph const & g, int v, vector<vi> & scc, int S[MAX_N], int & sz,
           int inS[MAX_N], int low[MAX_N], int num[MAX_N], int & time) {
    low[v] = num[v] = ++time;
    S[sz++] = v;
    inS[v] = true;
    for(auto const & e : g[v]){
        int w = e.dst;
        if(num[w] == 0) {
            visit(g, w, scc, S, sz, inS, low, num, time);
            low[v] = min(low[v], low[w]);
        } else if(inS[w])
            low[v] = min(low[v], num[w]);
    }
    if(low[v] == num[v]) {
        scc.push_back(vi());
        while(1) {
            int w = S[--sz];
            inS[w] = false;
            scc.back().push_back(w);
            if(v == w) break;
        }
    }
}

vector<vi> scc(Graph const & g) {
    vector<vi> sccs;
    const int n = g.size();
    static int num[MAX_N], low[MAX_N], inS[MAX_N], S[MAX_N];
    rep(i,n) num[i] = low[i] = inS[i] = 0;
    int sz = 0, time = 0;
    rep(u, n) if (num[u] == 0) visit(g, u, sccs, S, sz, inS, low, num, time);
    return sccs;
}

int main(){
    int n,m;
    cin >> n >> m;
    Graph g(n);
    rep(i,m){
        int s,t;
        cin >> s >> t;
        g[s].eb(s,t,0);
    }
    auto sc = scc(g);
    vi v(n);
    rep(i,sc.size())rep(j,sc[i].size()) v[sc[i][j]] = i;
    int q;
    cin >> q;
    rep(i,q){
        int a,b; cin >> a >> b;
        cout << (v[a]==v[b]) << endl;
    }
}

Measured memory_bytes: 3932