#include <bits/stdc++.h>

using namespace std;

using i64 = int64_t;

const i64 MOD = 1e9 + 7;


struct LowLink{
    vector<vector<int>>& edges;
    // 関節点
    vector<int> art;
    vector<pair<int,int>> bridge;

    vector<int> used, ord, low;
    int k;

    void dfs(int idx, int par){
        ord[idx] = k++;
        low[idx] = ord[idx];
        bool is_art = false;
        int cnt = 0;
        for(auto& to : edges[idx]){
            if(ord[to] == -1){
                ++cnt;
                dfs(to, idx);
                low[idx] = min(low[idx], low[to]);
                is_art |= par != -1 && low[to] >= ord[idx];
                if(ord[idx] < low[to])
                    bridge.emplace_back(idx, to);
            }else if(to != par)
                low[idx] = min(low[idx], ord[to]);
        }
        is_art |= (par == -1 && cnt > 1);
        if(is_art)
            art.emplace_back(idx);
    }

    LowLink(vector<vector<int>>& edges) :
        edges(edges),
        ord(edges.size(), -1),
        low(edges.size(), 0),
        k(0)
    {
        for(int i = 0; i < edges.size(); ++i)
            if(ord[i] == -1)
                dfs(i, -1);
        for(auto& b : bridge)
            b = make_pair(min(b.first, b.second), max(b.first, b.second));
        sort(art.begin(), art.end());
        sort(bridge.begin(), bridge.end());
    }
};


signed main(){
    int n, m;
    cin >> n >> m;
    vector<pair<int,int>> v(m);
    vector<vector<int>> edges(n);
    for(int i = 0; i < m; ++i){
        vector<int> l(2);
        for(auto& x : l)
            cin >> x;
        sort(l.begin(), l.end());
        v[i] = make_pair(l.front(), l.back());
        edges[l[0]].emplace_back(l[1]);
        edges[l[1]].emplace_back(l[0]);
    }
    LowLink ll(edges);
    for(auto& x : ll.art)
        cout << x << endl;
}


#include <iostream>
#include <vector>
#include <set>

using namespace std;

struct ArticularPoint {
    int n;
    vector<vector<int>> g;
    set<int> points;
    vector<int> parent;
    vector<int> discTime;
    vector<int> lowTime;
    vector<bool> visited;
    vector<bool> isAp;
    int time = 0;
    
    ArticularPoint(int n): n(n) {
        g.assign(n, vector<int>());
        parent.assign(n, -1);
        discTime.assign(n, 0);
        lowTime.assign(n, n + 1);
        visited.assign(n, false);
        isAp.assign(n, false);
    }
    
    void addEdge(int from, int to) {
        g[from].push_back(to);
        g[to].push_back(from);
    }
    
    int solve() {
        dfs(0, -1);
        return points.size();
    } 
    
    void dfs(int u, int p) {
        discTime[u] = time++;
        lowTime[u] = discTime[u];
        visited[u] = true;
        int child = 0;
        for (int v : g[u]) {
            if (!visited[v]) {
                child++;
                parent[v] = u;
                dfs(v, u);
                lowTime[u] = min(lowTime[u], lowTime[v]);
                if (lowTime[v] >= discTime[u]) {
                    isAp[u] = true;;
                }
            }
            else if (v != p) {
                lowTime[u] = min(lowTime[u], discTime[v]);
            }
        }
        //Remove root is it has only one child
        if (p < 0 && child == 1) {
           isAp[u] = false;
        }
    }   
};

int main() {
    int n, m;
    cin >> n >> m;
    ArticularPoint ap(n);
    
    for (int i = 0; i < m; i++) {
        int from, to;
        cin >> from >> to;
        ap.addEdge(from, to);
    }
    
    int ans = ap.solve();
    for (int i = 0; i < n; i++) {
        if (ap.isAp[i]) {
            cout << i << endl;
        }
    }
    
    return 0;
}