You are given a graph consisting of $n$ vertices and $m$ edges. It is not guaranteed that the given graph is connected. Some edges are already directed and you can't change their direction. Other edges are undirected and you have to choose some direction for all these edges.

You have to direct undirected edges in such a way that the resulting graph is directed and acyclic (i.e. the graph with all edges directed and having no directed cycles). Note that you have to direct all undirected edges.

You have to answer $t$ independent test cases.


-----Input-----

The first line of the input contains one integer $t$ ($1 \le t \le 2 \cdot 10^4$) — the number of test cases. Then $t$ test cases follow.

The first line of the test case contains two integers $n$ and $m$ ($2 \le n \le 2 \cdot 10^5$, $1 \le m \le min(2 \cdot 10^5, \frac{n(n-1)}{2})$) — the number of vertices and the number of edges in the graph, respectively.

The next $m$ lines describe edges of the graph. The $i$-th edge is described with three integers $t_i$, $x_i$ and $y_i$ ($t_i \in [0; 1]$, $1 \le x_i, y_i \le n$) — the type of the edge ($t_i = 0$ if the edge is undirected and $t_i = 1$ if the edge is directed) and vertices this edge connects (the undirected edge connects vertices $x_i$ and $y_i$ and directed edge is going from the vertex $x_i$ to the vertex $y_i$). It is guaranteed that the graph do not contain self-loops (i.e. edges from the vertex to itself) and multiple edges (i.e. for each pair ($x_i, y_i$) there are no other pairs ($x_i, y_i$) or ($y_i, x_i$)).

It is guaranteed that both sum $n$ and sum $m$ do not exceed $2 \cdot 10^5$ ($\sum n \le 2 \cdot 10^5$; $\sum m \le 2 \cdot 10^5$).


-----Output-----

For each test case print the answer — "NO" if it is impossible to direct undirected edges in such a way that the resulting graph is directed and acyclic, otherwise print "YES" on the first line and $m$ lines describing edges of the resulted directed acyclic graph (in any order). Note that you cannot change the direction of the already directed edges. If there are several answers, you can print any.


-----Example-----
Input
4
3 1
0 1 3
5 5
0 2 1
1 1 5
1 5 4
0 5 2
1 3 5
4 5
1 1 2
0 4 3
1 3 1
0 2 3
1 2 4
4 5
1 4 1
1 1 3
0 1 2
1 2 4
1 3 2

Output
YES
3 1
YES
2 1
1 5
5 4
2 5
3 5
YES
1 2
3 4
3 1
3 2
2 4
NO



-----Note-----

Explanation of the second test case of the example:

[Image]

Explanation of the third test case of the example:

[Image]

Difficulty: HARD

Solutions:
import sys
input = sys.stdin.readline

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

def print_list(l):
	print(' '.join(map(str, l)))
from collections import defaultdict as dc
N = int(input())
for _ in range(N):
	(n, m) = read_list()
	res = []
	gress = [0] * (n + 1)
	dn = dc(list)
	for _ in range(m):
		(d, x, y) = read_list()
		if d == 1:
			dn[x].append(y)
			gress[y] += 1
		res.append([d, x, y])
	zp = [i for i in range(1, n + 1) if gress[i] == 0]
	count = 0
	p = [0] * (n + 1)
	while zp:
		u = zp.pop()
		count += 1
		p[u] = count
		for v in dn[u]:
			gress[v] -= 1
			if gress[v] == 0:
				zp.append(v)
	if count == n:
		print('YES')
		for i in range(m):
			if res[i][0] == 1:
				print(res[i][1], res[i][2])
			elif p[res[i][1]] < p[res[i][2]]:
				print(res[i][1], res[i][2])
			else:
				print(res[i][2], res[i][1])
	else:
		print('NO')


