package main

// https://ei1333.github.io/luzhiled/snippets/graph/lowlink.html

import (
	"bufio"
	"fmt"
	"os"
	"sort"
	"strconv"
)

var scanner = bufio.NewScanner(os.Stdin)

func nextString() string {
	scanner.Scan()
	return scanner.Text()
}

func nextInt() int {
	n, err := strconv.Atoi(nextString())
	if err != nil {
		fmt.Printf("strconv.Atoi failed: %v\n", err)
	}
	return n
}

func newGraph(nNodes int) *Graph {
	g := Graph{}
	g.nodes = make([]*GraphNode, nNodes)
	for iNode := 0; iNode < len(g.nodes); iNode++ {
		g.nodes[iNode] = &GraphNode{}
		g.nodes[iNode].key = GraphNodeKey(iNode)
	}
	return &g
}

var infty = 1000000000

type GraphNodeKey int

// GraphNode is a node for undirected graph
type GraphNode struct {
	key       GraphNodeKey
	adjacents []*GraphNode
	visited   bool
	d, f      int
	parent    *GraphNode
	cc        int

	low             int // 22-2 c.
	is_articulation bool
}

func (g *Graph) setAdjacent(l, r GraphNodeKey) {
	g.nodes[l].adjacents = append(g.nodes[l].adjacents, g.nodes[r])
}

// Graph is a undirected graph
type Graph struct {
	nodes []*GraphNode
}

func (g *Graph) initialize() {
	for iNode := 0; iNode < len(g.nodes); iNode++ {
		g.nodes[iNode].visited = false
		g.nodes[iNode].d = infty
		g.nodes[iNode].f = infty
		g.nodes[iNode].parent = nil
		g.nodes[iNode].cc = -1 // 22.3-12
	}
}

var time = 0
var visitedNodes = []*GraphNode{}

func min(x, y int) int {
	if x < y {
		return x
	}
	return y
}

func dfsVisit(g *Graph, u *GraphNode, cc int) {
	time++
	u.d = time
	u.cc = cc

	u.visited = true
	for _, v := range u.adjacents {
		if !v.visited {
			v.parent = u
			dfsVisit(g, v, cc)
		}
	}
	time++
	u.f = time
	visitedNodes = append(visitedNodes, u)
}

func runDFS(g *Graph) {
	g.initialize()
	time = 0
	cc := 0

	for _, u := range g.nodes {
		if !u.visited {
			dfsVisit(g, u, cc)
			cc++
		}
	}
}

var bridges = [][]GraphNodeKey{}

func fillLowLink(graph *Graph) {
	for _, node := range visitedNodes {
		node.low = node.d
		node.is_articulation = false

		for _, adjacent := range node.adjacents {
			if adjacent.parent == node { // G_\pi上で node -> adjacent
				node.low = min(node.low, adjacent.low)
				node.is_articulation = node.is_articulation || (node.parent != nil && adjacent.low >= node.d)
				if adjacent.low > node.d {
					k1, k2 := node.key, adjacent.key
					if k1 > k2 {
						k1, k2 = k2, k1
					}
					bridges = append(bridges, []GraphNodeKey{k1, k2})
				}
			} else if adjacent != node.parent { // G上では繋がっているが、G_\pi上では繋がっていない
				node.low = min(node.low, adjacent.d)
			}
		}

		nChildren := 0
		for _, adjacent := range node.adjacents {
			if adjacent.parent == node {
				nChildren++
			}
		}
		node.is_articulation = node.is_articulation || (node.parent == nil && nChildren >= 2)
	}
}

func main() {
	scanner.Split(bufio.ScanWords)

	nNodes := nextInt()
	nEdges := nextInt()
	graph := newGraph(nNodes)
	for iEdge := 0; iEdge < nEdges; iEdge++ {
		l := GraphNodeKey(nextInt())
		r := GraphNodeKey(nextInt())
		graph.setAdjacent(l, r)
		graph.setAdjacent(r, l)
	}

	runDFS(graph)

	fillLowLink(graph)

	sort.Slice(bridges, func(i, j int) bool {
		if bridges[i][0] == bridges[j][0] {
			return bridges[i][1] < bridges[j][1]
		}
		return bridges[i][0] < bridges[j][0]
	})
	for _, bridge := range bridges {
		fmt.Println(bridge[0], bridge[1])
	}
}



Measured memory_bytes: 8912