#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>
#include <functional>
#include <vector>
#include <queue>
#include <deque>
#include <map>
#include <set>
#define nmax_def 220000
#define mod 1000000007
#define rep(i,n) for(int (i)=0;(i)<(n);(i)++)
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<bool> vb;

class Graph_func {
public:
	bool graph_from1 = true;
	bool graph_tree = true;
	bool graph_weight = false;
	bool graph_digraph = false;
	int Vnum;
	int Enum;
	vector<pii> edgelist;
	vl edgeweight;
	vector<vi> adjlist;
	vector<vl> adjlistweight;
	vi adjnum;

	vi adj_to_root;
	vector<int> DP;
	vi vlist_from_root;
	vl xdist;

	vb x_visited;
	vi x_prqarr;
	vb x_filled;

	void read_edge();
	void read_edge_array();
	void adjini();
	void visited_ini();
	void adjsort();
	vb graph_num_BFS(int BFS_ini, vb filled);
	int graph_num();
	void graph_BFS(ll BFS_ini);
	void graph_DFS(ll DFS_ini);
	void xydist_tree(int x);   // ex. xydist_tree(3)
	void xydist(int x);   // ex. xydist(3, 0)
	ll diameter();
	void ReRooting(ll root);
	Graph_func Kruskal();
	int dim_num(int dim);
	void solve();

	bool xydist_def = false;
};

// ----- UnionFind -----

class UnionFind {
public:
	vi par;
	vi adjnum;
	int N;

	void UnionFind_ini(int Narg);
	int root(int x);
	void unite(int x, int y);
	bool same(int x, int y);
	int adjnum_func(int x);
};

void UnionFind::UnionFind_ini(int Narg) {
	N = Narg;
	adjnum.resize(N);
	par.resize(N);
	rep(i, N) {
		adjnum[i] = 1;
		par[i] = i;
	}
}

int UnionFind::root(int x) {
	if (par[x] == x)
		return x;
	par[x] = root(par[x]);
	return par[x];
}

void UnionFind::unite(int x, int y) {
	int rx = root(x);
	int ry = root(y);
	if (rx == ry)
		return;
	par[rx] = ry;
	adjnum[ry] += adjnum[rx];
	return;
}

bool UnionFind::same(int x, int y) {
	int rx = root(x);
	int ry = root(y);
	return rx == ry;
}

int UnionFind::adjnum_func(int x) {
	int rx = root(x);
	return adjnum[rx];
}

// ----- graph -----

void Graph_func::read_edge() {
	cin >> Vnum;
	if (graph_tree)
		Enum = Vnum - 1;// graph
	else
		cin >> Enum;
	edgelist.resize(Enum);
	edgeweight.resize(Enum, 1);
	rep(i, Enum) {
		if (graph_weight)
			cin >> edgelist[i].first >> edgelist[i].second >> edgeweight[i];
		else
			cin >> edgelist[i].first >> edgelist[i].second;
		if (graph_from1) {
			edgelist[i].first--;
			edgelist[i].second--;
		}
		if (edgelist[i].first > edgelist[i].second)
			swap(edgelist[i].first, edgelist[i].second);
	}
	return;
}

void Graph_func::read_edge_array() {
	cin >> Vnum;
	Enum = 0;
	rep(i, Vnum) {
		string S;
		cin >> S;
		rep(j, Vnum) {
			if (S[j] == '1') {
				if (graph_digraph || i < j) {
					pii edgetmp = make_pair(i, j);
					edgelist.push_back(edgetmp);
					Enum++;
				}
			}
		}
	}
	if (!graph_digraph)
		Enum /= 2;
	return;
}

void Graph_func::adjini() {
	adjnum.resize(Vnum);
	xdist.resize(Vnum);
	adjlist.resize(Vnum);
	if (graph_weight)
		adjlistweight.resize(Vnum);
	adj_to_root.resize(Vnum, -1);
	DP.resize(Vnum, 0);
	rep(i, Vnum)
		adjnum[i] = 0;
	rep(i, Enum) {
		int x = edgelist[i].first;
		int y = edgelist[i].second;
		adjlist[x].push_back(y);
		if (!graph_digraph)
			adjlist[y].push_back(x);
		if (graph_weight) {
			ll xyweight = edgeweight[i];
			adjlistweight[x].push_back(xyweight);
			if (!graph_digraph)
				adjlistweight[y].push_back(xyweight);
		}
		adjnum[x]++;
		if (!graph_digraph)
			adjnum[y]++;
	}
	x_visited.resize(Vnum);
	visited_ini();

	return;
}

void Graph_func::visited_ini() {
	rep(i, Vnum) {
		adj_to_root[i] = i;
		x_visited[i] = false;
	}
	x_prqarr.resize(0);
}

void Graph_func::adjsort() {
	rep(i, Vnum)
		sort(adjlist[i].begin(), adjlist[i].end(), less<int>());
	return;
}

