#include <algorithm>
#include <array>
#include <cassert>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <numeric>
#include <queue>
#include <stack>
#include <string>
#include <utility>
#include <vector>
#define FOR(i,a,b) for (int i=(a),for_##i##_max=(b);i<=(for_##i##_max);++i)
#define RFOR(i,a,b) for (int i=(a),rfor_##i##_min=(b);i>=(rfor_##i##_min);--i)
#define REP(i,n) for (int i=0,rep_##i##_len=(n);i<(rep_##i##_len);++i)
#define RREP(i,n) for (int i=(n)-1;i>=0;--i)

namespace { // Basics

template<typename T>
void chmin(T &x, T y) {
  x = std::min(x, y);
}

template<typename T>
void chmax(T &x, T y) {
  x = std::max(x, y);
}

using lli = long long int;
using ld = long double;

} // namespace

namespace { // Graph Basics

template<typename WeightT>
struct Edge {
  int from, to;
  WeightT weight;
  Edge(int s, int d, WeightT w): from(s), to(d), weight(w) {}
};

template<typename WeightT>
bool
operator< (Edge<WeightT> const &lhs, Edge<WeightT> const &rhs) {
  if (lhs.weight != rhs.weight) {
    return lhs.weight < rhs.weight;
  } else if (lhs.from != rhs.from) {
    return lhs.from < rhs.from;
  }
  return lhs.to < rhs.to;
}

template<typename WeightT>
using Edges = std::vector<Edge<WeightT> >;

template<typename WeightT>
using AdjacencyList = std::vector<Edges<WeightT> >;

template<typename WeightT>
void
add_undir_edge(AdjacencyList<WeightT> &graph, int u, int v, WeightT w) {
  graph[u].emplace_back(u, v, w);
  graph[v].emplace_back(v, u, w);
}

template<typename WeightT>
AdjacencyList<WeightT>
inverse_graph(AdjacencyList<WeightT> const &G) {
  size_t const n = G.size();
  AdjacencyList<WeightT> F(n);
  for (size_t i = 0; i < n; ++i) {
    for (auto &&e: G[i]) {
      F[e.to].emplace_back(e.to, e.from, e.weight);
    }
  }
  return F;
}

} // namespace

namespace { // Strongnly Connected Components

struct SccResult {
  std::vector<int> top_index;
  std::vector<std::vector<int> > components;
};


template<typename T>
SccResult
kosaraju_scc(AdjacencyList<T> const &G) {
  int const N = G.size();

  // 1st DFS
  std::vector<bool> used(N, false);
  std::stack<int> order1;
  for (int s = 0; s < N; ++s) {
    if (used[s]) { continue; }
    std::stack<int> nodes;
    std::stack<bool> flags; // 0:visit, 1:index
    nodes.push(s); flags.push(0);
    while (!nodes.empty()) {
      auto const u = nodes.top(); nodes.pop();
      auto const is_visited = flags.top(); flags.pop();
      if (is_visited) {
        order1.push(u);
        continue;
      }
      if (used[u]) { continue; }
      used[u] = true;
      nodes.push(u); flags.push(1);
      for (auto &&e: G[u]) {
        nodes.push(e.to); flags.push(0);
      }
    }
  }

  // 2nd DFS
  auto const rG = inverse_graph(G);
  std::fill(begin(used), end(used), false);
  std::vector<int> order(N);
  std::vector<std::vector<int>> components;
  int top_index = 0;
  while (!order1.empty()) {
    auto const s = order1.top(); order1.pop();
    if (used[s]) { continue; }
    std::vector<int> scc;
    std::stack<int> stk; stk.push(s);
    while (!stk.empty()) {
      auto const u = stk.top(); stk.pop();
      if (used[u]) { continue; }
      used[u] = true;
      order[u] = top_index;
      scc.push_back(u);
      for (auto &&e: rG[u]) {
        stk.push(e.to);
      }
    }
    ++top_index;
    components.push_back(std::move(scc));
  }
  return { order, components };
}

} // namespace

using namespace std;

using Graph = AdjacencyList<bool>;

int main() {
  // cout << fixed << setprecision(10);

  int V, E;
  scanf("%d %d", &V, &E);
  Graph G(V);
  REP(i, E) {
    int S, T;
    scanf("%d %d", &S, &T);
    G[S].emplace_back(S, T, true);
  }
  auto const scc = kosaraju_scc(G);

  int Q;
  scanf("%d", &Q);
  REP(i, Q) {
    int U, V;
    scanf("%d %d", &U, &V);
    bool const same = (scc.top_index[U] == scc.top_index[V]);
    printf("%d\n", same? 1 : 0);
  }
  return 0;
}



Measured memory_bytes: 4204