module SimpleUndirectedGraphic
    require 'set'

    def each_connected_component(&block)
        return enum_for(__method__) unless block_given?
        reached = Set.new
        each_node do |s|
            next if reached.include?(s)
            cc = Set[s]
            queue = [s]
            until queue.empty?
                u = queue.shift
                each_neighbour(u) do |v|
                    next if cc.include?(v)
                    cc << v
                    queue << v
                end
            end
            block.call(cc)
            reached += cc
        end
    end

    def connected_components
        each_connected_component.to_a
    end

    def dfs(root, callback = Hash.new())
        known = Set[
            :WHEN_VISIT,
            :WHEN_CHECK,
            :WHEN_MOVE,
            :WHEN_RETURN,
            :WHEN_LEAVE,
        ]
        callback.keys.each do |name|
            raise "unknown callback: #{name}" if ! known.include?(name)
        end

        if f = callback[:WHEN_VISIT]
            f.call(root)
        end
        stack = [[root, to_enum(:each_neighbour, root)]]
        parent = { root => root }
        f = nil
        until stack.empty?
            u, itr = stack[-1]
            begin
                v = itr.next
                f.call(u, v) if f = callback[:WHEN_CHECK]
                next if v == parent[u]|| parent[v]

                stack << [v, to_enum(:each_neighbour, v)]
                parent[v] = u
                f.call(u, v) if f = callback[:WHEN_MOVE]

                f.call(v) if f = callback[:WHEN_VISIT]
            rescue StopIteration
                stack.pop
                f.call(u) if f = callback[:WHEN_LEAVE]
                if ! stack.empty?
                    f.call(stack[-1][0], u) if f = callback[:WHEN_RETURN]
                end
            end
        end
    end

    def each_biconnected_component(root = each_node.to_a[0])
        return to_enum(__method__) unless block_given?

        visit_order = {}
        backtrack = {}
        parent = {}
        bc = Set.new

        callback = {
            :WHEN_VISIT => -> u {
                backtrack[u] = visit_order[u] = visit_order.size
            },
            :WHEN_CHECK => -> u, v {
                if v != parent[u] && o = visit_order[v]
                    backtrack[u] = o if o < backtrack[u]
                end
            },
            :WHEN_MOVE => -> u, v {
                parent[v] = u
            },
            :WHEN_RETURN => -> u, v {
                l = backtrack[v]
                if visit_order[u] <= l
                    bc << u
                    yield(bc)
                    bc = Set.new
                end
                backtrack[u] = l if l < backtrack[u]
            },
            :WHEN_LEAVE => -> u {
                bc << u
            },
        }

        dfs(root, callback)
    end

    def biconnected_components
        each_biconnected_component.to_a
    end

    def cut_points
        appearance = Hash.new(0)
        each_biconnected_component do |s|
            s.each do |u|
                appearance[u] += 1
            end
        end
        Set[*appearance.keys.select{|u| appearance[u] > 1}]
    end
end

class Hash
    include SimpleUndirectedGraphic
    alias each_node each_key
    def each_neighbour(u)
        self[u].each do |v|
            yield(v)
        end
    end
end

n, m = gets.split.map(&:to_i)
g = {}
(0..n-1).each {|u| g[u] = Set.new}
m.times do
    u, v = gets.split.map(&:to_i)
    g[u] << v
    g[v] << u
end

puts g.cut_points.sort

Measured memory_bytes: 215696