#include <cstdio>  //{{{
#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <map>
#include <algorithm>

#define ALL(c) (c).begin(), (c).end()
#define DUMP(x) std::cerr << #x << ':' << x << '\n';

typedef long long ll;
// clang-format off
template<typename T,typename U>inline bool chmax(T&x,U a){if(x>=a)return 0;x=a;return 1;}
template<typename T,typename U>inline bool chmin(T&x,U a){if(x<=a)return 0;x=a;return 1;}
inline int in(){int x;scanf("%d", &x);return x;}
// clang-format on
// }}}

//{{{ graph.hpp
#ifndef INCLUDE_GRAPH_HPP
#define INCLUDE_GRAPH_HPP
#include <vector>
#include <climits>
namespace orliv {
namespace graph {
struct Edge {
  typedef int weight_type;
  static constexpr weight_type INF =
      std::numeric_limits<weight_type>::max() - 100;

  int from, to;
  weight_type w;
  Edge(int from, int to, weight_type w = 1) : from(from), to(to), w(w) {}
  bool operator<(const Edge& rhs) const {
    if (w != rhs.w) return w > rhs.w;
    if (from != rhs.from) return from < rhs.from;
    return to < rhs.to;
  }
};

typedef Edge::weight_type Weight;
typedef std::vector<Edge> Edges;
typedef std::vector<Weight> Weights;
typedef std::vector<int> Path;
typedef std::vector<int> Nodes;
}
typedef std::vector<graph::Edges> Graph;
}
#endif
//}}}
//{{{ scc.cc
#ifndef INCLUDE_GRAPH_HPP
#include "graph.hpp"
#endif
#include <stack>

namespace orliv {
namespace graph {
namespace scc_internal {
struct SCCImpl {
  const Graph& G;
  int k;
  std::vector<int> ord, low;
  std::stack<int> stack;
  std::vector<bool> instack;
  std::vector<Nodes> scc;
  SCCImpl(const Graph& g)
      : G(g), k(0), ord(g.size(), -1), low(g.size()), instack(g.size()) {}
  std::vector<Nodes> get() {
    for (int v = 0; v < G.size(); v++) {
      if (ord[v] >= 0) continue;
      dfs(v);
    }
    return std::move(scc);
  }

 private:
  void dfs(int v) {
    ord[v] = low[v] = k++;
    stack.push(v);
    instack[v] = true;
    for (const auto& e : G[v]) {
      int u = e.to;
      if (ord[u] < 0) {
        dfs(u);
        low[v] = std::min(low[v], low[u]);
      } else if (instack[u]) {
        low[v] = std::min(low[v], ord[u]);
      }
    }
    if (low[v] != ord[v]) return;

    scc.emplace_back();
    while (1) {
      int u = stack.top();
      stack.pop();
      instack[u] = false;
      scc.back().emplace_back(u);
      if (v == u) break;
    }
  }
};
}
std::vector<Nodes> scc(const Graph& g) {
  return std::move(scc_internal::SCCImpl(g).get());
}
}
}
//}}}

using namespace std;

// clang-format off
struct UnionFind {
  mutable vector<int> par;
  UnionFind(int N) : par(N, -1) {}
  int root(int x) const { return par[x] >= 0 ? par[x] = root(par[x]) : x; }
  bool same(int x, int y) const { return root(x) == root(y); }
  bool unite(int x, int y) {
    x = root(x), y = root(y);
    if (x == y) return false;
    if (par[x] > par[y]) swap(x, y);
    par[x] += par[y];
    par[y] = x;
    return true;
  }
};

// clang-format on
int main() {
  int V = in(), E = in();
  orliv::Graph g(V);
  for (int i = 0; i < E; i++) {
    int s = in(), t = in();
    g[s].emplace_back(s, t);
  }
  auto scc = orliv::graph::scc(g);
  UnionFind uf(V);
  for (const auto& nodes : scc) {
    int v = nodes[0];
    for (const auto& u : nodes) {
      uf.unite(v, u);
    }
  }
  int Q = in();
  for (int i = 0; i < Q; i++) {
    int u = in(), v = in();
    if (uf.same(u, v)) {
      cout << 1 << endl;
    } else {
      cout << 0 << endl;
    }
  }
  return 0;
}

Measured memory_bytes: 2760