Problem:
Strongly Connected Components

A direced graph is strongly connected if every two nodes are reachable from each other. In a strongly connected component of a directed graph, every two nodes of the component are mutually reachable.

Input

A directed graph G(V, E) and a sequence of queries where each query contains a pair of nodes u and v.

|V| |E|
s0 t0
s1 t1
:
s|E|-1 t|E|-1
Q
u0 v0
u1 v1
:
uQ-1 vQ-1

|V| is the number of nodes and |E| is the number of edges in the graph. The graph nodes are named with the numbers 0, 1,..., |V|-1 respectively.

si and ti represent source and target nodes of i-th edge (directed).

ui and vi represent a pair of nodes given as the i-th query.

Output

For each query, pinrt "1" if the given nodes belong to the same strongly connected component, "0" otherwise.

Constraints

1 ≤ |V| ≤ 10,000

0 ≤ |E| ≤ 30,000

1 ≤ Q ≤ 100,000

Sample Input 1

5 6
0 1
1 0
1 2
2 4
4 3
3 2
4
0 1
0 3
2 3
3 4

Sample Output 1

1
0
1
1

Solution in Kotlin (judge verdict: Accepted)


import java.util.*

class UnionFindTree{
    private var mParent:UnionFindTree? = null
    private fun Parent():UnionFindTree {
        return when(mParent) {
            null -> this
            else -> {
                mParent = mParent!!.Parent()
                mParent !!
            }
        }
    }
    fun Join(other:UnionFindTree):Unit {
        if (!IsSameUnion(other)){
            Parent().mParent = other.Parent()
        }
    }
    fun IsSameUnion(other:UnionFindTree):Boolean = Parent() == other.Parent()
}
data class Edge(val from:Node, val to:Node)
class Node(val Id:Int){
    private var mForwardEdges: LinkedList<Node> = LinkedList()
    private var mReverseEdges: LinkedList<Node> = LinkedList()
    fun ForwardEdges():LinkedList<Node> = mForwardEdges
    fun ReverseEdges():LinkedList<Node> = mReverseEdges
    fun AddEdge(edge:Edge):Unit {
        val (from, to) = edge
        when{
            from == this -> mForwardEdges.push(to)
            to == this -> mReverseEdges.push(from)
        }
    }
}
fun StackedDFS(current:Node, numArray: Array<Int>, init:Int):Int {
    val stack = Stack<Node>().apply{push(current)}
    var i = init
    while (!stack.empty()){
        when(numArray[stack.peek().Id]) {
            -1 -> {
                numArray[stack.peek().Id] = 0//DFSで訪問済み
                stack.peek().ForwardEdges().forEach { if (numArray[it.Id] == -1) stack.push(it) }//新たな訪問先を設定
            }
            0 -> {//ロールバックで再度訪問
                i += 1
                numArray[stack.peek().Id] = i
                stack.pop()
            }
            else -> stack.pop()
        }
    }
    return i
}
fun StackedInvDFS(current:Node, uft:Array<UnionFindTree>, isSearched: Array<Boolean>, numArray: Array<Int>, start:Int):Unit{
    val stack = Stack<Node>().apply{push(current)}
    while (!stack.empty()){
        when(isSearched[stack.peek().Id]){
            true -> stack.pop()
            false -> {
                isSearched[stack.peek().Id] = true
                stack.pop().ReverseEdges().forEach {
                    when(!isSearched[it.Id] && start > numArray[it.Id]){
                        true -> {
                            uft[current.Id].Join(uft[it.Id])
                            stack.push(it)
                        }
                    }
                }
            }
        }
    }
}

fun main(args:Array<String>):Unit{
    val (v, e) = readLine()!!.split(' ').map(String::toInt)
    val nodes = Array(v){Node(it)}
    for (i in 0 until e){
        val (from, to) = readLine()!!.split(' ').map(String::toInt)
        val edge = Edge(nodes[from], nodes[to])
        edge.from.AddEdge(edge)
        edge.to.AddEdge(edge)
    }
    val nums = Array(v){-1}
    nodes.fold(0){ init, node ->
        if (nums[node.Id] == -1)
            StackedDFS(node, nums, init)
        else
            init
    }
    val isSearched = Array(v){false}
    val uft = Array(v){UnionFindTree()}
    nums.withIndex().sortedByDescending { it.value }.map {
        nodes[it.index]
    }.forEach { node ->
        if (!isSearched[node.Id]){
            StackedInvDFS(node, uft, isSearched, nums, nums[node.Id])
        }
    }
    for (i in 0 until readLine()!!.toInt()){
        val (a, b) = readLine()!!.split(' ').map(String::toInt)
        println(if (uft[a].IsSameUnion(uft[b])) 1 else 0)
    }
}