use std::collections::HashSet;

#[derive(Debug, Clone)]
struct Graph {
    edges: Vec<Vec<usize>>,
    low: Vec<usize>,
    ord: Vec<usize>,
    used: Vec<bool>,
    bridge: HashSet<(usize, usize)>,
    articulation: HashSet<usize>,
    size: usize,
}

impl Graph {
    fn new(edges: Vec<Vec<usize>>) -> Self {
        let size = edges.len();
        let low = vec![size + 1; size];
        let ord = vec![size + 1; size];
        let used = vec![false; size];
        let bridge = HashSet::new();
        let articulation = HashSet::new();
        Self {
            edges,
            low,
            ord,
            used,
            bridge,
            articulation,
            size,
        }
    }
    fn dfs(&mut self, idx: usize, order: usize, parent: usize) -> usize {
        self.used[idx] = true;
        self.ord[idx] = order;
        self.low[idx] = self.ord[idx];
        let mut is_articulation = false;
        let mut order = order;
        let mut cnt = 0;
        let nodes = self.edges[idx].clone();
        for to in nodes {
            if !self.used[to] {
                cnt += 1;
                order = self.dfs(to, order+1, idx);
                self.low[idx] = min(self.low[idx],self.low[to]);
                is_articulation |= (parent != self.size + 1) & (self.ord[idx] <= self.low[to]);
                if self.ord[idx] < self.low[to] {
                    self.bridge.insert((min(idx,to), max(idx,to)));
                }
            } else if to != parent {
                self.low[idx] = min(self.low[idx],self.ord[to]);
            }
        }
        is_articulation |= (parent == self.size + 1) & (cnt > 1);
        if is_articulation {
            self.articulation.insert(idx);
        }
        return order;
    }
}

#[inline]
fn min(i:usize,j:usize)->usize{
    if i < j {
        i
    }else{
        j
    }
}

#[inline]
fn max(i:usize, j:usize)->usize{
    if i < j {
        j
    }else{
        i
    }
}
    
fn solve(graph: Vec<Vec<usize>>) {
    let size = graph.len();
    let mut graph = Graph::new(graph);
    let mut order = 0;
    for i in 0..size {
        if !graph.used[i] {
            order = graph.dfs(order, i, size + 1);
        }
    }
    let mut a:Vec<_> = graph.articulation.into_iter().collect();
    a.sort();
    for i in a{
        println!("{}",i);
    }
}

use std::io::{BufRead, BufReader};
fn main() {
    let mut read = BufReader::new(std::io::stdin())
        .lines()
        .filter_map(|e| e.ok());
    let (v, _e) = {
        let line = read.next().unwrap();
        let line: Vec<&str> = line.split(' ').collect();
        let v: usize = line[0].parse().unwrap();
        let e: usize = line[1].parse().unwrap();
        (v, e)
    };
    let graph = {
        let mut graph: Vec<Vec<_>> = vec![vec![]; v]; // Adj list
        for edge in read {
            if edge.is_empty() {
                break;
            }
            let mut edge = edge.split(' ');
            let start: usize = edge.next().unwrap().parse().unwrap();
            let end: usize = edge.next().unwrap().parse().unwrap();
            graph[start].push(end);
            graph[end].push(start);
        }
        graph
    };
    solve(graph);
}



Measured memory_bytes: 9292