There are $n$ cities in Berland and some pairs of them are connected by two-way roads. It is guaranteed that you can pass from any city to any other, moving along the roads. Cities are numerated from $1$ to $n$.

Two fairs are currently taking place in Berland — they are held in two different cities $a$ and $b$ ($1 \le a, b \le n$; $a \ne b$).

Find the number of pairs of cities $x$ and $y$ ($x \ne a, x \ne b, y \ne a, y \ne b$) such that if you go from $x$ to $y$ you will have to go through both fairs (the order of visits doesn't matter). Formally, you need to find the number of pairs of cities $x,y$ such that any path from $x$ to $y$ goes through $a$ and $b$ (in any order).

Print the required number of pairs. The order of two cities in a pair does not matter, that is, the pairs $(x,y)$ and $(y,x)$ must be taken into account only once.


-----Input-----

The first line of the input contains an integer $t$ ($1 \le t \le 4\cdot10^4$) — the number of test cases in the input. Next, $t$ test cases are specified.

The first line of each test case contains four integers $n$, $m$, $a$ and $b$ ($4 \le n \le 2\cdot10^5$, $n - 1 \le m \le 5\cdot10^5$, $1 \le a,b \le n$, $a \ne b$) — numbers of cities and roads in Berland and numbers of two cities where fairs are held, respectively.

The following $m$ lines contain descriptions of roads between cities. Each of road description contains a pair of integers $u_i, v_i$ ($1 \le u_i, v_i \le n$, $u_i \ne v_i$) — numbers of cities connected by the road.

Each road is bi-directional and connects two different cities. It is guaranteed that from any city you can pass to any other by roads. There can be more than one road between a pair of cities.

The sum of the values of $n$ for all sets of input data in the test does not exceed $2\cdot10^5$. The sum of the values of $m$ for all sets of input data in the test does not exceed $5\cdot10^5$.


-----Output-----

Print $t$ integers — the answers to the given test cases in the order they are written in the input.


-----Example-----
Input
3
7 7 3 5
1 2
2 3
3 4
4 5
5 6
6 7
7 5
4 5 2 3
1 2
2 3
3 4
4 1
4 2
4 3 2 1
1 2
2 3
4 1

Output
4
0
1

Difficulty: HARD

Solutions:
from sys import stdout
printn = lambda x: stdout.write(x)
inn = lambda : int(input())
inl = lambda : list(map(int, input().split()))
inm = lambda : map(int, input().split())
DBG = True and False
BIG = 999999999
R = 10 ** 9 + 7

def ddprint(x):
	if DBG:
		print(x)
t = inn()
for _ in range(t):
	(n, m, a, b) = inm()
	a -= 1
	b -= 1
	dst = [[] for i in range(n)]
	for i in range(m):
		(u, v) = inm()
		dst[u - 1].append(v - 1)
		dst[v - 1].append(u - 1)
	c = [0] * n
	c[a] = 1
	c[b] = 1
	for x in dst[a]:
		if c[x] == 1:
			continue
		q = [x]
		while len(q) > 0:
			y = q.pop()
			if c[y] == 1:
				continue
			c[y] = 1
			for z in dst[y]:
				if c[z] == 0:
					q.append(z)
	ddprint(c)
	nb = n - sum(c)
	c = [0] * n
	c[a] = 1
	c[b] = 1
	for x in dst[b]:
		if c[x] == 1:
			continue
		q = [x]
		while len(q) > 0:
			y = q.pop()
			if c[y] == 1:
				continue
			c[y] = 1
			for z in dst[y]:
				if c[z] == 0:
					q.append(z)
	ddprint(c)
	na = n - sum(c)
	print(na * nb)


from collections import defaultdict, deque
import sys, heapq, bisect, math, itertools, string, queue, copy, time
sys.setrecursionlimit(10 ** 8)
INF = float('inf')
mod = 10 ** 9 + 7
eps = 10 ** (-7)

def inp():
	return int(sys.stdin.readline())

def inpl():
	return list(map(int, sys.stdin.readline().split()))

def inpl_str():
	return list(sys.stdin.readline().split())

class UnionFind:

	def __init__(self, N):
		self.table = [i for i in range(N)]
		self.rank = [1 for i in range(N)]
		self.size = [1 for i in range(N)]

	def Find(self, x):
		if self.table[x] == x:
			return x
		else:
			self.table[x] = self.Find(self.table[x])
			self.size[x] = self.size[self.table[x]]
			return self.table[x]

	def Unite(self, x, y):
		(x, y) = (self.Find(x), self.Find(y))
		(sx, sy) = (self.Size(x), self.Size(y))
		if x == y:
			return
		if self.rank[x] > self.rank[y]:
			self.table[y] = x
			self.size[x] = sx + sy
		else:
			self.table[x] = y
			self.size[y] = sx + sy
			if self.rank[x] == self.rank[y]:
				self.rank[y] += 1

	def Check(self, x, y):
		return self.Find(x) == self.Find(y)

	def Size(self, x):
		return self.size[self.Find(x)]
for _ in range(inp()):
	(N, M, a, b) = inpl()
	a -= 1
	b -= 1
	(a, b) = (min(a, b), max(a, b))
	UF = UnionFind(N)
	alines = []
	blines = []
	for _ in range(M):
		(s, t) = inpl()
		s -= 1
		t -= 1
		(s, t) = (min(s, t), max(s, t))
		if s == a and t == b:
			continue
		elif s == a:
			alines.append(t)
		elif t == a:
			alines.append(s)
		elif s == b:
			blines.append(t)
		elif t == b:
			blines.append(s)
		else:
			UF.Unite(s, t)
	aconnects = set()
	acnts = [0] * N
	bcnts = [0] * N
	for a in alines:
		r = UF.Find(a)
		aconnects.add(r)
		acnts[r] = UF.Size(r)
	for b in blines:
		r = UF.Find(b)
		if r in aconnects:
			acnts[r] = 0
		else:
			bcnts[r] = UF.Size(r)
	print(sum(acnts) * sum(bcnts))


import sys
input = sys.stdin.readline
from collections import deque
t = int(input())
for testcaess in range(t):
	(n, m, a, b) = list(map(int, input().split()))
	E = [[] for i in range(n + 1)]
	for i in range(m):
		(x, y) = list(map(int, input().split()))
		E[x].append(y)
		E[y].append(x)
	USE1 = [0] * (n + 1)
	Q = deque()
	Q.append(a)
	USE1[a] = 1
	while Q:
		x = Q.pop()
		for to in E[x]:
			if to == b:
				continue
			if USE1[to] == 0:
				USE1[to] = 1
				Q.append(to)
	USE2 = [0] * (n + 1)
	Q = deque()
	Q.append(b)
	USE2[b] = 1
	while Q:
		x = Q.pop()
		for to in E[x]:
			if to == a:
				continue
			if USE2[to] == 0:
				USE2[to] = 1
				Q.append(to)
	ANS1 = 0
	ANS2 = 0
	for i in range(n + 1):
		if i == a or i == b:
			continue
		if USE1[i] == 1 and USE2[i] == 0:
			ANS1 += 1
		elif USE1[i] == 0 and USE2[i] == 1:
			ANS2 += 1
	print(ANS1 * ANS2)


import os, sys
from io import BytesIO, IOBase
from collections import deque

def bfs(n, path, st, exclude):
	curr = deque([st])
	visi = [1] + [0] * n
	(visi[st], visi[exclude]) = (1, 1)
	while len(curr):
		x = curr.popleft()
		for y in path[x]:
			if visi[y]:
				continue
			curr.append(y)
			visi[y] = 1
	return visi.count(0)

def main():
	for _ in range(int(input())):
		(n, m, a, b) = map(int, input().split())
		path = [[] for _ in range(n + 1)]
		for _ in range(m):
			(u1, v1) = map(int, input().split())
			path[u1].append(v1)
			path[v1].append(u1)
		print(bfs(n, path, a, b) * bfs(n, path, b, a))
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
main()


import sys
from collections import defaultdict

def dfs(start, graph, b):
	vis = defaultdict(int)
	a = set()
	q = [start]
	vis[start] = 1
	while q:
		cur = q.pop()
		for i in graph[cur]:
			if vis[i] == 0 and i != b:
				a.add(i)
				vis[i] = 1
				q.append(i)
	return a
t = int(sys.stdin.readline())
for _ in range(t):
	(n, m, a, b) = map(int, sys.stdin.readline().split())
	graph = defaultdict(list)
	for i in range(m):
		(u, v) = map(int, sys.stdin.readline().split())
		graph[u].append(v)
		graph[v].append(u)
	seta = dfs(a, graph, b)
	setb = dfs(b, graph, a)
	setc = seta.intersection(setb)
	seta = seta - setc
	setb = setb - setc
	ans = len(seta) * len(setb)
	print(ans)


from collections import defaultdict, deque
from itertools import permutations
from sys import stdin, stdout
from bisect import bisect_left, bisect_right
from copy import deepcopy
import sys
int_input = lambda : int(stdin.readline())
string_input = lambda : stdin.readline()
multi_int_input = lambda : map(int, stdin.readline().split())
multi_input = lambda : stdin.readline().split()
list_input = lambda : list(map(int, stdin.readline().split()))
string_list_input = lambda : list(string_input())
MOD = pow(10, 9) + 7
test = int_input()
set1 = []
n = 0

def dfs(graph, start, forbidden):
	Stack = [start]
	result = set([])
	visited = [False] * (n + 1)
	while Stack:
		children = Stack.pop()
		for items in graph[children]:
			if items == forbidden or visited[items]:
				continue
			else:
				visited[items] = True
				result.add(items)
				Stack.append(items)
	return result - {start}
for _ in range(test):
	(n, m, a, b) = multi_int_input()
	graph = {}
	for i in range(1, n + 1):
		graph[i] = []
	for i in range(m):
		(u, v) = multi_int_input()
		graph[u].append(v)
		graph[v].append(u)
	result1 = dfs(graph, a, b)
	result2 = dfs(graph, b, a)
	print(len(result1 - result2) * len(result2 - result1))


import sys
input = sys.stdin.buffer.readline

def dfs(start, end):
	visited = [0 for i in range(n + 1)]
	stack = [start]
	while stack:
		start = stack.pop()
		if start == end or visited[start]:
			continue
		visited[start] = 1
		for i in graph[start]:
			if visited[i] == 0:
				stack.append(i)
	return visited
for _ in range(int(input())):
	(n, m, a, b) = map(int, input().split())
	graph = [[] for i in range(n + 1)]
	for i in range(m):
		(x, y) = map(int, input().split())
		graph[x].append(y)
		graph[y].append(x)
	vis = dfs(a, b)
	vis2 = dfs(b, a)
	(ans1, ans2) = (0, 0)
	for i in range(1, n + 1):
		if i == a or i == b:
			continue
		if vis[i] and (not vis2[i]):
			ans1 += 1
		if not vis[i] and vis2[i]:
			ans2 += 1
	print(ans1 * ans2)


import heapq
import math
from collections import *
from functools import reduce, cmp_to_key
import sys
input = sys.stdin.readline
M = mod = 10 ** 9 + 7

def factors(n):
	return sorted(list(set(reduce(list.__add__, ([i, n // i] for i in range(1, int(n ** 0.5) + 1) if n % i == 0)))))

def inv_mod(n):
	return pow(n, mod - 2, mod)

def li():
	return [int(i) for i in input().rstrip('\n').split(' ')]

def st():
	return input().rstrip('\n')

def val():
	return int(input())
ispath = False

def dfs(node, endnode, g):
	global ispath
	stack = [node]
	while stack:
		currnode = stack.pop()
		if currnode == endnode:
			dfs.takepath = False
			ispath = True
		else:
			dfs.visited.add(currnode)
			dfs.currset.add(currnode)
			for j in g[currnode]:
				if j not in dfs.visited:
					stack.append(j)
for _ in range(val()):
	(n, m, a, b) = li()
	g = defaultdict(list)
	ispath = False
	for i in range(m):
		(x, y) = li()
		g[x].append(y)
		g[y].append(x)
	dfs.visited = set()
	(tot1, tot2) = [0] * 2
	dfs.visited = set([a])
	for i in g[a]:
		dfs.currset = set()
		dfs.takepath = True
		if i == b:
			ispath = True
			continue
		elif i not in dfs.visited:
			dfs(i, b, g)
			if dfs.takepath:
				tot1 += len(dfs.currset)
	dfs.visited.add(b)
	for i in g[b]:
		dfs.currset = set()
		dfs.takepath = True
		if i == a:
			ispath = True
			continue
		elif i not in dfs.visited:
			dfs(i, a, g)
			if dfs.takepath:
				tot2 += len(dfs.currset)
	print(tot1 * tot2 if ispath else 0)


import sys
from collections import deque
sys.setrecursionlimit(6 * 10 ** 5)
input = sys.stdin.readline
INF = 10 ** 9

def dfs(edge, a, b):
	visited = [0] * len(edge)
	visited[a] = 1
	ret = 0
	for item in edge[a]:
		dq = deque()
		if visited[item]:
			continue
		dq.append(item)
		visited[item] = 1
		val = 0
		while dq:
			v = dq.pop()
			val += 1
			if v == b:
				val = -INF
			for nv in edge[v]:
				if not visited[nv]:
					dq.append(nv)
					visited[nv] = 1
		if val > 0:
			ret += val
	return ret
n = int(input())
for _ in range(n):
	(n, m, a, b) = [int(item) for item in input().split()]
	a -= 1
	b -= 1
	edge = [[] for _ in range(n)]
	for i in range(m):
		(u, v) = [int(item) - 1 for item in input().split()]
		edge[u].append(v)
		edge[v].append(u)
	anum = dfs(edge, a, b)
	bnum = dfs(edge, b, a)
	print(anum * bnum)


t = int(input())
for _ in range(t):
	(n, m, a, b) = map(int, input().split())
	e = {}
	for _ in range(m):
		(u, v) = map(int, input().split())
		if u not in e:
			e[u] = set()
		e[u].add(v)
		if v not in e:
			e[v] = set()
		e[v].add(u)
	used = [False] * (n + 1)
	s = [-1] * n
	sl = 0
	sr = 0
	(c1, c2) = (0, 0)
	used[a] = True
	used[b] = True
	start = 1
	while start <= n and used[start]:
		start += 1
	while start <= n:
		s[sr] = start
		sr += 1
		used[start] = True
		c = 0
		da = False
		db = False
		while sl < sr:
			u = s[sl]
			sl += 1
			c += 1
			for v in e[u]:
				if v == a:
					da = True
				if v == b:
					db = True
				if not used[v]:
					s[sr] = v
					sr += 1
					used[v] = True
		while start <= n and used[start]:
			start += 1
		if da and (not db):
			c1 += c
		if not da and db:
			c2 += c
	print(c1 * c2)


import sys
reader = (s.rstrip() for s in sys.stdin)
input = reader.__next__
from collections import deque

def BFS(start, dont, G):
	que = deque()
	que.append(start)
	s = set()
	while que:
		cur = que.popleft()
		if cur in s:
			continue
		if cur != start:
			s.add(cur)
		for to in G[cur]:
			if to != dont and to != start and (to not in s):
				que.append(to)
	return s

def solve():
	(n, m, a, b) = map(int, input().split())
	(a, b) = (a - 1, b - 1)
	G = [[] for i in range(n)]
	for i in range(m):
		(x, y) = map(int, input().split())
		(x, y) = (x - 1, y - 1)
		G[x].append(y)
		G[y].append(x)
	sa = BFS(a, b, G)
	sb = BFS(b, a, G)
	left = sa - sb
	right = sb - sa
	ans = len(left) * len(right)
	print(ans)
t = int(input())
for i in range(t):
	solve()


t = int(input())
from collections import defaultdict

def bfs(graph, x, forb):
	visited = set()
	circle = [x]
	while len(circle) > 0:
		new = set()
		for v in circle:
			if v in visited:
				continue
			visited.add(v)
			for pov in graph[v]:
				if pov not in forb:
					new.add(pov)
		circle = new
	return visited

def can_visit(graph, x):
	visited = set()
	circle = [x]
	while len(circle) > 0:
		new = set()
		for v in circle:
			if v in visited:
				continue
			visited.add(v)
			for pov in graph[v]:
				new.add(pov)
		circle = new
	return visited
for _ in range(t):
	(n, m, a, b) = list(map(int, input().strip().split()))
	graph = defaultdict(list)
	for _ in range(m):
		(x, y) = list(map(int, input().strip().split()))
		graph[x].append(y)
		graph[y].append(x)
	start = 0
	for i in range(1, n + 1):
		if i != a and i != b:
			start = i
			break
	iza = bfs(graph, a, [b])
	izb = bfs(graph, b, [a])
	intersection = iza & izb
	num1 = len(iza) - 1 - len(intersection)
	num2 = len(izb) - 1 - len(intersection)
	print(num1 * num2)


import sys
from collections import deque
input = sys.stdin.readline

def Solve(G, a, b):
	visited = [False] * len(G)
	visited[a] = True
	count = 0
	stack = deque()
	for v in G[a]:
		if not visited[v]:
			stack.append(v)
			visited[v] = True
			partial = 0
			inb = False
			while stack:
				vertex = stack.pop()
				partial += 1
				if vertex == b:
					inb = True
				for item in G[vertex]:
					if not visited[item]:
						stack.append(item)
						visited[item] = True
			if not inb:
				count += partial
	return count
n = int(input())
for _ in range(n):
	(n, m, a, b) = [int(item) for item in input().split()]
	a -= 1
	b -= 1
	G = [[] for _ in range(n)]
	for i in range(m):
		(u, v) = [int(item) - 1 for item in input().split()]
		G[u].append(v)
		G[v].append(u)
	anum = Solve(G, a, b)
	bnum = Solve(G, b, a)
	print(anum * bnum)


from heapq import heappush, heappop, heapify
from collections import deque, defaultdict, Counter
import itertools
from itertools import permutations, combinations
import sys
import bisect
import string
import math
import time

def I():
	return int(input())

def MI():
	return map(int, input().split())

def LI():
	return [int(i) for i in input().split()]

def LI_():
	return [int(i) - 1 for i in input().split()]

def StoI():
	return [ord(i) - 97 for i in input()]

def ItoS(nn):
	return chr(nn + 97)

def GI(V, E, Directed=False, index=0):
	org_inp = []
	g = [[] for i in range(n)]
	for i in range(E):
		inp = LI()
		org_inp.append(inp)
		if index == 0:
			inp[0] -= 1
			inp[1] -= 1
		if len(inp) == 2:
			(a, b) = inp
			g[a].append(b)
			if not Directed:
				g[b].append(a)
		elif len(inp) == 3:
			(a, b, c) = inp
			aa = (inp[0], inp[2])
			bb = (inp[1], inp[2])
			g[a].append(bb)
			if not Directed:
				g[b].append(aa)
	return (g, org_inp)

def show(*inp, end='\n'):
	if show_flg:
		print(*inp, end=end)
YN = ['Yes', 'No']
mo = 10 ** 9 + 7
inf = float('inf')
l_alp = string.ascii_lowercase
u_alp = string.ascii_uppercase
input = lambda : sys.stdin.readline().rstrip()
show_flg = False
show_flg = True
t = I()
for _ in range(t):
	(n, m, a, b) = LI()
	(a, b) = (a - 1, b - 1)
	ans = 0
	(g, c) = GI(n, m)
	vb = [1 for i in range(n)]
	va = [1 for i in range(n)]
	q = [b]
	while q:
		c = q.pop()
		vb[c] = 0
		for nb in g[c]:
			if vb[nb] == 1 and nb != a:
				q.append(nb)
				vb[nb] = 0
	q = [a]
	while q:
		c = q.pop()
		va[c] = 0
		for nb in g[c]:
			if va[nb] == 1 and nb != b:
				q.append(nb)
				va[nb] = 0
	(x, y) = (sum(vb), sum(va))
	ans = (x - 1) * (y - 1)
	print(ans)


def solve():
	(N, M, A, B) = map(int, input().split())
	roads = [list(map(lambda x: int(x) - 1, input().split())) for _ in range(M)]
	A -= 1
	B -= 1
	adj = [[] for _ in range(N)]
	for (a, b) in roads:
		adj[a].append(b)
		adj[b].append(a)

	def dfs(start, invalid):
		Q = [start]
		visited = set()
		while Q:
			q = Q.pop()
			for next in adj[q]:
				if next == invalid or next in visited:
					continue
				else:
					visited.add(next)
					Q.append(next)
		return visited - {start}
	set_A = dfs(A, B)
	set_B = dfs(B, A)
	print(len(set_A - set_B) * len(set_B - set_A))
T = int(input())
for _ in range(T):
	solve()


import sys
from collections import defaultdict
reader = (map(int, s.split()) for s in sys.stdin)
(t,) = next(reader)
for _ in range(t):
	(n, m, a, b) = next(reader)
	a -= 1
	b -= 1
	g = defaultdict(list)
	for i in range(m):
		(v, to) = next(reader)
		v -= 1
		to -= 1
		g[v].append(to)
		g[to].append(v)

	def dfs(s, comp):
		stack = [s]
		while stack:
			v = stack.pop()
			if not visited[v]:
				visited[v] = True
				comp.add(v)
				stack.extend(g[v])
	visited = [False] * n
	visited[b] = True
	compA = set()
	dfs(s=a, comp=compA)
	compA -= {a}
	visited = [False] * n
	visited[a] = True
	compB = set()
	dfs(s=b, comp=compB)
	compB -= {b}
	ans = len(compA - compB) * len(compB - compA)
	print(ans)


def main():
	t = int(input())
	allans = []
	for _ in range(t):
		(n, m, a, b) = readIntArr()
		adj = [[] for __ in range(n + 1)]
		for __ in range(m):
			(u, v) = readIntArr()
			adj[u].append(v)
			adj[v].append(u)

		def reachableFromAWOPassingB(a, b):
			st = [a]
			reachable = set()
			reachable.add(a)
			while st:
				node = st.pop()
				for nex in adj[node]:
					if nex != b and nex not in reachable:
						reachable.add(nex)
						st.append(nex)
			reachable.remove(a)
			return reachable
		vA = reachableFromAWOPassingB(a, b)
		vB = reachableFromAWOPassingB(b, a)
		unionNodes = []
		for node in vA:
			if node in vB:
				unionNodes.append(node)
		for node in unionNodes:
			vA.remove(node)
			vB.remove(node)
		ans = len(vA) * len(vB)
		allans.append(ans)
	multiLineArrayPrint(allans)
	return
import sys
input = lambda : sys.stdin.readline().rstrip('\r\n')

def oneLineArrayPrint(arr):
	print(' '.join([str(x) for x in arr]))

def multiLineArrayPrint(arr):
	print('\n'.join([str(x) for x in arr]))

def multiLineArrayOfArraysPrint(arr):
	print('\n'.join([' '.join([str(x) for x in y]) for y in arr]))

def readIntArr():
	return [int(x) for x in input().split()]

def makeArr(defaultVal, dimensionArr):
	dv = defaultVal
	da = dimensionArr
	if len(da) == 1:
		return [dv for _ in range(da[0])]
	else:
		return [makeArr(dv, da[1:]) for _ in range(da[0])]

def queryInteractive(x, y):
	print('? {} {}'.format(x, y))
	sys.stdout.flush()
	return int(input())

def answerInteractive(ans):
	print('! {}'.format(ans))
	sys.stdout.flush()
inf = float('inf')
MOD = 10 ** 9 + 7
for _abc in range(1):
	main()


import sys
readline = sys.stdin.readline

def dfs(s, t, Edge):
	N = len(Edge)
	used = [0] * N
	used[s] = 1
	used[t] = 1
	stack = [s]
	while stack:
		vn = stack.pop()
		for vf in Edge[vn]:
			if not used[vf]:
				used[vf] = 1
				stack.append(vf)
	return used
T = int(readline())
Ans = [None] * T
for qu in range(T):
	(N, M, A, B) = map(int, readline().split())
	A -= 1
	B -= 1
	Edge = [[] for _ in range(N)]
	for _ in range(M):
		(a, b) = map(int, readline().split())
		a -= 1
		b -= 1
		Edge[a].append(b)
		Edge[b].append(a)
	sa = dfs(A, B, Edge)
	sb = dfs(B, A, Edge)
	ca = 0
	cb = 0
	for (fa, fb) in zip(sa, sb):
		if fa == fb:
			continue
		if fa:
			ca += 1
		elif fb:
			cb += 1
	Ans[qu] = ca * cb
print('\n'.join(map(str, Ans)))


from collections import deque

def solveOne():
	(nVertices, nEdges, v1, v2) = map(int, input().split())
	v1 -= 1
	v2 -= 1
	g = [[] for _ in range(nVertices)]
	for _ in range(nEdges):
		(u, v) = map(lambda x: int(x) - 1, input().split())
		g[u].append(v)
		g[v].append(u)

	def bfs(start, restricted):
		visited = {start}
		q = deque([start])
		while q:
			v = q.pop()
			for to in g[v]:
				if to != restricted and to not in visited:
					visited.add(to)
					q.appendleft(to)
		return visited - {start}
	set1 = bfs(v1, v2)
	set2 = bfs(v2, v1)
	return len(set1 - set2) * len(set2 - set1)
for _ in range(int(input())):
	print(solveOne())


import sys
ans = []
for _ in range(int(input())):
	(n, m, a, b) = map(int, input().split())
	a -= 1
	b -= 1
	adj = [[] for _ in range(n)]
	for (u, v) in (map(int, sys.stdin.readline().split()) for _ in range(m)):
		adj[u - 1].append(v - 1)
		adj[v - 1].append(u - 1)
	visited = [0] * n
	visited[a] = 3
	visited[b] = 3
	stack = [a]
	while stack:
		v = stack.pop()
		for dest in adj[v]:
			if visited[dest] & 1:
				continue
			visited[dest] |= 1
			stack.append(dest)
	stack = [b]
	while stack:
		v = stack.pop()
		for dest in adj[v]:
			if visited[dest] & 2:
				continue
			visited[dest] |= 2
			stack.append(dest)
	ans.append(visited.count(1) * visited.count(2))
print(*ans, sep='\n')


import os
import sys
from io import BytesIO, IOBase
from collections import deque

def main():
	for _ in range(int(input())):
		(n, m, a, b) = map(int, input().split())
		tree = [[] for _ in range(n + 1)]
		for i in range(m):
			(x, y) = map(int, input().split())
			tree[x].append(y)
			tree[y].append(x)
		p = [0] * (n + 1)
		q = deque([(a, -1)])
		v = [0] * (n + 1)
		v[a] = 1
		while q:
			(c, pa) = q.popleft()
			p[c] = pa
			for i in tree[c]:
				if not v[i]:
					q.append((i, c))
					v[i] = 1
		(path, z) = ([], b)
		while z != -1:
			path.append(z)
			z = p[z]
		v = [0] * (n + 1)
		v[a] = v[b] = 1
		for i in range(1, len(path) - 1):
			if not v[path[i]]:
				q = deque([path[i]])
				v[path[i]] = 1
				while q:
					c = q.popleft()
					for j in tree[c]:
						if not v[j]:
							q.append(j)
							v[j] = 1
		(x, y) = (set(), set())
		q = deque([a])
		v1 = v[:]
		while q:
			c = q.popleft()
			for j in tree[c]:
				if not v1[j]:
					q.append(j)
					x.add(j)
					v1[j] = 1
		q = deque([b])
		while q:
			c = q.popleft()
			for j in tree[c]:
				if not v[j]:
					q.append(j)
					y.add(j)
					v[j] = 1
		z = x.intersection(y)
		print((len(x) - len(z)) * (len(y) - len(z)))
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
main()


import os
import sys
from io import BytesIO, IOBase
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
from math import factorial
from collections import Counter, defaultdict
from heapq import heapify, heappop, heappush

def RL():
	return map(int, sys.stdin.readline().rstrip().split())

def RLL():
	return list(map(int, sys.stdin.readline().rstrip().split()))

def N():
	return int(input())

def comb(n, m):
	return factorial(n) / (factorial(m) * factorial(n - m)) if n >= m else 0

def perm(n, m):
	return factorial(n) // factorial(n - m) if n >= m else 0

def mdis(x1, y1, x2, y2):
	return abs(x1 - x2) + abs(y1 - y2)

def ctd(chr):
	return ord(chr) - ord('a')
mod = 998244353
INF = float('inf')

def main():
	for _ in range(N()):
		(n, m, a, b) = RL()
		gp = [[] for _ in range(n + 1)]
		for _ in range(m):
			(f, t) = RL()
			gp[f].append(t)
			gp[t].append(f)

		def BFS(node):
			ano = a if node == b else b
			vis = [0] * (n + 1)
			vis[node] = 1
			q = [node]
			for nd in q:
				for nex in gp[nd]:
					if vis[nex] == 1 or nex == ano:
						continue
					q.append(nex)
					vis[nex] = 1
			return q
		arra = BFS(a)
		arrb = BFS(b)
		(la, lb) = (len(arra) - 1, len(arrb) - 1)
		stb = set(arrb)
		for i in arra:
			if i == a:
				continue
			if i in stb:
				la -= 1
				lb -= 1
		print(la * lb)
main()


import sys
import threading
from collections import deque

def func():
	lines = sys.stdin.readlines()
	nxt = 0
	t = int(lines[nxt])
	nxt += 1
	ans = []
	for _ in range(t):
		(n, m, a, b) = map(int, lines[nxt].split())
		nxt += 1
		g = [[] for _ in range(n)]
		for _ in range(m):
			(u, v) = map(int, lines[nxt].split())
			nxt += 1
			g[u - 1].append(v - 1)
			g[v - 1].append(u - 1)
		a -= 1
		b -= 1
		sigs = [0] * n
		sigs[a] = -1
		sigs[b] = -1
		cur_sig = 0
		inv = {}
		cnt = {}
		for i in range(n):
			if sigs[i]:
				continue
			cur_sig += 1
			cnt[cur_sig] = 1
			inv[cur_sig] = set()
			sigs[i] = cur_sig
			q = deque()
			q.append(i)
			while len(q):
				node = q.popleft()
				for v in g[node]:
					if v == a:
						inv[cur_sig].add('A')
					if v == b:
						inv[cur_sig].add('B')
					if sigs[v]:
						continue
					sigs[v] = cur_sig
					cnt[cur_sig] += 1
					q.append(v)
		A = 0
		B = 0
		for (k, v) in inv.items():
			if v == {'A'}:
				A += cnt[k]
			if v == {'B'}:
				B += cnt[k]
		ans.append(str(A * B))
	print('\n'.join(ans))
func()


import sys

def input():
	return sys.stdin.readline().strip()

def list2d(a, b, c):
	return [[c] * b for i in range(a)]

def list3d(a, b, c, d):
	return [[[d] * c for j in range(b)] for i in range(a)]

def list4d(a, b, c, d, e):
	return [[[[e] * d for j in range(c)] for j in range(b)] for i in range(a)]

def ceil(x, y=1):
	return int(-(-x // y))

def INT():
	return int(input())

def MAP():
	return map(int, input().split())

def LIST(N=None):
	return list(MAP()) if N is None else [INT() for i in range(N)]

def Yes():
	print('Yes')

def No():
	print('No')

def YES():
	print('YES')

def NO():
	print('NO')
sys.setrecursionlimit(10 ** 9)
INF = 10 ** 18
MOD = 10 ** 9 + 7

def dfs(start, avoid):
	res = [0] * N
	stack = [start]
	while stack:
		u = stack.pop()
		res[u] = 1
		for v in nodes[u]:
			if not res[v] and v != avoid:
				stack.append(v)
	return res
for _ in range(INT()):
	(N, M, a, b) = MAP()
	a -= 1
	b -= 1
	nodes = [[] for i in range(N)]
	for i in range(M):
		(x, y) = MAP()
		x -= 1
		y -= 1
		nodes[x].append(y)
		nodes[y].append(x)
	froma = dfs(a, b)
	fromb = dfs(b, a)
	aonly = bonly = 0
	for i in range(N):
		if i != a and i != b:
			if froma[i] and (not fromb[i]):
				aonly += 1
			if fromb[i] and (not froma[i]):
				bonly += 1
	print(aonly * bonly)


from sys import stdin, stdout
from collections import deque
T = int(stdin.readline().strip())
out = []
for _ in range(T):
	(n, m, a, b) = stdin.readline().split()
	(n, m) = (int(n), int(m))
	roads = {}
	for _ in range(m):
		(x, y) = stdin.readline().split()
		roads.setdefault(x, []).append(y)
		roads.setdefault(y, []).append(x)
	visited = set([a])
	(counta, ignore) = (0, 0)
	for aa in roads[a]:
		if aa not in visited:
			next = deque([aa])
			(flg, c) = (True, 0)
			while next:
				v1 = next.popleft()
				if v1 == b:
					flg = False
					continue
				if v1 in visited:
					continue
				visited.add(v1)
				for v2 in filter(lambda x: x not in visited, roads[v1]):
					next.appendleft(v2)
				c += 1
			if flg:
				counta += c
			else:
				ignore += c
	out.append('{}\n'.format(counta * (n - 2 - counta - ignore)))
stdout.writelines(out)


import os
import sys
from io import BytesIO, IOBase
from collections import deque

def main():
	for _ in range(int(input())):
		(n, m, a, b) = map(int, input().split())
		graph = [set() for _ in range(n + 1)]
		for _ in range(m):
			(x, y) = map(int, input().split())
			graph[x].add(y)
			graph[y].add(x)
		vis = [0] * (n + 1)
		(na, nb) = (1, 1)
		for item in graph[a]:
			graph[item].remove(a)
		q = deque([b])
		vis[b] = 1
		while q:
			z = q.popleft()
			for item in graph[z]:
				if vis[item] == 0:
					na += 1
					vis[item] = 1
					q.append(item)
		na = n - na - 1
		for item in graph[a]:
			graph[item].add(a)
		for item in graph[b]:
			graph[item].remove(b)
		vis = [0] * (n + 1)
		q = deque([a])
		vis[a] = 1
		while q:
			z = q.popleft()
			for item in graph[z]:
				if vis[item] == 0:
					nb += 1
					vis[item] = 1
					q.append(item)
		nb = n - nb - 1
		print(na * nb)
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
main()


import os
import sys
from io import BytesIO, IOBase
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
from math import gcd, ceil

def pre(s):
	n = len(s)
	pi = [0] * n
	for i in range(1, n):
		j = pi[i - 1]
		while j and s[i] != s[j]:
			j = pi[j - 1]
		if s[i] == s[j]:
			j += 1
		pi[i] = j
	return pi

def prod(a):
	ans = 1
	for each in a:
		ans = ans * each
	return ans

def lcm(a, b):
	return a * b // gcd(a, b)

def binary(x, length=16):
	y = bin(x)[2:]
	return y if len(y) >= length else '0' * (length - len(y)) + y

def dfs(graph, start, end):
	n = len(graph)
	(visited, finished) = ([False] * n, [False] * n)
	stack = [start]
	while stack:
		start = stack[-1]
		if not visited[start]:
			visited[start] = True
			if start == end:
				continue
			for child in graph[start]:
				if not visited[child]:
					stack.append(child)
		else:
			stack.pop()
			finished[start] = True
	return visited
for _ in range(int(input()) if True else 1):
	(n, m, a, b) = map(int, input().split())
	graph = [[] for __ in range(n + 1)]
	for __ in range(m):
		(x, y) = map(int, input().split())
		graph[x] += [y]
		graph[y] += [x]
	vis = dfs(graph, a, b)
	vis2 = dfs(graph, b, a)
	(ans1, ans2) = (0, 0)
	for i in range(1, n + 1):
		if i == a or i == b:
			continue
		if vis[i] and (not vis2[i]):
			ans1 += 1
		if not vis[i] and vis2[i]:
			ans2 += 1
	print(ans1 * ans2)


import sys
input = sys.stdin.readline

def dfs(g, i, e, n):
	vis = [0] * (n + 1)
	s = [i]
	ans = set()
	while len(s) > 0:
		top = s[-1]
		s.pop()
		if vis[top] == 1 or top == e:
			continue
		vis[top] = 1
		ans.add(top)
		for j in g[top]:
			s.append(j)
	return ans
t = int(input())
for _ in range(t):
	(n, m, a, b) = map(int, input().split())
	g = [[] for i in range(n + 1)]
	for i in range(m):
		(x, y) = map(int, input().split())
		g[x].append(y)
		g[y].append(x)
	seta = dfs(g, a, b, n)
	setb = dfs(g, b, a, n)
	inter = seta.intersection(setb)
	seta = seta - inter
	setb = setb - inter
	print((len(seta) - 1) * (len(setb) - 1))


for t in range(int(input())):
	(n, m, a, b) = map(int, input().split())
	neigh_cities = [[] for i in range(n + 1)]
	for i in range(m):
		(x, y) = map(int, input().split())
		neigh_cities[x].append(y)
		neigh_cities[y].append(x)
	with_a = 0
	with_b = 0
	remaining_cities = set(range(1, n + 1))
	remaining_cities.difference_update({a, b})
	while len(remaining_cities) != 0:
		to_be_explored = set()
		already_explored = set()
		connected_to_a = False
		connected_to_b = False
		comp = []
		to_be_explored.add(remaining_cities.pop())
		while len(to_be_explored) != 0:
			city = to_be_explored.pop()
			comp.append(city)
			already_explored.add(city)
			for i in neigh_cities[city]:
				if i == a:
					connected_to_a = True
					continue
				if i == b:
					connected_to_b = True
					continue
				if i not in already_explored:
					to_be_explored.add(i)
					remaining_cities.discard(i)
		if connected_to_a and (not connected_to_b):
			with_a += len(comp)
		if connected_to_b and (not connected_to_a):
			with_b += len(comp)
	print(with_a * with_b)


import sys

def input():
	return sys.stdin.readline().strip()

def list2d(a, b, c):
	return [[c] * b for i in range(a)]

def list3d(a, b, c, d):
	return [[[d] * c for j in range(b)] for i in range(a)]

def list4d(a, b, c, d, e):
	return [[[[e] * d for j in range(c)] for j in range(b)] for i in range(a)]

def ceil(x, y=1):
	return int(-(-x // y))

def INT():
	return int(input())

def MAP():
	return map(int, input().split())

def LIST(N=None):
	return list(MAP()) if N is None else [INT() for i in range(N)]

def Yes():
	print('Yes')

def No():
	print('No')

def YES():
	print('YES')

def NO():
	print('NO')
sys.setrecursionlimit(10 ** 9)
INF = 10 ** 18
MOD = 10 ** 9 + 7

class UnionFind:

	def __init__(self, n):
		self.n = n
		self.par = [i for i in range(n + 1)]
		self.rank = [0] * (n + 1)
		self.size = [1] * (n + 1)
		self.tree = [True] * (n + 1)

	def find(self, x):
		if self.par[x] == x:
			return x
		else:
			self.par[x] = self.find(self.par[x])
			return self.par[x]

	def union(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			self.tree[x] = False
			return
		if not self.tree[x] or not self.tree[y]:
			self.tree[x] = self.tree[y] = False
		if self.rank[x] < self.rank[y]:
			self.par[x] = y
			self.size[y] += self.size[x]
		else:
			self.par[y] = x
			self.size[x] += self.size[y]
			if self.rank[x] == self.rank[y]:
				self.rank[x] += 1

	def is_same(self, x, y):
		return self.find(x) == self.find(y)

	def get_size(self, x=None):
		if x is not None:
			return self.size[self.find(x)]
		else:
			res = set()
			for i in range(self.n + 1):
				res.add(self.find(i))
			return len(res) - 1

	def is_tree(self, x):
		return self.tree[self.find(x)]
for _ in range(INT()):
	(N, M, a, b) = MAP()
	uf1 = UnionFind(N)
	uf2 = UnionFind(N)
	for i in range(M):
		(x, y) = MAP()
		if a in [x, y] and b in [x, y]:
			continue
		elif a in [x, y]:
			uf1.union(x, y)
		elif b in [x, y]:
			uf2.union(x, y)
		else:
			uf1.union(x, y)
			uf2.union(x, y)
	cnt1 = N - uf1.get_size(a) - 1
	cnt2 = N - uf2.get_size(b) - 1
	print(cnt1 * cnt2)


from collections import deque
from collections import defaultdict
import sys
input = sys.stdin.readline
inf = 100000000000000000
mod = 998244353
for CASES in range(int(input())):
	A = defaultdict(list)
	(n, m, a, b) = map(int, input().split())
	for i in range(m):
		(x, y) = map(int, input().split())
		A[x].append(y)
		A[y].append(x)
	VISA = [0] * (n + 2)
	VISA[a] = 1
	VISA[b] = 1
	Q = deque()
	Q.append(a)
	while Q:
		now = Q.pop()
		for to in A[now]:
			if VISA[to] == 0:
				VISA[to] = 1
				Q.append(to)
	VISB = [0] * (n + 2)
	VISB[a] = 1
	VISB[b] = 1
	Q = deque()
	Q.append(b)
	while Q:
		now = Q.pop()
		for to in A[now]:
			if VISB[to] == 0:
				VISB[to] = 1
				Q.append(to)
	ansa = 0
	ansb = 0
	for i in range(1, n + 1):
		if VISA[i] == 0 and VISB[i] == 1:
			ansb += 1
		elif VISA[i] == 1 and VISB[i] == 0:
			ansa += 1
	print(ansa * ansb)


from sys import stdin

def input():
	return stdin.readline()[:-1]

def intput():
	return int(input())

def sinput():
	return input().split()

def intsput():
	return map(int, sinput())
t = intput()
for _ in range(t):
	(n, m, a, b) = intsput()
	colors = [0] * (n + 1)
	colors[a] = 'a'
	colors[b] = 'b'
	roads = {}
	for i in range(m):
		(x, y) = intsput()
		if x not in roads:
			roads[x] = []
		if y not in roads:
			roads[y] = []
		roads[x].append(y)
		roads[y].append(x)
	counts = {(True, False): 0, (True, True): 0, (False, True): 0}
	visited = set()
	while len(visited) < n - 2:
		for i in range(1, n + 1):
			if i not in (a, b) and i not in visited:
				break
		else:
			exit(1)
		start = i
		visited.add(start)
		cnt = 1
		colors[start] = 1
		adj = roads[start]
		(meta, metb) = (False, False)
		while adj:
			nxt = adj.pop()
			if nxt == a:
				meta = True
			elif nxt == b:
				metb = True
			elif nxt not in visited:
				visited.add(nxt)
				cnt += 1
				colors[nxt] = 1
				adj += roads[nxt]
		col1 = (meta, metb)
		counts[col1] += cnt
	print(counts[True, False] * counts[False, True])


class UnionFind:

	def __init__(self, n):
		self.n = n
		self.root = [-1] * (n + 1)
		self.rnk = [0] * (n + 1)

	def Find_Root(self, x):
		if self.root[x] < 0:
			return x
		else:
			self.root[x] = self.Find_Root(self.root[x])
			return self.root[x]

	def Unite(self, x, y):
		x = self.Find_Root(x)
		y = self.Find_Root(y)
		if x == y:
			return
		elif self.rnk[x] > self.rnk[y]:
			self.root[x] += self.root[y]
			self.root[y] = x
		else:
			self.root[y] += self.root[x]
			self.root[x] = y
			if self.rnk[x] == self.rnk[y]:
				self.rnk[y] += 1

	def isSameGroup(self, x, y):
		return self.Find_Root(x) == self.Find_Root(y)

	def Count(self, x):
		return -self.root[self.Find_Root(x)]
import sys
input = sys.stdin.readline
Q = int(input())
Query = []
for _ in range(Q):
	(N, M, a, b) = map(int, input().split())
	CD = [list(map(int, input().split())) for _ in range(M)]
	Query.append((N, M, a, b, CD))

def main():
	for (N, M, a, b, CD) in Query:
		uni1 = UnionFind(N)
		uni2 = UnionFind(N)
		for (c, d) in CD:
			if c != a and d != a:
				uni1.Unite(c, d)
			if c != b and d != b:
				uni2.Unite(c, d)
		p0 = 0
		p1 = 0
		for n in range(1, N + 1):
			if uni1.isSameGroup(n, b) and (not uni2.isSameGroup(n, a)):
				p0 += 1
			if not uni1.isSameGroup(n, b) and uni2.isSameGroup(n, a):
				p1 += 1
		print((p0 - 1) * (p1 - 1))
main()


import os
import sys
from io import BytesIO, IOBase
from math import gcd, inf, sqrt, ceil

def lcm(a, b):
	return a * b // gcd(a, b)

def sieve():
	spf[1] = 1
	for i in range(2, MAXN):
		spf[i] = i
	for i in range(4, MAXN, 2):
		spf[i] = 2
	for i in range(3, ceil(sqrt(MAXN))):
		if spf[i] == i:
			for j in range(i * i, MAXN, i):
				if spf[j] == j:
					spf[j] = i

def getFactorization(x):
	ret = Counter()
	while x != 1:
		ret[spf[x]] += 1
		x = x // spf[x]
	return ret

def printDivisors(n):
	i = 2
	z = [1, n]
	while i <= sqrt(n):
		if n % i == 0:
			if n / i == i:
				z.append(i)
			else:
				z.append(i)
				z.append(n // i)
		i = i + 1
	return z

def create(n, x, f):
	pq = len(bin(n)[2:])
	if f == 0:
		tt = min
	else:
		tt = max
	dp = [[inf] * n for _ in range(pq)]
	dp[0] = x
	for i in range(1, pq):
		for j in range(n - (1 << i) + 1):
			dp[i][j] = tt(dp[i - 1][j], dp[i - 1][j + (1 << i - 1)])
	return dp

def enquiry(l, r, dp, f):
	if l > r:
		return inf if not f else -inf
	if f == 1:
		tt = max
	else:
		tt = min
	pq1 = len(bin(r - l + 1)[2:]) - 1
	return tt(dp[pq1][l], dp[pq1][r - (1 << pq1) + 1])

def SieveOfEratosthenes(n):
	prime = [True for i in range(n + 1)]
	p = 2
	while p * p <= n:
		if prime[p] == True:
			for i in range(p * p, n + 1, p):
				prime[i] = False
		p += 1
	x = []
	for i in range(2, n + 1):
		if prime[i]:
			x.append(i)
	return x

def main():

	class dsu:

		def __init__(self, n):
			self.parent = [0] * (n + 1)
			self.size = [0] * (n + 1)

		def make_set(self, v):
			self.parent[v] = v
			self.size[v] = 1

		def union_set(self, a, b):
			a = self.find_set(a)
			b = self.find_set(b)
			if a != b:
				if self.size[a] < self.size[b]:
					(a, b) = (b, a)
				self.parent[b] = a
				self.size[a] += self.size[b]

		def find_set(self, v):
			if v == self.parent[v]:
				return v
			self.parent[v] = self.find_set(self.parent[v])
			return self.parent[v]
	for _ in range(int(input())):
		(n, m, a, b) = map(int, input().split())
		x = []
		xx = dsu(n)
		yy = dsu(n)
		for i in range(m):
			(u, v) = map(int, input().split())
			u -= 1
			v -= 1
			x.append((u, v))
		for i in range(n):
			xx.make_set(i)
			yy.make_set(i)
		for i in x:
			if i[0] != a - 1 and i[1] != a - 1:
				xx.union_set(i[0], i[1])
			if i[0] != b - 1 and i[1] != b - 1:
				yy.union_set(i[0], i[1])
		xxxx = 0
		yyyy = 0
		for i in range(n):
			if xx.find_set(i) != xx.find_set(b - 1):
				xxxx += 1
			if yy.find_set(i) != yy.find_set(a - 1):
				yyyy += 1
		print((xxxx - 1) * (yyyy - 1))
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
main()


import sys, math
import io, os
from bisect import bisect_left as bl, bisect_right as br, insort
from collections import defaultdict as dd, deque, Counter

def data():
	return sys.stdin.readline().strip()

def mdata():
	return list(map(int, data().split()))

def outl(var):
	sys.stdout.write(' '.join(map(str, var)) + '\n')

def out(var):
	sys.stdout.write(str(var) + '\n')
from decimal import Decimal
mod = int(1000000000.0) + 7

def dfs(graph, start, end):
	n = len(graph)
	dp = [0] * n
	(visited, finished) = ([False] * n, [False] * n)
	stack = [start]
	while stack:
		start = stack.pop()
		dp[start] = 1
		if not visited[start] and start != end:
			visited[start] = True
			for child in graph[start]:
				if not visited[child]:
					stack.append(child)
	return n - sum(dp) - 1
for t in range(int(data())):
	(n, m, a, b) = mdata()
	graph = [[] for i in range(n + 1)]
	for i in range(m):
		(u, v) = mdata()
		graph[u].append(v)
		graph[v].append(u)
	out(dfs(graph, a, b) * dfs(graph, b, a))


from sys import stdin

def input():
	return next(stdin)[:-1]

class DisjointUnionSet:

	def __init__(self, size):
		self.parent = list(range(size))
		self.rank = [0] * size

	def find_set(self, v):
		if v == self.parent[v]:
			return v
		self.parent[v] = self.find_set(self.parent[v])
		return self.parent[v]

	def union_sets(self, a, b):
		a = self.find_set(a)
		b = self.find_set(b)
		if a != b:
			if self.rank[a] < self.rank[b]:
				(a, b) = (b, a)
			self.parent[b] = a
			if self.rank[a] == self.rank[b]:
				self.rank[a] += 1

def main():

	def solve():
		(n, m, a, b) = map(int, input().split())
		dusa = DisjointUnionSet(n)
		dusb = DisjointUnionSet(n)
		for _ in range(m):
			(u, v) = map(int, input().split())
			if u != a and v != a:
				dusa.union_sets(u - 1, v - 1)
			if u != b and v != b:
				dusb.union_sets(u - 1, v - 1)
		pa = dusb.find_set(a - 1)
		pb = dusa.find_set(b - 1)
		ac = 0
		bc = 0
		for i in range(n):
			if i == a - 1 or i == b - 1:
				continue
			if dusa.find_set(i) != pb:
				ac += 1
			if dusb.find_set(i) != pa:
				bc += 1
		print(ac * bc)
	q = int(input())
	for _ in range(q):
		solve()
main()


import sys
input = sys.stdin.buffer.readline

class UnionFind:

	def __init__(self, n):
		self.n = n
		self.root = [-1] * (n + 1)
		self.rnk = [0] * (n + 1)

	def find_root(self, x):
		if self.root[x] < 0:
			return x
		else:
			self.root[x] = self.find_root(self.root[x])
			return self.root[x]

	def unite(self, x, y):
		x = self.find_root(x)
		y = self.find_root(y)
		if x == y:
			return
		elif self.rnk[x] > self.rnk[y]:
			self.root[x] += self.root[y]
			self.root[y] = x
		else:
			self.root[y] += self.root[x]
			self.root[x] = y
			if self.rnk[x] == self.rnk[y]:
				self.rnk[y] += 1

	def isSameGroup(self, x, y):
		return self.find_root(x) == self.find_root(y)

	def size(self, x):
		return -self.root[self.find_root(x)]
t = int(input())
for _ in range(t):
	(N, M, a, b) = map(int, input().split())
	edge = []
	for _ in range(M):
		(u, v) = map(int, input().split())
		edge.append((u, v))
	UF_a = UnionFind(N)
	UF_b = UnionFind(N)
	for (u, v) in edge:
		if u != a and v != a:
			UF_a.unite(u, v)
		if u != b and v != b:
			UF_b.unite(u, v)
	c = N - 1 - UF_a.size(b)
	d = N - 1 - UF_b.size(a)
	print(c * d)