vb Graph_func::graph_num_BFS(int BFS_ini, vb filled) { // ex. graph_num_BFS(i, filled);
	x_prqarr.push_back(BFS_ini);
	x_visited[BFS_ini] = true;

	while (!x_prqarr.empty()) {
		int Ntmp = x_prqarr.size();
		vi x_prqarr_next(0);
		rep(n, Ntmp) {
			int x = x_prqarr[n];
			rep(i, adjnum[x]) {
				int x_new = adjlist[x][i];
				if (!x_visited[x_new]) {
					x_prqarr_next.push_back(x_new);
					x_visited[x_new] = true;
					filled[x_new] = true;
				}
			}
		}
		x_prqarr = x_prqarr_next;
	}
	return filled;
}

int Graph_func::graph_num() {
	int anstmp = 0;
	int i = 0;
	vector<bool> filled;
	filled.resize(Vnum);
	rep(j, Vnum)
		filled[j] = false;
	bool end = false;
	while (!end) {
		if (i >= Vnum)
			break;
		while (1) {
			if (!filled[i])
				break;
			i++;
			if (i >= Vnum) {
				end = true;
				break;
			}
		}
		if (end)
			break;
		filled[i] = true;
		filled = graph_num_BFS(i, filled);
		anstmp++;
	}
	return anstmp;
}

void Graph_func::graph_BFS(ll BFS_ini) {
	visited_ini();
	x_prqarr.push_back(BFS_ini);
	x_visited[BFS_ini] = true;
	vlist_from_root.resize(1, BFS_ini);
	while (!x_prqarr.empty()) {
		vi x_prqarr_next(0);
		int Ntmp = x_prqarr.size();
		rep(n, Ntmp) {
			int x = x_prqarr[n];
			rep(i, adjnum[x]) {
				int x_new = adjlist[x][i];
				if (!x_visited[x_new]) {
					adj_to_root[x_new] = x;
					vlist_from_root.push_back(x_new);
					x_prqarr_next.push_back(x_new);
					x_visited[x_new] = true;
					//cout << x_new << endl;
				}
			}
		}
		x_prqarr = x_prqarr_next;
	}
	return;
}

void Graph_func::graph_DFS(ll DFS_ini) {
	visited_ini();
	x_prqarr.push_back(DFS_ini);
	x_visited[DFS_ini] = true;

	while (!x_prqarr.empty()) {
		int Ntmp = x_prqarr.size();
		rep(a, Ntmp) {
			int x = x_prqarr[x_prqarr.size() - 1];
			x_prqarr.pop_back();
			rep(i, adjnum[x]) {
				int x_new = adjlist[x][i];
				if (!x_visited[x_new]) {
					adj_to_root[x_new] = x;
					x_prqarr.push_back(x_new);
					x_visited[x_new] = true;
				}
			}
		}
	}
	return;
}

int Graph_func::dim_num(int dim) {
	int anstmp = 0;
	rep(i, Vnum) {
		if (adjnum[i] == dim)
			anstmp++;
	}
	return anstmp;
}

void Graph_func::solve() {
	ll ans = 0;
	ll ansall = 1;
	rep(i, Enum)
		ansall *= 2;
	ll M;
	cin >> M;
	vector<pii> uv(M);
	vector<vector<int>> M_edge(0);
	rep(i, M) {
		cin >> uv[i].first >> uv[i].second;
		uv[i].first--;
		uv[i].second--;
		graph_DFS(uv[i].first);
		vector<int> M_edge_tmp(0);
		int xtmp = uv[i].second;
		while (1) {
			int xroot = adj_to_root[xtmp];
			int a = xtmp;
			int b = xroot;
			if (a > b)
				swap(a, b);
			rep(i, Enum) {
				if (edgelist[i].first == a && edgelist[i].second == b) {
					M_edge_tmp.push_back(i);
					break;
				}
			}
			if (xroot == uv[i].first)
				break;
			xtmp = xroot;
		}
		M_edge.push_back(M_edge_tmp);
	}
	ll M2 = 1;
	rep(i, M)
		M2 *= (ll)2;
	rep(b, M2) {
		vector<bool> edge_used(Enum, 0);
		int bitcount = 0;
		rep(i, M) {
			if ((b >> i) % 2 == 1) {
				bitcount++;
				int edgesum = M_edge[i].size();
				rep(j, edgesum) {
					edge_used[M_edge[i][j]] = 1;
				}
			}
		}
		ll edge_num_tmp = 0;
		rep(i, Enum) {
			if (edge_used[i])
				edge_num_tmp++;
		}
		ll anstmp = ansall;
		rep(i, edge_num_tmp) {
			anstmp /= (ll)2;
		}
		if (bitcount % 2 == 1) {
			ans -= anstmp;
		}
		else
			ans += anstmp;
	}
	cout << ans << endl;
	return;
}

int main(void) {
	Graph_func graph;
	graph.read_edge();
	graph.adjini();
	graph.solve();
	return 0;
}

Measured memory_bytes: 256