/*
NOTE
*min_element(.begin(),.end())
*max_element(.begin(),.end())
priority_queue<> pq
 push()  pop() size()  top()
map<>
 find() begin() end() insert(map<>::value_type())
pair<>
sort(.begin(), .end())
sort(arr, arr+N)
sort(a, a+N, greater<int>())
binary_search(vc.begin(), vc.end(), x)  //binary_search???true, false?????????
vector<int>::iterator lit = lower_bound(vc.begin(), vc.end(), x);
  lower_bound?????????????????????"??\???"????????????????????????????????????????????¬???????????????
vector<int>::iterator uit = upper_bound(vc.begin(), vc.end(), x);
  upper_bound????????????????????????"?¶???????"?????????????????????????????????????????¬???????????????
*/
#include <iostream>
#include <cstdio>
#include <climits>
#include <cmath>
#include <cassert>
#include <algorithm>
#include <utility>
#include <vector>
#include <string>
#include <stack>
#include <queue>
#include <map>
#include <set>

#define MAX 100
#define INF 1<<20
#define LLINF 10e12 // 1<<31 // 2^31
#define REP(i,n) for(int i=0;i<n;i++)
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)
#define ALL(o) (o).begin(), (o).end()
#define ERASE(o) (o).erase(unique(ALL((o))), (o).end());

using namespace std;
typedef long long ll;
/////
typedef int Weight;
struct Edge
{
  int src, dst;
  Weight weight;
  Edge(int src, int dst, Weight weight) :
    src(src), dst(dst), weight(weight) { }
};
bool operator < (const Edge &e, const Edge &f)
{
  return e.weight != f.weight ? e.weight > f.weight : // !!INVERSE!! ???????????????????????????
    e.src != f.src ? e.src < f.src : e.dst < f.dst;
}
struct UndirectionalCompare
{
  bool operator() (const Edge& e, const Edge& f) const
  {
    if (min(e.src,e.dst) != min(f.src,f.dst))
      return min(e.src,e.dst) < min(f.src,f.dst);
    return max(e.src,e.dst) < max(f.src,f.dst);
  }
};
typedef set<Edge, UndirectionalCompare> Edgeset;
typedef vector<Edge> Edges;
typedef vector<Edges> Graph;
typedef vector<Weight> Array;
typedef vector<Array> Matrix;

/////
void visit(const Graph &g, int v, int u,
    vector<int>& art, vector<Edgeset>& bcomp,
    stack<Edge>& S, vector<int>& num, vector<int>& low, int& time)
{
  low[v] = num[v] = ++time;
  FOR(e, g[v])
  {
    int w = e->dst;
    if (num[w] < num[v]) S.push(*e);              // for bcomps
    if (num[w] == 0)
    {
      visit(g, w, v, art, bcomp, S, num, low, time);
      low[v] = min(low[v], low[w]);
      if ((num[v] == 1 && num[w] != 2) ||         // for arts
          (num[v] != 1 && low[w] >= num[v])) art.push_back(v);
      if (low[w] >= num[v])                       // for bcomps
      {
        bcomp.push_back(Edgeset());
        while (1) {
          Edge f = S.top(); S.pop();
          bcomp.back().insert(f);
          if (f.src == v && f.dst == w) break;
        }
      }
    } else low[v] = min(low[v], num[w]);
  }
}

void articulationPoint(const Graph& g,
    vector<int>& art, vector<Edgeset>& bcomp)
{
  const int n = g.size();
  vector<int> low(n), num(n);
  stack<Edge> S;
  REP(u, n) if (num[u] == 0)
  {
    int time = 0;
    visit(g, u, -1, art, bcomp, S, num, low, time);
  }
}
/////
int main()
{
  cin.tie(0);
  ios::sync_with_stdio(false);
  // FROM HERE
  int V, E, r; cin >> V >> E;
  Graph G(V);
  REP(i,E)
  {
    int s, t; cin >> s >> t;
    Edge a(s,t,1), b(t,s,1);
    G[s].push_back(a);
    G[t].push_back(b);
  }
  vector<int> art;
  vector<Edgeset> bcomp;
  articulationPoint(G,art,bcomp);
  sort(ALL(art));
  ERASE(art);
  FOR(a,art) cout << *a << endl;
  return 0;
}

Measured memory_bytes: 8132