// ??£??\???????????§??¨????????????????????°??????

#include<algorithm>
#include<functional>
#include<stack>
#include<queue>
#include<vector>

using Weight = int;
using Vertex = int;
struct Edge {Vertex from, to; Weight weight;};
using Graph = std::vector<std::vector<Edge>>;

// ?????????????????????????????°?????? O(|E|)
Graph reverse(const Graph& G) {
  Graph H(G.size());
  for(const auto& list: G) for(const auto& e: list) H[e.to].push_back({e.to, e.from, e.weight});
  return H;
}

// ????????£??????????????????????????????????????? O(|V|)
std::vector<Vertex> connected_component(const Graph& G, Vertex v) {
  static std::vector<bool> used(G.size());
  used[v] = true;
  std::vector<Vertex> S = {v};
  for(const auto& e: G[v]) if(!used[e.to]) {
    auto t = connected_component(G, e.to);
    S.insert(end(S), begin(t), end(t));
  }
  return S;
}

// ??????cur???????????£???????????????????????¢??????/???????????? O(|V| + |E|)
// ???cur???????????¨??????pre==cur?????????
// ???cut_vertex??????????????????????????°?????\???????????§?????????
void lowlink(const Graph& G, Vertex cur, Vertex pre, std::vector<int>& cut_vertex, std::vector<Edge>& bridge) {
  static std::vector<bool> used(G.size());
  static std::vector<int> ord(G.size()), low(G.size());
  static int timer = 1;
  ord[cur] = low[cur] = timer++;
  used[cur] = true;
  for(const auto& e: G[cur]) if(e.to != pre) {
    if(used[e.to]) {
      low[cur] = std::min(low[cur], ord[e.to]);
    } else {
      lowlink(G, e.to, cur, cut_vertex, bridge);
      low[cur] = std::min(low[cur], low[e.to]);
      if(cur == pre) if(ord[cur]+1 < ord[e.to]) cut_vertex.push_back(cur);
      if(cur != pre) if(ord[cur] <= low[e.to])  cut_vertex.push_back(cur);
      if(ord[cur] < low[e.to])                  bridge.push_back(e);
    }
  }
}

// ?????£?????????????§£ O(|V| + |E|)
void Tarjan(const Graph& G, Vertex v, std::vector<std::vector<Vertex>>& scc) {
  static std::stack<Vertex> S;
  static std::vector<bool> inS(G.size());
  static std::vector<int> ord(G.size()), low(G.size());
  static int timer = 1;
  ord[v] = low[v] = timer++;
  S.push(v);
  inS[v] = true;
  for(const auto& e: G[v]) {
    if(!ord[e.to]) {
      Tarjan(G, e.to, scc);
      low[v] = std::min(low[v], low[e.to]);
    } else if(inS[e.to]) {
      low[v] = std::min(ord[v], low[e.to]);
    }
  }
  if(ord[v] == low[v]) {
    scc.push_back(std::vector<int>());
    while(true) {
      Vertex w = S.top();
      S.pop();
      inS[w] = false;
      scc.back().push_back(w);
      if(v == w) break;
    }
  }
}
std::vector<std::vector<Vertex>> Tarjan(const Graph& G) {
  std::vector<std::vector<Vertex>> scc;
  for(int v = 0; v < G.size(); ++v) Tarjan(G, v, scc);
  return scc;
}

// ???????§???????????????? O(|E| + |V| log |V|)
std::vector<Weight> Dijkstra(const Graph& G, Vertex s) {
  std::vector<Weight> d(G.size(), -1);
  std::priority_queue<Edge, std::vector<Edge>, std::function<bool(Edge,Edge)>> q([](Edge lhs, Edge rhs){return lhs.weight > rhs.weight;});
  q.push({s, s, 0});
  while(!q.empty()) {
    auto cur = q.top();
    q.pop();
    if(d[cur.to] != -1) continue;
    d[cur.to] = cur.weight;
    for(const auto& nex: G[cur.to]) if(d[nex.to] != -1) q.push({cur.to, nex.to, cur.weight + nex.weight});
  }
  return d;
}

// ???????????? O(|E| + |V|^3)
std::vector<std::vector<Weight>> WarshallFloyd(const Graph& G) {
  std::vector<std::vector<Weight>> d(G.size(), std::vector<Weight>(G.size(), -1));
  for(int v = 0; v < G.size(); ++v) {
    d[v][v] = 0;
    for(const auto& e: G[v]) {
      if(d[e.from][e.to] == -1) d[e.from][e.to] = e.weight;
      else                      d[e.from][e.to] = std::min(d[e.from][e.to], e.weight);
    }
  }
  for(int i = 0; i < G.size(); ++i) for(int j = 0; j < G.size(); ++j) for(int k = 0; k < G.size(); ++k) {
    if(d[i][k] != -1 && d[k][j] != -1) {
      if(d[i][j] == -1) d[i][j] = d[i][k] + d[k][j];
      else              d[i][j] = std::min(d[i][j], d[i][k] + d[k][j]);
    }
  }
  return d;
}

#include<bits/stdc++.h>
using namespace std;

int main() {
  int V, E;
  cin >> V >> E;
  Graph G(V);
  for(int i = 0; i < E; ++i) {
    int s, t;
    cin >> s >> t;
    G[s].push_back({s, t, 0});
    G[t].push_back({t, s, 0});
  }

  vector<int> used;
  vector<int> rep;
  for(int v = 0; v < V; ++v) if(find(begin(used), end(used), v) == end(used)) {
    auto t = connected_component(G, v);
    rep.push_back(t.front());
    used.insert(begin(used), begin(t), end(t));
  }

  vector<int> cut_vertex;
  vector<Edge> bridge;
  for(auto v: rep) lowlink(G, v, v, cut_vertex, bridge);

  set<int> S(begin(cut_vertex), end(cut_vertex));
  for(auto v: S) cout << v << endl;
}

Measured memory_bytes: 5904