Bertown has n junctions and m bidirectional roads. We know that one can get from any junction to any other one by the existing roads. 

As there were more and more cars in the city, traffic jams started to pose real problems. To deal with them the government decided to make the traffic one-directional on all the roads, thus easing down the traffic. Your task is to determine whether there is a way to make the traffic one-directional so that there still is the possibility to get from any junction to any other one. If the answer is positive, you should also find one of the possible ways to orient the roads.

Input

The first line contains two space-separated integers n and m (2 ≤ n ≤ 105, n - 1 ≤ m ≤ 3·105) which represent the number of junctions and the roads in the town correspondingly. Then follow m lines, each containing two numbers which describe the roads in the city. Each road is determined by two integers ai and bi (1 ≤ ai, bi ≤ n, ai ≠ bi) — the numbers of junctions it connects.

It is guaranteed that one can get from any junction to any other one along the existing bidirectional roads. Each road connects different junctions, there is no more than one road between each pair of junctions.

Output

If there's no solution, print the single number 0. Otherwise, print m lines each containing two integers pi and qi — each road's orientation. That is the traffic flow will move along a one-directional road from junction pi to junction qi. You can print the roads in any order. If there are several solutions to that problem, print any of them.

Examples

Input

6 8
1 2
2 3
1 3
4 5
4 6
5 6
2 4
3 5


Output

1 2
2 3
3 1
4 5
5 6
6 4
4 2
3 5


Input

6 7
1 2
2 3
1 3
4 5
4 6
5 6
2 4


Output

0

Source: codeforces | Difficulty: HARD
Tags: Graph algorithms

Graph traversal


Solutions:
from sys import stdin, setrecursionlimit
import threading
input = lambda : stdin.readline().rstrip('\r\n')
from collections import deque as que
inin = lambda : int(input())
inar = lambda : list(map(int, input().split()))
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
from collections import defaultdict
adj = defaultdict(list)
visited = [False] * 100001
intime = [0] * 100001
outtime = [0] * 100001
res = []
bridge = False
timer = 0

@bootstrap
def dfs(node, par):
	global adj, visited, intime, outtime, res, bridge, timer
	visited[node] = True
	intime[node] = timer
	outtime[node] = timer
	timer += 1
	for j in adj[node]:
		if j == par:
			continue
		if visited[j]:
			outtime[node] = min(outtime[node], intime[j])
			if intime[node] > intime[j]:
				res.append((node, j))
		else:
			yield dfs(j, node)
			if outtime[j] > intime[node]:
				bridge = True
				yield None
			res.append((node, j))
			outtime[node] = min(outtime[node], outtime[j])
	yield

def main():
	(n, m) = map(int, input().split())
	global adj, visited, intime, outtime, res, bridge, timer
	timer = 0
	bridge = False
	for i in range(m):
		(u, v) = map(int, input().split())
		adj[u].append(v)
		adj[v].append(u)
	dfs(1, -1)
	if bridge:
		print(0)
	else:
		for i in range(len(res)):
			print(*res[i])
main()


from sys import stdin
input = lambda : stdin.readline().rstrip('\r\n')
from collections import deque as que
inin = lambda : int(input())
inar = lambda : list(map(int, input().split()))
from collections import defaultdict
adj = defaultdict(list)
visited = [False] * 100001
intime = [0] * 100001
outtime = [0] * 100001
res = []
bridge = False
timer = 0

def dfs(root, p):
	global adj, visited, intime, outtime, res, bridge, timer
	visited[root] = True
	intime[root] = timer
	outtime[root] = timer
	timer += 1
	bridge = False
	stack = [(root, p, adj[root].__iter__())]
	while stack:
		(node, par, i) = stack.pop()
		try:
			j = next(i)
			stack.append((node, par, i))
			if j == par:
				continue
			if visited[j]:
				outtime[node] = min(outtime[node], intime[j])
				if intime[node] > intime[j]:
					res.append((node, j))
			else:
				visited[j] = True
				intime[j] = outtime[j] = timer
				timer += 1
				stack.append((j, node, adj[j].__iter__()))
		except StopIteration:
			if node == root:
				continue
			if outtime[node] > intime[par]:
				bridge = True
				return
			res.append((par, node))
			outtime[par] = min(outtime[par], outtime[node])