t = int(input())
Maxn = 210000
while t > 0:
	t -= 1
	(n, m) = map(int, input().split())
	to = [[]]
	for i in range(0, n):
		to.append([])
	d = [0] * (n + 1)
	ran = [0] * (n + 1)
	q = []
	cnt = 0
	to[0].append(1)
	for i in range(0, m):
		(bj, u, v) = map(int, input().split())
		if bj:
			to[u].append(v)
			d[v] += 1
			q.append((u, v))
		else:
			q.append((u, v))
	que = []
	for i in range(1, n + 1):
		if d[i] == 0:
			que.append(i)
	while len(que):
		now = que.pop()
		cnt += 1
		ran[now] = cnt
		for i in to[now]:
			d[i] -= 1
			if d[i] == 0:
				que.append(i)
	if cnt != n:
		print('NO')
		continue
	print('YES')
	for i in q:
		if ran[i[0]] < ran[i[1]]:
			print(i[0], i[1])
		else:
			print(i[1], i[0])


from collections import defaultdict as dc
N = int(input())
for _ in range(N):
	(n, m) = map(int, input().split())
	res = []
	gress = [0] * (n + 1)
	dn = dc(list)
	for _ in range(m):
		(d, x, y) = map(int, input().split())
		if d == 1:
			dn[x].append(y)
			gress[y] += 1
		res.append([d, x, y])
	zp = [i for i in range(1, n + 1) if gress[i] == 0]
	count = 0
	p = [0] * (n + 1)
	while zp:
		u = zp.pop()
		count += 1
		p[u] = count
		for v in dn[u]:
			gress[v] -= 1
			if gress[v] == 0:
				zp.append(v)
	if count == n:
		print('YES')
		for (d, x, y) in res:
			if d == 1:
				print(x, y)
			elif p[x] < p[y]:
				print(x, y)
			else:
				print(y, x)
	else:
		print('NO')


(n, m) = (int(), int())
gr = []
order = []
was = []

def pseudo_dfs(ver):
	was[ver] = 1
	good = True
	stck = [ver]
	while len(stck) > 0:
		ver = stck[-1]
		while len(gr[ver]) > 0:
			to = gr[ver][-1]
			if was[to] == 1:
				good = False
			if was[to] == 0:
				stck.append(to)
				was[to] = 1
				break
			gr[ver].pop()
		if len(gr[ver]) == 0:
			was[ver] = 2
			order.append(ver)
			stck.pop()
	return good
t = int(input())
for _ in range(t):
	(n, m) = map(int, input().split())
	gr = [[] for _ in range(n)]
	ed = []
	for _ in range(m):
		(type, x, y) = map(int, input().split())
		x -= 1
		y -= 1
		ed.append((type, x, y))
		if type == 1:
			gr[x].append(y)
	was = [0 for _ in range(n)]
	good = True
	order.clear()
	for i in range(n):
		if was[i] == 0:
			good &= pseudo_dfs(i)
	if good == False:
		print('NO')
		continue
	num_in_order = [0 for _ in range(n)]
	for (num, elem) in enumerate(order):
		num_in_order[elem] = num
	print('YES')
	for e in ed:
		if e[0] == 0 and num_in_order[e[1]] < num_in_order[e[2]]:
			print(e[2] + 1, e[1] + 1)
		else:
			print(e[1] + 1, e[2] + 1)


import itertools

def main():
	t = int(input())
	for _ in range(t):
		(n, m) = map(int, input().split())
		Z = []
		G = [[] for _ in range(n)]
		deg = [0] * n
		for i in range(m):
			(temp, x, y) = map(int, input().split())
			x -= 1
			y -= 1
			if temp == 0:
				Z.append((x, y))
			else:
				G[x].append(y)
				deg[y] += 1
				Z.append((x, y))
		topo_list = topological(G, deg)
		if len(topo_list) < n:
			print('NO')
			continue
		print('YES')
		dic = {}
		for (i, x) in enumerate(topo_list):
			dic[x] = i
		for (x, y) in Z:
			if dic[x] < dic[y]:
				ans = [x + 1, y + 1]
			else:
				ans = [y + 1, x + 1]
			print(*ans)

