//#define _GLIBCXX_DEBUG
#include <iostream>
#include <vector>
#include <stdio.h>
#include <bits/stdc++.h>


using namespace std;
#define ll long long
#define ld long double
#define  P pair<ll,ll>
#define FOR(i,n,m) for(ll i=n; i<(ll)m;i++)
#define FORa(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)
#define FORr(i,m,n) for(ll i=n; i>=(ll)m; i--)
#define FORm(i,m) for(auto i=m.begin();i!=m.end();i++)
#define REP(i,n) for(int i=0;i<(int)n;++i)
#define ALL(c) (c).begin(), (c).end()
#define VEC2(x,a,b) vector<vector<ll>> x = vector<vector<ll>>(a,vector<ll>(b,0))
#define sortAl(v) sort(v.begin(),v.end())
#define sortAlr(v) sort(v.begin(),v.end()); reverse(v.begin(),v.end())
#define cinv(v,n,m) FOR(i,n,m) cin>>v.at(i)
#define coutv(v,n,m) FOR(i,n,m) cout<<v.at(i) <<" "; cout<<endl
#define cout(n) cout<<fixed<<setprecision(n)

//計算量 V+E

//    Edges := 重み付き辺の集合
//    WeightedGraph := 重み付きグラフ
//    UnWeightedGraph := 重み無しグラフ
//    Matrix := 距離行列
template< typename T >
struct edge {
  ll src, to;
  T cost;

  edge(ll to, T cost) : src(-1), to(to), cost(cost) {}

  edge(ll src, ll to, T cost) : src(src), to(to), cost(cost) {}

  edge &operator=(const int &x) {
    to = x;
    return *this;
  }

  operator ll() const { return to; }
};

template< typename T >
using Edges = vector< edge< T > >;
template< typename T >
using WeightedGraph = vector< Edges< T > >;
using UnWeightedGraph = vector< vector< ll > >;
template< typename T >
using Matrix = vector< vector< T > >;


struct UnionFind
{
  vector< int > data;

  UnionFind(int sz)
  {
    data.assign(sz, -1);
  }

  bool unite(int x, int y)
  {
    x = find(x), y = find(y);
    if(x == y) return(false);
    if(data[x] > data[y]) swap(x, y);
    data[x] += data[y];
    data[y] = x;
    return(true);
  }

  int find(int k)
  {
    if(data[k] < 0) return(k);
    return(data[k] = find(data[k]));
  }

  int size(int k)
  {
    return(-data[find(k)]);
  }
};

template< typename G >
struct LowLink
{
  const G &g;
  UnionFind uf;
  vector< int > used, ord, low, parent;

  LowLink(const G &g) : g(g), uf(g.size()), used(g.size()), ord(g.size()), low(g.size()), parent(g.size(), -1) {}

  void dfs(int idx, int &k, int par = -1)
  {
    used[idx] = true;
    ord[idx] = k++;
    low[idx] = ord[idx];

    for(auto &to : g[idx]) {
      if(!used[to]) {
        dfs(to, k, idx);
        low[idx] = min(low[idx], low[to]);
        parent[to] = idx;
        if(ord[idx] >= low[to]) uf.unite(idx, to);
      } else if(to != par) {
        low[idx] = min(low[idx], ord[to]);
      }
    }
  }

  void dfs()
  {
    int k = 0;
    dfs(0, k);
  }
};


template< typename G >
struct ArticulationPoints : LowLink< G >
{
  using LL = LowLink< G >;

  ArticulationPoints(const G &g) : LL(g) {}

  vector< int > build()
  {
    LL::dfs();
    vector< int > vs;
    int sum = 0;
    for(int i = LL::g.size() - 1; i >= 1; i--) {
      if(LL::parent[i] == 0) ++sum;
      else if(LL::ord[LL::parent[i]] <= LL::low[i]) {
        vs.emplace_back(LL::parent[i]);
      }
    }
    if(sum > 1) vs.push_back(0);
    sort(begin(vs), end(vs));
    vs.erase(unique(begin(vs), end(vs)), end(vs));
    return (vs);
  }
};


int main(){
    cin.tie(0);
    ios::sync_with_stdio(false);
    ll v,e;
    cin>>v>>e;
    UnWeightedGraph g(v);
    FOR(i,0,e){
      ll in1,in2;
      cin>>in1>>in2;
      g[in1].push_back(in2);
      g[in2].push_back(in1);
    }
    ArticulationPoints<UnWeightedGraph> res = {g};
    vector<int> ans = res.build();
    FOR(i,0,ans.size()){
      cout<<ans[i]<<endl;
    }

}



Measured memory_bytes: 5660