def main():
	(n, m) = map(int, input().split())
	global adj, visited, intime, outtime, res, bridge, timer
	timer = 0
	bridge = False
	for i in range(m):
		(u, v) = map(int, input().split())
		adj[u].append(v)
		adj[v].append(u)
	dfs(1, -1)
	if bridge:
		print(0)
	else:
		for i in range(len(res)):
			print(*res[i])
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 threading import stack_size, Thread
sys.setrecursionlimit(10 ** 6)
stack_size(2 ** 25)
timer = 0
g = False
dic = {}
visited = {}
in_time = []
low = []
edges = []

def dfs(node, parent):
	global timer
	visited[node] = 1
	in_time[node] = low[node] = timer
	timer += 1
	for i in dic[node]:
		if i == parent:
			continue
		if visited[i] == 1:
			low[node] = min(low[node], in_time[i])
			if in_time[node] > in_time[i]:
				edges.append((node, i))
		else:
			dfs(i, node)
			if low[i] > in_time[node]:
				global g
				g = True
				return
			edges.append((node, i))
			low[node] = min(low[node], low[i])

def main():
	for _ in range(1):
		(n, m) = map(int, input().split())
		global dic
		for i in range(m):
			(u, v) = map(int, input().split())
			if u in dic:
				dic[u].append(v)
			else:
				dic[u] = [v]
			if v in dic:
				dic[v].append(u)
			else:
				dic[v] = [u]
		global visited, in_time, low, edges
		in_time = [0] * (n + 1)
		low = [0] * (n + 1)
		for i in range(1, n + 1):
			visited[i] = 0
		dfs(1, -1)
		if g:
			print(0)
		else:
			for (i, j) in edges:
				print(i, j)
Thread(target=main).start()


from collections import defaultdict
import os
import sys
from io import BytesIO, IOBase
from types import GeneratorType
from collections import defaultdict
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')
sys.setrecursionlimit(3 * 10 ** 4)

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

@bootstrap
def dfs(u, p):
	for j in adj[u]:
		if j != p:
			if id[j] == 0:
				id[j] = id[u] + 1
				yield dfs(j, u)
			elif id[u] > id[j]:
				up[u] += 1
				down[j] += 1
	yield

@bootstrap
def dfs2(u, p):
	val[u] = up[u] - down[u]
	for j in adj[u]:
		if j != p:
			if id[j] == 0:
				id[j] = id[u] + 1
				ans.append([u, j])
				yield dfs2(j, u)
				val[u] += val[j]
			elif id[u] > id[j]:
				ans.append([u, j])
	yield
(n, m) = map(int, input().split())
adj = [[] for i in range(n + 1)]
edges = []
for j in range(m):
	(u, v) = map(int, input().split())
	adj[u].append(v)
	adj[v].append(u)
up = defaultdict(lambda : 0)
down = defaultdict(lambda : 0)
id = [0] * (n + 1)
id[1] = 1
dfs(1, 0)
val = [0] * (n + 1)
id = [0] * (n + 1)
id[1] = 1
ans = []
dfs2(1, 0)
poss = 1
for j in range(2, n + 1):
	if val[j] == 0:
		poss = 0
		break
if not poss:
	print(0)
else:
	for j in ans:
		print(*j)


def dfs(node: int, graph):
	time = 0
	n = len(graph)
	d = [-1] * n
	f = [-1] * n
	pi = [-1] * n
	low = [n + 1] * n
	orientation = []
	stack = []
	stack.append(node)
	pi[node] = node
	while stack:
		s = stack.pop()
		if d[s] == -1:
			d[s] = time
			time += 1
			stack.append(s)
			low[s] = d[s]
			if pi[s] != s:
				orientation.append((pi[s], s))
			for v in graph[s]:
				if d[v] == -1:
					stack.append(v)
					pi[v] = s
				elif pi[s] != v:
					low[s] = min(low[s], low[v])
					orientation.append((s, v))
		elif f[s] == -1:
			parent = pi[s]
			low[parent] = min(low[s], low[parent])
			if low[s] > d[parent]:
				return 0
			f[s] = time
			time += 1
	return (orientation, d, f, pi, low)
from sys import stdin, stdout
(n, m) = [int(x) for x in stdin.readline().split()]
graph = [[] for _ in range(n)]
for _ in range(m):
	(u, v) = [int(x) - 1 for x in stdin.readline().split()]
	graph[u].append(v)
	graph[v].append(u)