def topological(graph, deg):
	start = []
	n = len(deg)
	for i in range(n):
		if deg[i] == 0:
			start.append(i)
	topo = []
	while start:
		v = start.pop()
		topo.append(v)
		for u in graph[v]:
			deg[u] -= 1
			if deg[u] == 0:
				start.append(u)
	return topo
main()


from sys import stdin, setrecursionlimit
input = stdin.readline

def solve():
	(n, m) = map(int, input().split())
	adj = [[] for _ in range(n)]
	edges = []
	deg = [0] * n
	for _ in range(m):
		(d, u, v) = map(int, input().split())
		u -= 1
		v -= 1
		edges.append((u, v))
		if d == 1:
			adj[u].append(v)
			deg[v] += 1
	pos = [0] * n
	idx = 0
	st = [i for i in range(n) if deg[i] == 0]
	while len(st) > 0:
		u = st.pop()
		pos[u] = idx
		idx += 1
		for v in adj[u]:
			deg[v] -= 1
			if deg[v] == 0:
				st.append(v)
	if idx < n:
		print('NO')
		return
	print('YES')
	for (x, y) in edges:
		if pos[x] < pos[y]:
			print(x + 1, y + 1)
		else:
			print(y + 1, x + 1)

def main():
	t = int(input())
	for _ in range(t):
		solve()
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')

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)
mod = 998244353
INF = float('inf')
from math import factorial
from collections import Counter, defaultdict, deque
from heapq import heapify, heappop, heappush
from types import GeneratorType

def bootstrap(f, stack=[]):

	def wrappedfunc(*args, **kwargs):
		if stack:
			return f(*args, **kwargs)
		else:
			to = f(*args, **kwargs)
			while True:
				if type(to) is GeneratorType:
					stack.append(to)
					to = next(to)
				else:
					stack.pop()
					if not stack:
						break
					to = stack[-1].send(to)
			return to
	return wrappedfunc

def main():
	for _ in range(N()):
		(n, m) = RL()
		gp = [[[], []] for _ in range(n + 1)]
		ind = [0] * (n + 1)
		edgs = []
		q = []
		for _ in range(m):
			(t, x, y) = RL()
			if t == 0:
				gp[x][0].append(y)
				gp[y][0].append(x)
			else:
				gp[x][1].append(y)
				ind[y] += 1
			edgs.append([x, y])
		for i in range(1, n + 1):
			if ind[i] == 0:
				q.append(i)
		ct = 0
		sq = [0] * (n + 1)
		while q:
			nd = q.pop()
			ct += 1
			sq[nd] = ct
			for nex in gp[nd][1]:
				ind[nex] -= 1
				if ind[nex] == 0:
					q.append(nex)
		if ct == n:
			print('YES')
			for (a, b) in edgs:
				(sa, sb) = (sq[a], sq[b])
				if sa < sb:
					print(a, b)
				else:
					print(b, a)
		else:
			print('NO')
main()


from sys import stdin, stdout

def directing_edges(n, m, ind, dic, seq):
	q = []
	res = []
	for i in range(n):
		if ind[i] == 0:
			q.append(i)
	while len(q) > 0:
		cur = q.pop()
		res.append(cur)
		if cur in dic:
			for next in dic[cur]:
				ind[next] -= 1
				if ind[next] == 0:
					q.append(next)
	if len(res) < n:
		stdout.write('NO\n')
	else:
		stdout.write('YES\n')
		pos = [0] * n
		for i in range(n):
			pos[res[i]] = i
		for sq in seq:
			if pos[sq[0]] < pos[sq[1]]:
				print(sq[0] + 1, sq[1] + 1)
			else:
				print(sq[1] + 1, sq[0] + 1)
t = int(stdin.readline())
for i in range(t):
	(n, m) = map(int, stdin.readline().split())
	dic = {}
	ind = [0] * n
	seq = []
	for j in range(m):
		(t, x, y) = map(int, stdin.readline().split())
		x -= 1
		y -= 1
		seq.append([x, y])
		if t == 1:
			if x not in dic:
				dic[x] = []
			dic[x].append(y)
			ind[y] += 1
	directing_edges(n, m, ind, dic, seq)


