#[allow(unused_imports)]
use std::io::{stdin, Read, StdinLock};
#[allow(unused_imports)]
use std::cmp::{max, min, Ordering};
#[allow(unused_imports)]
use std::str::FromStr;
#[allow(unused_imports)]
use std::collections::{HashSet, HashMap, BinaryHeap};
#[allow(unused_imports)]
use std::vec::Vec;

#[allow(dead_code)]
const INF: i32 = 1000_000_000;
#[allow(dead_code)]
const INFLL: i64 = 1000_000_000_000_000_000;
#[allow(dead_code)]
const EPS: f64 = 1.0e-10;
#[allow(dead_code)]
const MOD: i32 = 1000_000_007;

struct Scanner<'a> {
    cin: StdinLock<'a>,
}

impl<'a> Scanner<'a> {
    #[allow(dead_code)]
    fn new(cin: StdinLock<'a>) -> Scanner<'a> {
        Scanner {cin: cin}
    }

    #[allow(dead_code)]
    fn read1<T: FromStr>(&mut self) -> Option<T> {
        let token = self.cin.by_ref().bytes().map(|c| c.unwrap() as char)
                    .skip_while(|c| c.is_whitespace())
                    .take_while(|c| !c.is_whitespace())
                    .collect::<String>();
        token.parse::<T>().ok()
    }

    #[allow(dead_code)]
    fn read<T: FromStr>(&mut self) -> T {
        self.read1().unwrap()
    }
}

trait Edge {
    fn from(&self) -> usize;
    fn to(&self) -> usize;
}

#[allow(dead_code)]
#[derive(Eq, PartialEq, PartialOrd, Clone)]
struct WeightedEdge {
    from: usize,
    to: usize,
    weight: i32,
}

impl Edge for WeightedEdge {
    fn from(&self) -> usize {
        self.from
    }
    fn to(&self) -> usize {
        self.to
    }
}

#[allow(dead_code)]
impl WeightedEdge {
    fn new(from: usize, to: usize, weight: i32) -> WeightedEdge {
        WeightedEdge {
            from: from,
            to: to,
            weight: weight
        }
    }
}

impl Ord for WeightedEdge {
    fn cmp(&self, other: &WeightedEdge) -> Ordering {
        if self.weight > other.weight {
            Ordering::Greater
        } else if self.weight < other.weight {
            Ordering::Less
        } else {
            Ordering::Equal
        }
    }
}


/// Graph Trait
trait Graph<E: Edge> {
    fn edges(&self, v: usize) -> &std::vec::Vec<E>;
    fn node_size(&self) -> usize;
}

/// Weighted (Adjacent List) Graph
#[derive(Clone)]
struct WeightedGraph {
    adj_list: std::vec::Vec<std::vec::Vec<WeightedEdge>>,
}

#[allow(dead_code)]
impl WeightedGraph {
    fn new(n: usize) -> WeightedGraph {
        WeightedGraph {
            adj_list: vec![std::vec::Vec::<WeightedEdge>::new(); n],
        }
    }

    fn add_edge(&mut self, from: usize, to: usize, w: i32) {
        self.adj_list[from].push(WeightedEdge::new(from, to, w));
    }
}

impl Graph<WeightedEdge> for WeightedGraph {
    fn edges(&self, v: usize) -> &std::vec::Vec<WeightedEdge> {
        &self.adj_list[v]
    }

    fn node_size(&self) -> usize {
        self.adj_list.len()
    }
}


fn scc_dfs<E: Edge>(g: &Graph<E>, v: usize, vs: &mut Vec<usize>, used: &mut Vec<bool>) {
    used[v] = true;
    for e in g.edges(v) {
        if !used[e.to()] {
            scc_dfs(g, e.to(), vs, used);
        }
    }
    vs.push(v);
}

fn scc_rdfs(rg: &Vec<Vec<usize>>, v: usize, k: usize, comp: &mut Vec<usize>, used: &mut Vec<bool>) {
    used[v] = true;
    comp[v] = k;
    for &to in &rg[v] {
        if !used[to] {
            scc_rdfs(rg, to, k, comp, used);
        }
    }
}

struct StronglyConnectedComponent<E: Edge, G: Graph<E> + Clone> {
    g: G,
    comp: Vec<usize>,
    k: usize,

    phantom: std::marker::PhantomData<E>,
}

#[allow(dead_code)]
impl<E: Edge, G: Graph<E> + Clone> StronglyConnectedComponent<E, G> {
    fn new(g: &G) -> StronglyConnectedComponent<E, G> {
        let mut rg: Vec<Vec<usize>> = vec![Vec::<usize>::new(); g.node_size()];
        for v in 0..g.node_size() {
            for e in g.edges(v) {
                rg[e.to()].push(e.from());
            }
        }

        let mut used: Vec<bool> = vec![false; g.node_size()];
        let mut vs: Vec<usize> = Vec::new();
        for v in 0..g.node_size() {
            if !used[v] {
                scc_dfs(g, v, &mut vs, &mut used);
            }
        }
        used = used.into_iter().map(|_x| false).collect();
        let mut k = 0;
        let mut comp: Vec<usize> = vec![0; g.node_size()];
        for &v in vs.iter().rev() {
            if !used[v] {
                scc_rdfs(&rg, v, k, &mut comp, &mut used);
                k += 1;
            }
        }

        StronglyConnectedComponent::<E, G> {
            g: g.clone(),
            comp: comp,
            k: k,
            phantom: std::marker::PhantomData,
        }
    }

    fn belongs(&self, v: usize) -> usize {
        self.comp[v]
    }

    fn build_graph(&self) -> Vec<Vec<usize>> {
        use std::collections::HashSet;
        let k = self.k;
        let mut s: Vec<HashSet<usize>> = vec![HashSet::<usize>::new(); k];
        let mut res: Vec<Vec<usize>> = vec![Vec::<usize>::new(); k];
        for v in 0..self.g.node_size() {
            for e in self.g.edges(v) {
                s[self.belongs(v)].insert(self.belongs(e.to()));
            }
        }
        for i in 0..k {
            for &j in &s[i] {
                if i != j {
                    res[i].push(j);
                }
            }
        }
        res
    }
}

fn main() {
    let cin = stdin();
    let cin = cin.lock();
    let mut sc = Scanner::new(cin);

    let n: usize = sc.read();
    let m: usize = sc.read();
    let mut g: WeightedGraph = WeightedGraph::new(n);
    for _i in 0..m {
        let s: usize = sc.read();
        let t: usize = sc.read();
        g.add_edge(s, t, 0);
    }
    let scc = StronglyConnectedComponent::new(&g);
    let q: usize = sc.read();
    for _i in 0..q {
        let u: usize = sc.read();
        let v: usize = sc.read();
        if scc.belongs(u) == scc.belongs(v) {
            println!("1");
        } else {
            println!("0");
        }
    }
}


Measured memory_bytes: 7692