#include "bits/stdc++.h"
#include<unordered_map>
#include<unordered_set>
#pragma warning(disable:4996)
using namespace std;
using ld = long double;
template<class T>
using Table = vector<vector<T>>;
const ld eps=1e-9;

//// < "D:\D_Download\Visual Studio 2015\Projects\programing_contest_c++\Debug\a.txt" > "D:\D_Download\Visual Studio 2015\Projects\programing_contest_c++\Debug\b.txt"
 
struct Edge {
	int src;
	int dst;
	int id;
};
//
//// res: bridges
//// v: current node
//// from_id: parent edge
//int bri_dfs(vector<vector<Edge>>&g, vector<int>& res, int now_node, int& count, int from_id, vector<int>& low, vector<int>& pre) {
//	pre[v] = count++;
//	low[now_node] = pre[now_node];
//	for (auto it = g[now_node].begin(); it != g[now_node].end(); it++) {
//		int to = it->dst;
//		if (pre[to] == -1) {
//			// destination has not been visited
//			// visit destination and update low[now_node]
//			low[now_node] = min(low[now_node], bri_dfs(g, res, to, count, it->id, low, pre));
//			if (low[to] == pre[to]) {
//				// edge is not contained in a closed path -> bridge
//				//res.push_back(it->id);
//				res[it->id] = true;
//			}
//		}
//		else {
//			if (from_id == it->id) {
//				// ignore a path to parent
//				continue;
//			}
//			low[now_node] = min(low[now_node], low[to]);
//		}
//	}
//	return low[now_node];
//}
//
//// Calculate bridges in a undirected graph.
//// Assume graph is connected and has no parallel edges or self-loops.
//// g: adjacency list
//// V: number of nodes
//void  bridges(vector<vector<Edge>>&g, int V, vector<int>&res) {
//	
//	if (V > 0) {
//		// assume at least the first vertex exists
//		vector<int> low(V, -1);  // lowest reacheable index
//		vector<int> pre(V, -1);  // pre-order index
//		int count = 0;  // pre-order index counter
//		bri_dfs(g, res, 0, count, -1, low, pre);  // start dfs from vertex 0
//	}
//}


// res: nodes
// now_node: current node
// from_node: parent node
int ari_dfs(vector<vector<Edge>>&g, vector<int>& res, int now_node, int& count, int from_node, vector<int>& low, vector<int>& pre) {
	pre[now_node] = count++;
	low[now_node] = pre[now_node];
	int c_num = 0;
	for (auto it = g[now_node].begin(); it != g[now_node].end(); it++) {
		int to = it->dst;
		if (pre[to] == -1) {
			c_num++;
			// destination has not been visited
			// visit destination and update low[now_node]
			int child_low = ari_dfs(g, res, to, count, now_node, low, pre);
			if (pre[now_node] <= child_low&&now_node!=-1)res[now_node] = true;
			low[now_node] = min(low[now_node],child_low);
			
		}
		else {
			if (from_node == it->dst) {
				// ignore a path to parent
				continue;
			}
			low[now_node] = min(low[now_node], pre[to]);
		}
	}
	if (from_node == -1) {
		res[now_node] = c_num >= 2;
	}
	return low[now_node];
}

// Calculate bridges in a undirected graph.
// Assume graph is connected and has no parallel edges or self-loops.
// g: adjacency list
// V: number of nodes
void  aritics(vector<vector<Edge>>&g, int V, vector<int>&res) {

	if (V > 0) {
		// assume at least the first vertex exists
		vector<int> low(V, -1);  // lowest reacheable index
		vector<int> pre(V, -1);  // pre-order index
		int count = 0;  // pre-order index counter
		ari_dfs(g, res, 0, count, -1, low, pre);  // start dfs from vertex 0

		int a = 0; a++;
		a--;
	}
	
}

int main() {
	int V, E; cin >> V >> E;
	vector<vector<Edge>>es(V);
	for (int i = 0; i < E; ++i) {
		int s, t; cin >> s >> t;
		if (s > t)swap(s, t);
		es[s].push_back(Edge{ s,t,i });
		es[t].push_back(Edge{ t,s,i });
	}
	vector<int>res(V);
	aritics(es, V, res);
	vector<int>bris;
	for (int i = 0; i <V; ++i) {
		if (res[i])bris.push_back(i);
	}
	
	for (int i = 0; i < bris.size(); ++i) {
		cout << bris[i] << endl;
	}
	return 0;
}

Measured memory_bytes: 6436