def solve():
	(n, m) = map(int, input().split())
	edges = []
	adj = [[] for _ in range(n)]
	indeg = [0] * n
	for _ in range(m):
		(t, x, y) = map(int, input().split())
		x -= 1
		y -= 1
		edges.append((x, y))
		if t == 1:
			adj[x].append(y)
			indeg[y] += 1
	q = [i for i in range(n) if indeg[i] == 0]
	count = 0
	order = [0] * n
	while q:
		top = q.pop()
		order[top] = count
		count += 1
		for nei in adj[top]:
			indeg[nei] -= 1
			if indeg[nei] == 0:
				q.append(nei)
	if count < n:
		print('NO')
		return
	print('YES')
	for (x, y) in edges:
		if order[x] > order[y]:
			(x, y) = (y, x)
		print(x + 1, y + 1)
t = int(input())
for _ in range(t):
	solve()


for _ in range(int(input())):
	(n, m) = map(int, input().split())
	g = {i: [] for i in range(1, n + 1)}
	(indegree, rnk) = ([0] * (n + 1), [0] * (n + 1))
	edge = []
	for __ in range(m):
		(t, u, v) = map(int, input().split())
		if t:
			g[u].append(v)
			indegree[v] += 1
		edge.append((u, v))
	stack = []
	for i in range(1, n + 1):
		if indegree[i] == 0:
			stack.append(i)
	cnt = 0
	while stack:
		u = stack.pop()
		(rnk[u], cnt) = (cnt + 1, cnt + 1)
		for v in g[u]:
			indegree[v] -= 1
			if indegree[v] == 0:
				stack.append(v)
	if cnt != n:
		print('NO')
	else:
		print('YES')
		for x in edge:
			print(*x) if rnk[x[0]] < rnk[x[1]] else print(*x[::-1])


import sys
input = sys.stdin.readline
t = int(input())
for _ in range(t):
	(n, m) = map(int, input().split())
	g = [[] for i in range(n)]
	edges = []
	in_deg = [0] * n
	for __ in range(m):
		(ty, u, v) = map(int, input().split())
		edges.append([u - 1, v - 1])
		if ty == 1:
			g[u - 1].append(v - 1)
			in_deg[v - 1] += 1
	q = [i for i in range(n) if in_deg[i] == 0]
	cnt = 0
	order = [0] * n
	while q:
		v = q.pop()
		order[v] = cnt
		cnt += 1
		for to in g[v]:
			in_deg[to] -= 1
			if in_deg[to] == 0:
				q.append(to)
	if cnt < n:
		print('NO')
		continue
	print('YES')
	for (x, y) in edges:
		if order[x] > order[y]:
			print(y + 1, x + 1)
		else:
			print(x + 1, y + 1)


t = int(input())
while t:
	t -= 1
	(n, m) = map(int, input().split())
	ed = []
	graph = []
	for i in range(n + 1):
		graph.append([])
	deg = [0] * (n + 1)
	for i in range(m):
		(x, u, v) = map(int, input().split())
		if x == 1:
			graph[u].append(v)
			deg[v] += 1
		ed.append([u, v])
	q = []
	for i in range(1, n + 1):
		if deg[i] == 0:
			q.append(i)
	ord = [0] * (n + 1)
	cnt = 0
	while len(q) > 0:
		cur = q.pop()
		cnt += 1
		ord[cur] = cnt
		for i in graph[cur]:
			deg[i] -= 1
			if deg[i] == 0:
				q.append(i)
	if cnt != n:
		print('NO')
		continue
	print('YES')
	for i in ed:
		if ord[i[0]] > ord[i[1]]:
			print(i[1], i[0])
		else:
			print(i[0], i[1])


import bisect as bi
import math as mt
import collections as cc
I = lambda : list(map(int, input().split()))

def topo(g):
	indg = [0] * (n + 1)
	for i in range(1, n + 1):
		for j in g[i]:
			indg[j] += 1
	st = cc.deque()
	for i in range(1, n + 1):
		if indg[i] == 0:
			st.append(i)
	ans = []
	while st:
		x = st.pop()
		ans.append(x)
		for y in g[x]:
			indg[y] -= 1
			if indg[y] == 0:
				st.append(y)
	return ans
