#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <string>
#include <iomanip>
#include <algorithm>
#include <cmath>
#include <stdio.h>
#include <assert.h>
using namespace std;
#define int long long
int MOD = 1000000007;
class biconnected {
private:
	void dfs(int u, int p, int &k, int q)
	{
		visit[u] = true;
		ord[u] = k++;
		low[u] = ord[u];
		for (int i = 0; i < (int)G[u].size(); i++) {
			int v = G[u][i];
			if (!visit[v]) {
				dfs(v, u, k, i);
				low[u] = min(low[u], low[v]);
				if (ord[u] < low[v]) {
					bridge.emplace_back(u, v);
					check[u][i].second = 1;
					check[v][check[u][i].first].second = 1;
				}
			}
			else if (v != p || q != check[u][i].first) {
				low[u] = min(low[u], ord[v]);
			}
		}
	}
	void restrict_dfs(int u, int p, int kind, queue<int>& que)
	{
		visit[u] = true;
		cmp[u] = kind;
		for (int i = 0; i < (int)G[u].size(); i++) {
			int v = G[u][i];
			if (check[u][i].second) {
				if (!visit[v]) {
					que.push(v);
				}
			}
			else if (!visit[v]) {
				restrict_dfs(v, u, kind, que);
			}
		}
	}
	void rebuild()
	{
		kind = 0;
		fill(visit, visit + V, false);
		for (int i = 0; i < V; i++) {
			if (!visit[i]) {
				queue<int> que;
				que.push(i);
				while (!que.empty()) {
					int p = que.front();
					que.pop();
					restrict_dfs(p, -1, kind, que);
					kind++;
				}
			}
		}
	}
public:
	int V, kind;
	vector<vector<int> > G, tree;
	vector<vector<pair<int, int> > > check;
	vector<pair<int, int> > bridge;
	vector<int> ord, low, cmp;
	bool *visit;
	biconnected(int node_size)
		: V(node_size), kind(0), G(V), check(V), ord(V), low(V)
		, cmp(V), visit(new bool[V]()) {}
	// ~biconnected(){ delete[] visit; }
	void add_edge(int u, int v)
	{
		G[u].push_back(v), G[v].push_back(u);
		check[u].emplace_back((int)check[v].size(), 0);
		check[v].emplace_back((int)check[u].size() - 1, 0);
	}
	// 橋を検出する.
	void detect_bridge() {
		int id = 0;
		for (int i = 0; i < V; i++) {
			if (!visit[i]) {
				dfs(i, -1, id, -1);
			}
		}
	}
	// 2(辺)連結成分を頂点とする木(tree) を作る(事前に detect_bridge() を呼んでおく必要がある).
	// 木の頂点数を返す.
	// cmp[i] は元の頂点 i の含まれる頂点(2(辺)連結成分) を表す.
	int make_bctree()
	{
		rebuild();
		tree.resize(kind);
		for (int i = 0; i < (int)bridge.size(); i++) {
			int a = cmp[bridge[i].first], b = cmp[bridge[i].second];
			tree[a].push_back(b), tree[b].push_back(a);
		}
		return kind;
	}
};
vector<vector<int> > tree;
vector<vector<int> > XX;
vector<vector<int> > YY;
map<pair<int, int>, int> dir;
bool ok = true;
void dfs(int a, int p, set<int> &st1, set<int> &st2) {



	for (int i : tree[a]) {
		if (i != p) {
			set<int> B1;
			set<int> B2;
			dfs(i, a, B1, B2);
			if (!ok)break;
			if (st1.size() < B1.size()) {
				swap(st1, B1);
			}
			if (st2.size() < B2.size()) {
				swap(st2, B2);
			}
			for (const int &s : B1) {
				if (st2.count(s) == 0) {
					st1.insert(s);
				}
				else {
					st2.erase(s);
				}
			}
			for (const int &s : B2) {
				if (st1.count(s) == 0) {
					st2.insert(s);
				}
				else {
					st1.erase(s);
				}
			}
		}
	}

	


	for (int i = 0; i < XX[a].size(); i++) {
		if (st2.count(XX[a][i]) == 0) {
			st1.insert(XX[a][i]);
		}
		else {
			st2.erase(XX[a][i]);
		}
	}
	for (int i = 0; i < YY[a].size(); i++) {
		if (st1.count(YY[a][i]) == 0) {
			st2.insert(YY[a][i]);
		}
		else {
			st1.erase(YY[a][i]);
		}
	}

	if (st1.size() > 0 && st2.size() > 0) {
		ok = false;
	}

	if (st1.size() > 0) {
		dir[make_pair(a, p)] = 0;
		dir[make_pair(p, a)] = 1;
	}
	else {
		dir[make_pair(a, p)] = 1;
		dir[make_pair(p, a)] = 0;
	}


}
vector<pair<int, int> > res;
vector<vector<int> > g;
vector<int> V;

void dfs2(int a, int p = -1) {
	//cerr << a << endl;
	V[a] = 1;

	for (int i : g[a]) {
		if (i != p) {
			if (V[i] == 0) {
				dfs2(i, a);
				res.emplace_back(a + 1, i + 1);
			}
			else if (V[i] == 1) {
				res.emplace_back(a + 1, i + 1);
			}
		}
	}
	V[a] = 2;
}
signed main() {
	cin.tie(0);
	ios::sync_with_stdio(false);
	int N, M;
	cin >> N >> M;
	vector<pair<int, int> > vp(M);
	biconnected G(N);
	for (int i = 0; i < M; i++) {
		cin >> vp[i].first >> vp[i].second;
		vp[i].first--;
		vp[i].second--;
		G.add_edge(vp[i].first, vp[i].second);
	}
	G.detect_bridge();
	G.make_bctree();
	tree = G.tree;
	int S = tree.size();

	int K;
	cin >> K;
	int a, b;
	vector<pair<int, int> > A;
	XX.resize(S);
	YY.resize(S);
	for (int i = 0; i < K; i++) {
		cin >> a >> b;
		a--; b--;
		if (G.cmp[a] == G.cmp[b])continue;
		A.emplace_back(G.cmp[a], G.cmp[b]);
		XX[G.cmp[a]].push_back(i);
		YY[G.cmp[b]].push_back(i);
	}
	set<int> st1, st2;
	dfs(0, -1, st1, st2);
	if (!ok) {
		cout << "No" << endl;
		return 0;
	}
	g.resize(N);
	V.resize(N, 0);
	for (int i = 0; i < vp.size(); i++) {
		a = vp[i].first;
		b = vp[i].second;
		if (G.cmp[a] == G.cmp[b]) {
			g[a].push_back(b);
			g[b].push_back(a);
		}
		else {
			int d = dir[make_pair(G.cmp[a], G.cmp[b])];
			if (d == 0) {
				res.emplace_back(a + 1, b + 1);
			}
			else {
				res.emplace_back(b + 1, a + 1);
			}
		}
	}

	for (int i = 0; i < N; i++) {
		if (V[i] == 0) {
			dfs2(i);
		}
	}
	cout << "Yes" << endl;
	assert(res.size() == M);
	for (int i = 0; i < res.size(); i++) {
		cout << res[i].first << " " << res[i].second << endl;
	}
}


Measured memory_bytes: 21956