← Home
package main

import (
	"bufio"
	"bytes"
	"io"
	"math/bits"
	"os"
	"strconv"
)

type Edge struct {
	to int
	id int
}

func main() {
	data, _ := io.ReadAll(os.Stdin)
	idx := 0
	nextInt := func() int {
		for idx < len(data) && (data[idx] < '0' || data[idx] > '9') {
			idx++
		}
		val := 0
		for idx < len(data) && data[idx] >= '0' && data[idx] <= '9' {
			val = val*10 + int(data[idx]-'0')
			idx++
		}
		return val
	}

	n := nextInt()
	m := nextInt()

	g := make([][]Edge, n+1)
	U := make([]int, m)
	V := make([]int, m)

	for i := 0; i < m; i++ {
		u := nextInt()
		v := nextInt()
		U[i] = u
		V[i] = v
		g[u] = append(g[u], Edge{v, i})
		g[v] = append(g[v], Edge{u, i})
	}

	tin := make([]int, n+1)
	low := make([]int, n+1)
	iter := make([]int, n+1)
	parent := make([]int, n+1)
	parentE := make([]int, n+1)
	isBridge := make([]bool, m)

	timer := 0
	st := make([]int, 0, n)

	for s := 1; s <= n; s++ {
		if tin[s] != 0 {
			continue
		}
		parent[s] = 0
		parentE[s] = -1
		st = append(st[:0], s)
		for len(st) > 0 {
			v := st[len(st)-1]
			if tin[v] == 0 {
				timer++
				tin[v] = timer
				low[v] = timer
			}
			if iter[v] < len(g[v]) {
				e := g[v][iter[v]]
				iter[v]++
				if e.id == parentE[v] {
					continue
				}
				to := e.to
				if tin[to] == 0 {
					parent[to] = v
					parentE[to] = e.id
					st = append(st, to)
				} else {
					if tin[to] < low[v] {
						low[v] = tin[to]
					}
				}
			} else {
				st = st[:len(st)-1]
				if parent[v] != 0 {
					p := parent[v]
					if low[v] < low[p] {
						low[p] = low[v]
					}
					if low[v] > tin[p] {
						isBridge[parentE[v]] = true
					}
				}
			}
		}
	}

	tree := make([][]int, n+1)
	weights := make([]int64, n+1)

	visited := make([]bool, n+1)
	compStack := make([]int, 0, n)
	verts := make([]int, 0)

	for s := 1; s <= n; s++ {
		if visited[s] {
			continue
		}
		visited[s] = true
		compStack = append(compStack[:0], s)
		verts = verts[:0]
		edgeInc := 0

		for len(compStack) > 0 {
			v := compStack[len(compStack)-1]
			compStack = compStack[:len(compStack)-1]
			verts = append(verts, v)
			for _, e := range g[v] {
				if isBridge[e.id] {
					continue
				}
				edgeInc++
				to := e.to
				if !visited[to] {
					visited[to] = true
					compStack = append(compStack, to)
				}
			}
		}

		if edgeInc > 0 {
			tree = append(tree, nil)
			weights = append(weights, int64(edgeInc/2))
			bnode := len(tree) - 1
			for _, v := range verts {
				tree[bnode] = append(tree[bnode], v)
				tree[v] = append(tree[v], bnode)
			}
		}
	}

	for i := 0; i < m; i++ {
		if isBridge[i] {
			u := U[i]
			v := V[i]
			tree[u] = append(tree[u], v)
			tree[v] = append(tree[v], u)
		}
	}

	N := len(tree) - 1

	parent0 := make([]int, N+1)
	depth := make([]int, N+1)
	psum := make([]int64, N+1)
	seenTree := make([]bool, N+1)

	st = append(st[:0], 1)
	seenTree[1] = true
	parent0[1] = 1

	for len(st) > 0 {
		v := st[len(st)-1]
		st = st[:len(st)-1]
		for _, to := range tree[v] {
			if seenTree[to] {
				continue
			}
			seenTree[to] = true
			parent0[to] = v
			depth[to] = depth[v] + 1
			psum[to] = psum[v] + weights[to]
			st = append(st, to)
		}
	}

	LOG := bits.Len(uint(N))
	up := make([][]int, LOG)
	up[0] = parent0
	for k := 1; k < LOG; k++ {
		up[k] = make([]int, N+1)
		prev := up[k-1]
		cur := up[k]
		for v := 1; v <= N; v++ {
			cur[v] = prev[prev[v]]
		}
	}

	lca := func(a, b int) int {
		if depth[a] < depth[b] {
			a, b = b, a
		}
		diff := depth[a] - depth[b]
		k := 0
		for diff > 0 {
			if diff&1 == 1 {
				a = up[k][a]
			}
			diff >>= 1
			k++
		}
		if a == b {
			return a
		}
		for j := LOG - 1; j >= 0; j-- {
			if up[j][a] != up[j][b] {
				a = up[j][a]
				b = up[j][b]
			}
		}
		return up[0][a]
	}

	q := nextInt()
	var out bytes.Buffer
	for i := 0; i < q; i++ {
		a := nextInt()
		b := nextInt()
		l := lca(a, b)
		ans := psum[a] + psum[b] - 2*psum[l] + weights[l]
		out.WriteString(strconv.FormatInt(ans, 10))
		out.WriteByte('\n')
	}

	w := bufio.NewWriterSize(os.Stdout, 1<<20)
	w.Write(out.Bytes())
	w.Flush()
}