for tc in range(int(input())):
	(n, m) = I()
	g = cc.defaultdict(list)
	ed = []
	for i in range(m):
		(f, x, y) = I()
		ed.append([x, y])
		if f == 1:
			g[x].append(y)
	top = topo(g)
	if len(top) < n:
		print('NO')
	else:
		print('YES')
		inn = {}
		for i in range(n):
			inn[top[i]] = i
		for i in range(len(ed)):
			(x, y) = ed[i]
			if inn[x] > inn[y]:
				(x, y) = (y, x)
			print(x, y)


import sys
from collections import deque
input = sys.stdin.buffer.readline
print = sys.stdout.write
T = int(input())
for _ in range(T):
	(n, m) = map(int, input().split())
	(e, inc) = ([[] for _ in range(n + 1)], [0] * (n + 1))
	edges = []
	for _ in range(m):
		(a, b, c) = map(int, input().split())
		edges.append((b, c))
		if a == 1:
			e[b].append(c)
			inc[c] += 1
	q = [u for u in range(1, n + 1) if inc[u] == 0]
	tp = []
	while q:
		u = q.pop()
		tp.append(u)
		for v in e[u]:
			inc[v] -= 1
			if inc[v] == 0:
				q.append(v)
	if len(tp) < n:
		print('NO\n')
		continue
	order = [0] * (n + 1)
	for (i, u) in enumerate(tp):
		order[u] = i
	print('YES\n')
	for (b, c) in edges:
		if order[b] < order[c]:
			print('%d %d\n' % (b, c))
		else:
			print('%d %d\n' % (c, b))


from collections import defaultdict as dc

def tpsort():
	q = [i for i in range(1, n + 1) if ins[i] == 0]
	tpcnt = 0
	while q:
		ele = q.pop()
		tp[ele] = tpcnt
		tpcnt += 1
		for each in di[ele]:
			ins[each] -= 1
			if ins[each] == 0:
				q.append(each)
	return tpcnt == n
for _ in range(int(input())):
	(n, m) = map(int, input().split())
	di = dc(list)
	edges = []
	ins = [0] * (n + 1)
	tp = [0] * (n + 1)
	for i in range(m):
		(t, a, b) = map(int, input().split())
		edges.append([t, a, b])
		if t == 1:
			di[a].append(b)
			ins[b] += 1
	x = tpsort()
	if not x:
		print('NO')
	else:
		print('YES')
		for (t, a, b) in edges:
			if t == 0:
				if tp[a] > tp[b]:
					print(b, a)
				else:
					print(a, b)
			else:
				print(a, b)


import sys
from functools import lru_cache, cmp_to_key
from heapq import merge, heapify, heappop, heappush, nsmallest
from math import ceil, floor, gcd, fabs, factorial, fmod, sqrt, inf
from collections import defaultdict as dd, deque, Counter as C
from itertools import combinations as comb, permutations as perm
from bisect import bisect_left as bl, bisect_right as br, bisect
from time import perf_counter
from fractions import Fraction
from decimal import Decimal
mod = pow(10, 9) + 7
mod2 = 998244353

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

def out(var):
	sys.stdout.write(str(var) + '\n')

def outa(*var, end='\n'):
	sys.stdout.write(' '.join(map(str, var)) + end)

def l():
	return list(sp())

def sl():
	return list(ssp())

def sp():
	return map(int, data().split())

def ssp():
	return map(str, data().split())

def l1d(n, val=0):
	return [val for i in range(n)]

def l2d(n, m, val=0):
	return [l1d(n, val) for j in range(m)]

def kahn():
	q = []
	for i in range(1, n + 1):
		if not indeg[i]:
			q.append(i)
	time = 0
	while q:
		source = q.pop()
		order[source] = time
		for child in graph[source]:
			indeg[child] -= 1
			if not indeg[child]:
				q.append(child)
		time += 1
	for i in indeg:
		if i:
			return False
	return True