start = 0
for i in range(n):
	if len(graph[i]) < len(graph[start]):
		start = i
s = dfs(0, graph)
if s:
	for edge in s[0]:
		(u, v) = edge
		sol = f'{u + 1} {v + 1}\n'
		stdout.write(sol)
else:
	stdout.write(f'{s}')


from __future__ import division, print_function
import os
import sys
from io import BytesIO, IOBase
if sys.version_info[0] < 3:
	from __builtin__ import xrange as range
	from future_builtins import ascii, filter, hex, map, oct, zip
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')

def print(*args, **kwargs):
	(sep, file) = (kwargs.pop('sep', ' '), kwargs.pop('file', sys.stdout))
	at_start = True
	for x in args:
		if not at_start:
			file.write(sep)
		file.write(str(x))
		at_start = False
	file.write(kwargs.pop('end', '\n'))
	if kwargs.pop('flush', False):
		file.flush()
if sys.version_info[0] < 3:
	(sys.stdin, sys.stdout) = (FastIO(sys.stdin), FastIO(sys.stdout))
else:
	(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')

def main():
	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
	import time

	class Graph(object):

		def __init__(self):
			self.neighbours = {}

		def __repr__(self):
			s = ''
			for i in self.neighbours:
				s += str(i) + ': ' + ' '.join(map(str, self.neighbours[i])) + '\n'
			return s

		def add_node(self, node):
			self.neighbours[node] = set()

		def add_edge(self, edge):
			(u, v) = edge
			self.neighbours[u].add(v)
			self.neighbours[v].add(u)

		@bootstrap
		def dfs(self, node, par):
			visited[node] = 1
			intime[node] = lowtime[node] = timer[0]
			timer[0] += 1
			for child in self.neighbours[node]:
				if child == par:
					continue
				if visited[child] == 1:
					if intime[node] > intime[child]:
						lis.append([node, child])
					lowtime[node] = min(lowtime[node], intime[child])
				else:
					lis.append([node, child])
					yield self.dfs(child, node)
					if lowtime[child] > intime[node]:
						flag[0] = 0
					lowtime[node] = min(lowtime[node], lowtime[child])
			yield

		def bfs(self, node):
			q = queue()
			visited[node] = 1
			q.append(node)
			while q:
				cur = q.popleft()
				for child in self.neighbours[cur]:
					if visited[child] == 0:
						q.append(child)
						visited[child] = 1
	g = Graph()
	(n, m) = map(int, input().split())
	for i in range(n):
		g.add_node(i + 1)
	for i in range(m):
		(x, y) = map(int, input().split())
		g.add_edge((x, y))
	visited = [0] * (n + 1)
	intime = [0] * (n + 1)
	lowtime = [0] * (n + 1)
	timer = [0]
	flag = [1]
	lis = []
	g.dfs(1, -1)
	if flag[0]:
		for i in lis:
			print(' '.join(map(str, i)))
	else:
		print(0)
main()


from sys import stdin, stdout, setrecursionlimit
from collections import defaultdict
from threading import stack_size, Thread
setrecursionlimit(10 ** 6)
stack_size(2 ** 25)
adj = defaultdict(list)
visited = [False] * 100001
intime = [0] * 100001
outtime = [0] * 100001
res = []
bridge = False
timer = 0

def dfs(node, par):
	global adj, visited, intime, outtime, res, bridge, timer
	visited[node] = True
	intime[node] = timer
	outtime[node] = timer
	timer += 1
	for j in adj[node]:
		if j == par:
			continue
		if visited[j]:
			outtime[node] = min(outtime[node], intime[j])
			if intime[node] > intime[j]:
				res.append((node, j))
		else:
			dfs(j, node)
			if outtime[j] > intime[node]:
				bridge = True
				return
			res.append((node, j))
			outtime[node] = min(outtime[node], outtime[j])

def solve():
	(n, m) = map(int, stdin.readline().split())
	global adj, visited, intime, outtime, res, bridge, timer
	timer = 0
	bridge = False
	for i in range(m):
		(u, v) = map(int, stdin.readline().split())
		adj[u].append(v)
		adj[v].append(u)
	dfs(1, -1)
	if bridge:
		print(0)
	else:
		for i in range(len(res)):
			print(*res[i])
Thread(target=solve).start()


from __future__ import division, print_function
MOD = 998244353
mod = 10 ** 9 + 7
import threading
threading.stack_size(102400000)
import sys
sys.setrecursionlimit(2000000)
from collections import Counter, defaultdict, deque

def get_ints():
	return map(int, sys.stdin.readline().strip().split())

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

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

class Graph:

	def __init__(self, vertices):
		self.vertices = vertices
		self.graph = defaultdict(list)
		self.visited = [False] * (vertices + 1)
		self.timer = 0
		self.IN = [0] * (vertices + 1)
		self.LOW = [0] * (vertices + 1)
		self.bridge = False
		self.result = []

	def addEdge(self, x, y):
		self.graph[x].append(y)
		self.graph[y].append(x)

	def dfs(self, node, parent):
		self.visited[node] = True
		self.IN[node] = self.timer
		self.LOW[node] = self.timer
		self.timer += 1
		for child in self.graph[node]:
			if child == parent:
				continue
			if self.visited[child]:
				self.LOW[node] = min(self.LOW[node], self.IN[child])
				if self.IN[node] > self.IN[child]:
					self.result.append((node, child))
			else:
				self.dfs(child, node)
				if self.LOW[child] > self.IN[node]:
					self.bridge = True
					return
				self.result.append((node, child))
				self.LOW[node] = min(self.LOW[node], self.LOW[child])

	def count_bridges(self):
		self.dfs(1, -1)
		if self.bridge:
			print(0)
		else:
			for i in range(len(self.result)):
				print(*self.result[i])

def main():
	(n, m) = get_ints()
	graph = Graph(n)
	for i in range(m):
		(x, y) = get_ints()
		graph.addEdge(x, y)
	graph.count_bridges()
py2 = round(0.5)
if py2:
	from future_builtins import ascii, filter, hex, map, oct, zip
	range = xrange
import os, sys
from io import IOBase, BytesIO
BUFSIZE = 8192

class FastIO(BytesIO):
	newlines = 0

	def __init__(self, file):
		self._file = file
		self._fd = file.fileno()
		self.writable = 'x' in file.mode or 'w' in file.mode
		self.write = super(FastIO, self).write if self.writable else None

	def _fill(self):
		s = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
		self.seek((self.tell(), self.seek(0, 2), super(FastIO, self).write(s))[0])
		return s

	def read(self):
		while self._fill():
			pass
		return super(FastIO, self).read()

	def readline(self):
		while self.newlines == 0:
			s = self._fill()
			self.newlines = s.count(b'\n') + (not s)
		self.newlines -= 1
		return super(FastIO, self).readline()

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

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		if py2:
			self.write = self.buffer.write
			self.read = self.buffer.read
			self.readline = self.buffer.readline
		else:
			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')
threading.Thread(target=main).start()


import os
import sys
from io import BytesIO, IOBase

def main():
	(n, m) = map(int, input().split())
	graph = [[] for _ in range(n + 1)]
	for _ in range(m):
		(a, b) = map(int, input().split())
		graph[a].append(b)
		graph[b].append(a)
	visited = [0] * (n + 1)
	intime = [0] * (n + 1)
	low = [0] * (n + 1)
	timer = 0
	idx = [0] * (n + 1)
	parent = [0] * (n + 1)
	stack = [1]
	visited[1] = 1
	parent[1] = 1
	ans = set()
	while stack:
		x = stack[-1]
		y = idx[x]
		if y == len(graph[x]):
			stack.pop()
			for item in graph[x]:
				if item != parent[x]:
					low[x] = min(low[x], low[item])
			if low[x] > low[parent[x]]:
				print(0)
				exit()
		else:
			z = graph[x][y]
			if visited[z] == 0:
				timer += 1
				visited[z] = 1
				stack.append(z)
				intime[z] = timer
				low[z] = timer
				parent[z] = x
				ans.add((x, z))
			elif z != parent[x]:
				if (z, x) not in ans:
					ans.add((x, z))
			idx[x] += 1
	for item in ans:
		print(*item)
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 threading import stack_size, Thread
sys.setrecursionlimit(10 ** 6)
stack_size(2 ** 25)

def inputt():
	return sys.stdin.readline().strip()
timer = 0
g = False
dic = {}
visited = {}
in_time = []
low = []
edges = []

def dfs(node, parent):
	global timer
	visited[node] = 1
	in_time[node] = low[node] = timer
	timer += 1
	for i in dic[node]:
		if i == parent:
			continue
		if visited[i] == 1:
			low[node] = min(low[node], in_time[i])
			if in_time[node] > in_time[i]:
				edges.append((node, i))
		else:
			dfs(i, node)
			if low[i] > in_time[node]:
				global g
				g = True
				return
			edges.append((node, i))
			low[node] = min(low[node], low[i])

def main():
	for _ in range(1):
		(n, m) = map(int, inputt().split())
		global dic
		for i in range(m):
			(u, v) = map(int, inputt().split())
			if u in dic:
				dic[u].append(v)
			else:
				dic[u] = [v]
			if v in dic:
				dic[v].append(u)
			else:
				dic[v] = [u]
		global visited, in_time, low, edges
		in_time = [0] * (n + 1)
		low = [0] * (n + 1)
		for i in range(1, n + 1):
			visited[i] = 0
		dfs(1, -1)
		if g:
			print(0)
		else:
			for (i, j) in edges:
				print(i, j)
Thread(target=main).start()


from sys import stdin, setrecursionlimit
import threading
input = lambda : stdin.readline().rstrip('\r\n')
from collections import deque as que
inin = lambda : int(input())
inar = lambda : list(map(int, input().split()))
from collections import defaultdict
adj = defaultdict(list)
visited = [False] * 100001
intime = [0] * 100001
outtime = [0] * 100001
res = []
bridge = False
timer = 0

def dfs(node, par):
	global adj, visited, intime, outtime, res, bridge, timer
	visited[node] = True
	intime[node] = timer
	outtime[node] = timer
	timer += 1
	for j in adj[node]:
		if j == par:
			continue
		if visited[j]:
			outtime[node] = min(outtime[node], intime[j])
			if intime[node] > intime[j]:
				res.append((node, j))
		else:
			dfs(j, node)
			if outtime[j] > intime[node]:
				bridge = True
				return
			res.append((node, j))
			outtime[node] = min(outtime[node], outtime[j])

def main():
	(n, m) = map(int, input().split())
	global adj, visited, intime, outtime, res, bridge, timer
	timer = 0
	bridge = False
	for i in range(m):
		(u, v) = map(int, input().split())
		adj[u].append(v)
		adj[v].append(u)
	dfs(1, -1)
	if bridge:
		print(0)
	else:
		for i in range(len(res)):
			print(*res[i])
setrecursionlimit(1 << 30)
threading.stack_size(1 << 25)
main_thread = threading.Thread(target=main)
main_thread.start()
main_thread.join()


from sys import stdin, stdout, setrecursionlimit
from collections import defaultdict, deque
from threading import stack_size, Thread
setrecursionlimit(10 ** 6)
stack_size(2 ** 25)
graph = defaultdict(list)
bridge = False
vis = [0] * 100001
low = [0] * 100001
In = [0] * 100001
timer = 0
ans = []

def dfs(v, par):
	global graph, vis, In, low, ans, bridge, timer
	vis[v] = 1
	In[v] = timer
	low[v] = timer
	timer += 1
	if bridge == True:
		return None
	for i in graph[v]:
		if i == par:
			continue
		if vis[i] == 1:
			low[v] = min(low[v], In[i])
			if In[v] > In[i]:
				ans.append([v, i])
		else:
			dfs(i, v)
			if low[i] > In[v]:
				bridge = True
				return None
			ans.append([v, i])
			low[v] = min(low[v], low[i])

def solve():
	(n, m) = map(int, stdin.readline().split())
	global graph, vis, In, low, ans, bridge, timer
	timer = 0
	bridge = False
	for i in range(m):
		(a, b) = map(int, stdin.readline().split())
		graph[a].append(b)
		graph[b].append(a)
	dfs(1, -1)
	if bridge:
		print(0)
	else:
		for i in range(len(ans)):
			print(*ans[i])
Thread(target=solve).start()


from sys import stdout
WHITE = 0
GRAY = 1
BLACK = 2
to_print = []

def dfs_visit_iter(G, u, save):
	stack = []
	stack.append((u, 0))
	color = [0] * len(G)
	pi = [-1] * len(G)
	sol = []
	cant = 1
	while len(stack) != 0:
		(current, i) = stack[len(stack) - 1]
		color[current] = GRAY
		if i == len(G[current]):
			stack.pop()
			color[current] = BLACK
		else:
			while i < len(G[current]):
				v = G[current][i]
				if color[v] == WHITE:
					stack[len(stack) - 1] = (current, i + 1)
					cant += 1
					if save:
						sol.append((current, v))
						to_print.append(str(current + 1) + ' ' + str(v + 1))
					pi[v] = current
					stack.append((v, 0))
					break
				elif pi[current] != v:
					if color[v] == GRAY and save:
						sol.append((current, v))
						to_print.append(str(current + 1) + ' ' + str(v + 1))
				i += 1
				stack[len(stack) - 1] = (current, i)
	return (sol, cant)

def main():
	s = input().split(' ')
	n = int(s[0])
	m = int(s[1])
	G = [[] for i in range(n)]
	for _ in range(m):
		s = input().split(' ')
		n1 = int(s[0]) - 1
		n2 = int(s[1]) - 1
		G[n2].append(n1)
		G[n1].append(n2)
	(sol, _) = dfs_visit_iter(G, 0, True)
	G2 = [[] for i in range(n)]
	for (x, y) in sol:
		G2[y].append(x)
	(_, totalvisited) = dfs_visit_iter(G2, 0, False)
	if totalvisited != n:
		print(0)
		return
	stdout.write('\n'.join(to_print))
	stdout.write('\n')
main()


from sys import setrecursionlimit
from collections import defaultdict
from threading import stack_size, Thread
setrecursionlimit(1 << 30)
stack_size(2 ** 25)
edge = defaultdict(list)
visited = [False] * 100001
intime = [0] * 100001
low = [0] * 100001
l1 = []
bridge = False
timer = 0

def DFS(node, parent):
	global l1, edge, visited, intime, low, timer, bridge
	visited[node] = 1
	intime[node] = timer
	low[node] = timer
	timer += 1
	for child in edge[node]:
		if visited[child] == 1:
			if child == parent:
				pass
			else:
				low[node] = min(intime[child], low[node])
				if intime[node] > intime[child]:
					l1.append([node, child])
		else:
			DFS(child, node)
			if low[child] > intime[node]:
				bridge = True
				return None
			l1.append([node, child])
			low[node] = min(low[node], low[child])

def main():
	r = lambda : map(int, input().split())
	(n, m) = r()
	global edge, visited, intime, low, l1, bridge, timer
	for i in range(1, n + 1):
		edge[i] = []
		visited[i] = 0
		intime[i] = 0
		low[i] = 0
	for _ in range(m):
		(p, q) = r()
		edge[p].append(q)
		edge[q].append(p)
	DFS(1, -1)
	if bridge == True:
		print(0)
	else:
		for i in l1:
			print(*i)
Thread(target=main).start()


import os
from io import BytesIO, IOBase
import sys
sys.setrecursionlimit(10 ** 6)
import threading
threading.stack_size(2 ** 25)
vis = [0] * (10 ** 5 + 1)
low = [0] * (10 ** 5 + 1)
timer = 0
ans = 0
d = {1: [] for i in range(10 ** 6 + 1)}
intim = [0] * (10 ** 6 + 1)
arr = []

def dfs(child, par):
	global timer, ans, vis, low, d, arr, intim
	vis[child] = 1
	low[child] = intim[child] = timer
	timer += 1
	for i in d[child]:
		if i == par:
			continue
		if vis[i]:
			low[child] = min(low[child], intim[i])
			if intim[child] > intim[i]:
				arr.append([child, i])
		else:
			dfs(i, child)
			if low[i] > intim[child]:
				ans = 1
				return
			arr.append([child, i])
			low[child] = min(low[child], low[i])

def main():
	(n, m) = map(int, input().split())
	global vis, low, timer, d, intim, arr, ans
	d = {i: [] for i in range(n + 1)}
	for _ in range(m):
		(a, b) = map(int, input().split())
		d[a].append(b)
		d[b].append(a)
	ans = 0
	arr = []
	vis = [0] * (n + 1)
	low = [0] * (n + 1)
	timer = 0
	intim = [0] * (n + 1)
	dfs(1, -1)
	if ans == 1:
		print(0)
	else:
		for i in arr:
			print(i[0], i[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))

def input():
	return sys.stdin.readline().rstrip('\r\n')

def write(*args, end='\n'):
	for x in args[:-1]:
		sys.stdout.write(str(x) + ' ')
	sys.stdout.write(str(args[-1]))
	sys.stdout.write(end)

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

def r_int():
	return int(input())
threading.Thread(target=main).start()


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')
import threading
sys.setrecursionlimit(2000000)
threading.stack_size(10 ** 8)

def dfs(x, y):
	global v
	global e
	global t
	global ans
	global adj
	global l
	global route
	v[x] = 1
	e[x] = t
	l[x] = t
	t += 1
	for i in adj[x]:
		if i == y:
			continue
		if v[i]:
			l[x] = min(l[x], e[i])
			if e[x] > e[i]:
				route.append([x, i])
		else:
			dfs(i, x)
			if e[x] < l[i]:
				ans = False
			l[x] = min(l[x], l[i])
			route.append([x, i])

def main():
	global v
	global e
	global t
	global ans
	global adj
	global l
	global route
	global d
	route = []
	(n, m) = map(int, input().split())
	v = [0] * (n + 1)
	l = [0] * (n + 1)
	e = [0] * (n + 1)
	t = 0
	ans = True
	adj = []
	for i in range(n + 1):
		adj.append([])
	for i in range(m):
		(x, y) = map(int, input().split())
		adj[x].append(y)
		adj[y].append(x)
	dfs(1, -1)
	if ans == False:
		print(0)
	else:
		for i in route:
			print(*i)
z = threading.Thread(target=main)
z.start()
z.join()


import os, sys
from io import BytesIO, IOBase

def bridges(n, path):
	(poi, start, low, st, time) = ([0] * n, [0] * n, [10 ** 10] * n, [0], 0)
	(visi, edg) = ([1] + [0] * (n - 1), [])
	while len(st):
		(x, y) = (st[-1], path[st[-1]])
		while poi[x] != len(y) and visi[y[poi[x]]]:
			if len(st) > 1 and y[poi[x]] != st[-2]:
				low[x] = min(low[x], start[y[poi[x]]])
				if start[y[poi[x]]] < start[x]:
					edg.append((x + 1, y[poi[x]] + 1))
			poi[x] += 1
		if poi[x] == len(y):
			zz = st.pop()
			if len(st):
				low[st[-1]] = min(low[st[-1]], low[zz])
				if low[zz] > start[st[-1]]:
					return []
		else:
			time += 1
			i = y[poi[x]]
			visi[i] = 1
			st.append(i)
			start[i] = time
			poi[x] += 1
			edg.append((x + 1, i + 1))
	return edg

def main():
	(n, m) = map(int, input().split())
	path = [[] for _ in range(n)]
	for _ in range(m):
		(u1, v1) = map(lambda xx: int(xx) - 1, input().split())
		path[u1].append(v1)
		path[v1].append(u1)
	x = bridges(n, path)
	if not len(x):
		print(0)
	else:
		for i in x:
			print(*i)
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()


from sys import stdin, stdout, setrecursionlimit
from collections import defaultdict
from threading import stack_size, Thread
setrecursionlimit(10 ** 6)
stack_size(2 ** 25)
edge = defaultdict(list)
bridge = False
vis = [0] * 100001
low = [0] * 100001
inTime = [0] * 100001
timer = 0
ans = []

def dfs(node, parent):
	global edge, vis, inTime, low, ans, bridge, timer
	vis[node] = 1
	low[node] = timer
	inTime[node] = timer
	timer += 1
	for j in edge[node]:
		if j == parent:
			continue
		if vis[j] == 1:
			low[node] = min(low[node], inTime[j])
			if inTime[node] > inTime[j]:
				ans.append([node, j])
		else:
			dfs(j, node)
			if low[j] > inTime[node]:
				bridge = True
				return
			ans.append([node, j])
			low[node] = min(low[node], low[j])

def solve():
	(n, m) = map(int, stdin.readline().split())
	global edge, vis, inTime, low, ans, bridge, timer
	timer = 0
	bridge = False
	for i in range(m):
		(u, v) = map(int, stdin.readline().split())
		edge[u].append(v)
		edge[v].append(u)
	dfs(1, -1)
	if bridge:
		print(0)
	else:
		for i in range(len(ans)):
			print(*ans[i])
Thread(target=solve).start()