for _ in range(int(data())):
	(n, m) = sp()
	graph = [set() for i in range(n + 1)]
	edges = []
	(indeg, vis) = ([0] * (n + 1), [0] * (n + 1))
	for i in range(m):
		(f, u, v) = sp()
		edges.append([u, v])
		if f:
			graph[u].add(v)
			indeg[v] += 1
	order = [0] * (n + 1)
	if not kahn():
		out('NO')
		continue
	out('YES')
	for (a, b) in edges:
		if order[a] > order[b]:
			out('{} {}'.format(b, a))
			continue
		out('{} {}'.format(a, b))


for _ in range(int(input())):
	(n, m) = map(int, input().split())
	edge = []
	cnt = [0 for i in range(n + 1)]
	h = [[] for i in range(n + 1)]
	for i in range(m):
		(k, x, y) = map(int, input().split())
		edge.append((x, y))
		if k == 1:
			h[x].append(y)
			cnt[y] += 1
	pos = [0 for i in range(n + 1)]
	temp = 0
	arr = []
	for i in range(1, n + 1):
		if cnt[i] == 0:
			arr.append(i)
	while arr != []:
		node = arr.pop()
		pos[node] = temp
		temp += 1
		for i in h[node]:
			cnt[i] -= 1
			if cnt[i] == 0:
				arr.append(i)
	if temp != n:
		print('NO')
	else:
		print('YES')
		for (x, y) in edge:
			if pos[x] < pos[y]:
				print(x, y)
				continue
			print(y, x)


import sys
input = sys.stdin.readline
t = int(input())
for xx in range(t):
	(n, m) = list(map(int, input().split()))
	E = []
	N = [[] for _ in range(n)]
	IN = [0 for _ in range(n)]
	for _ in range(m):
		(a, b, c) = list(map(int, input().split()))
		b -= 1
		c -= 1
		E.append((b, c))
		if a == 1:
			N[b].append(c)
			IN[c] += 1
	Q = []
	for i in range(n):
		if IN[i] == 0:
			Q.append(i)
	count = 0
	OR = [0 for _ in range(n)]
	while Q:
		curr = Q.pop()
		OR[curr] = count
		count += 1
		for child in N[curr]:
			IN[child] -= 1
			if IN[child] == 0:
				Q.append(child)
	if count < n:
		print('NO')
	else:
		print('YES')
		for edge in E:
			(x, y) = (edge[0], edge[1])
			if OR[x] > OR[y]:
				(x, y) = (y, x)
			print(x + 1, y + 1)


import sys
input = sys.stdin.readline
for f in range(int(input())):
	(n, m) = map(int, input().split())
	neig = [0] * n
	upn = [0] * n
	for i in range(n):
		neig[i] = [0]
		upn[i] = []
	lown = [0] * n
	edges = []
	for i in range(m):
		(t, a, b) = map(int, input().split())
		a -= 1
		b -= 1
		edges.append([a, b])
		neig[a][0] += 1
		neig[b][0] += 1
		neig[a].append(b)
		neig[b].append(a)
		if t == 1:
			lown[b] += 1
			upn[a].append(b)
	levs = [0] * n
	for i in range(n):
		levs[i] = []
	level = [0] * n
	tod = []
	for i in range(n):
		if lown[i] == 0:
			tod.append(i)
	while len(tod) > 0:
		v = tod.pop()
		levs[level[v]].append(v)
		for u in upn[v]:
			level[v] = level[u] + 1
			lown[u] -= 1
			if lown[u] == 0:
				tod.append(u)
	poss = True
	for i in range(n):
		if lown[i] > 0:
			poss = False
	if poss:
		print('YES')
		height = [0] * n
		i = 0
		for l in levs:
			for u in l:
				height[u] = i
				i += 1
		for e in edges:
			(a, b) = (e[0], e[1])
			if height[a] < height[b]:
				print(a + 1, b + 1)
			else:
				print(b + 1, a + 1)
	else:
		print('NO')