#include <bits/stdc++.h>
using namespace std;
ifstream fin("ciclueuler.in");
ofstream fout("ciclueuler.out");
typedef pair<int, int> pii;
const int inf = 1 << 30;
template<typename T>
class Graph {
public:
// constructori
Graph() : m_n(0), m_ad() {}
explicit Graph(int n) : m_n(n) {
m_ad.resize(m_n + 1);
}
Graph(int n, vector<vector<T>> &ad) :
m_n(n), m_ad(ad) {}
void addEdge(int v, int u) {
m_ad[v].push_back(u);
}
void addEdge(int v, int u, int cost) {
m_ad[v].push_back({u, cost});
}
// dfs
void DFS(int v, vector<bool> &vis) {
vis[v] = true;
for (auto &x : m_ad[v]) {
if (!vis[x]) {
DFS(x, vis);
}
}
}
int components() {
int compCount = 0;
vector<bool> vis(m_n, false);
for (int i = 1; i <= m_n; ++i) {
if (!vis[i]) {
++compCount;
DFS(i, vis);
}
}
return compCount;
}
// bfs
void minDist(int start, ostream &out) {
vector<int> dist(m_n + 1, -1);
queue<int> Q;
int x;
dist[start] = 0;
Q.push(start);
while (!Q.empty()) {
x = Q.front(); Q.pop();
for (auto &y : m_ad[x]) {
if (dist[y] == -1) {
dist[y] = dist[x] + 1;
Q.push(y);
}
}
}
for (int i = 1; i <= m_n; ++i) {
out << dist[i] << ' ';
}
}
// sortare topologica
void topologicalSort(int v, vector<bool> &vis, vector<int> &stack) {
vis[v] = true;
for (auto &x : m_ad[v]) {
if (!vis[x]) {
topologicalSort(x, vis, stack);
}
}
stack.push_back(v);
}
void printTopoSorted(ostream &out) {
vector<bool> vis(m_n + 1, false);
vector<int> stack;
for (int i = 1; i <= m_n; ++i) {
if (!vis[i]) {
topologicalSort(i, vis, stack);
}
}
for (auto i = stack.size() - 1; i >= 0; --i) {
out << stack[i] << ' ';
}
}
// ctc
vector<vector<int>> getReversedGraph() {
vector<vector<int>> tAd(m_n + 1);
for (int i = 1; i <= m_n; ++i) {
for (auto &w : m_ad[i]) {
tAd[w].push_back(i);
}
}
return tAd;
}
void tDFS(int v, vector<vector<int>> &tAd, vector<bool> &vis, int compCount, vector<vector<int>> &comp) {
vis[v] = true;
comp[compCount - 1].push_back(v);
for (auto &x : tAd[v]) {
if (!vis[x]) {
tDFS(x, tAd, vis, compCount, comp);
}
}
}
void stronglyConnectedComponents(ostream &out) {
vector<vector<int>> tAd = getReversedGraph();
vector<bool> vis1(m_n + 1, false);
vector<bool> vis2(m_n + 1, false);
vector<int> stack;
int compCount = 0;
vector<vector<int>> comp;
for (int i = 1; i <= m_n; ++i) {
if (!vis1[i]) {
topologicalSort(i, vis1, stack);
}
}
for (auto i = stack.size() - 1; i >= 0; --i) {
if (!vis2[stack[i]]) {
++compCount;
comp.emplace_back();
tDFS(stack[i], tAd, vis2, compCount, comp);
}
}
out << compCount << '\n';
for (int i = 0; i < compCount; ++i) {
for (auto &x : comp[i]) {
out << x << ' ';
}
out << '\n';
}
}
// biconex
void bccDFS(int v, int parent, vector<int> &disc, vector<int> &low,
vector<int> &stack, vector<vector<int>> &comp) {
static int time = 0;
int children = 0;
disc[v] = low[v] = ++time;
for (auto &w : m_ad[v]) {
if (w == parent) continue;
if (!disc[w]) {
++children;
stack.push_back(w);
bccDFS(w, v, disc, low, stack, comp);
low[v] = min(low[v], low[w]);
if (low[w] >= disc[v]) {
comp.emplace_back();
stack.push_back(v);
while (!stack.empty() && stack.back() != w) {
comp[comp.size() - 1].push_back(stack.back());
stack.pop_back();
}
if (!stack.empty()) {
comp[comp.size() - 1].push_back(stack.back());
stack.pop_back();
}
}
} else if (w != parent) {
low[v] = min(low[v], disc[w]);
}
}
}
void biconnectedComponents(ostream &out) {
vector<int> disc(m_n + 1, 0);
vector<int> low(m_n + 1, 0);
vector<int> stack;
vector<vector<int>> comp;
bccDFS(1, 0, disc, low, stack, comp);
out << comp.size() << '\n';
for (auto &c : comp) {
for (auto &v : c) {
out << v << ' ';
}
out << '\n';
}
}
// Havel Hakimi
static bool eligible(vector<int> &v) {
int s = 0;
auto n = v.size();
for (auto &x : v) {
if (x > n - 1) {
return false;
}
s += x;
}
return s % 2 == 0;
}
static string canBuildGraph(vector<int> &v) {
if (!eligible(v)) {
return "No";
}
sort(v.begin(), v.end(), greater<>());
while (v[0]) {
for (int i = 1; i <= v[0]; ++i) {
if (v[i] == 0) {
return "No";
}
--v[i];
}
v.erase(v.begin());
sort(v.begin(), v.end(), greater<>());
}
return "Yes";
}
// graf
void findPaths(vector<vector<int>> &paths, vector<int> &path, vector<vector<int>> &parent, int current) {
if (current == -1) {
paths.push_back(path);
return;
}
for (auto &p : parent[current]) {
path.push_back(current);
findPaths(paths, path, parent, p);
path.pop_back();
}
}
void BFS(vector<vector<int>> &parents, int start) {
vector<int> dist(m_n + 1, inf);
queue<int> Q;
Q.push(start);
parents[start] = {-1};
dist[start] = 0;
while (!Q.empty()) {
int current = Q.front(); Q.pop();
for (auto &x : m_ad[current]) {
if (dist[current] + 1 < dist[x]) {
dist[x] = dist[current] + 1;
Q.push(x);
parents[x].clear();
parents[x].push_back(current);
} else if (dist[x] == dist[current] + 1) {
parents[x].push_back(current);
}
}
}
}
void optimalPaths(int start, int end, ostream &out) {
vector<vector<int>> paths;
vector<int> path;
vector<vector<int>> parents(m_n + 1);
BFS(parents, start);
findPaths(paths, path, parents, end);
vector<int> check(m_n + 1, 0);
auto pathCount = paths.size();
int count = 0;
for (auto &p : paths) {
for (auto &v : p) {
++check[v];
}
}
for (int i = 1; i <= m_n; ++i) {
if (check[i] == pathCount) {
++count;
}
}
out << count << '\n';
for (int i = 1; i <= m_n; ++i) {
if (check[i] == pathCount) {
out << i << ' ';
}
}
}
// disjoint
int find(int x, vector<int> &root) {
int rx = x, aux;
while (rx != root[rx]) {
rx = root[rx];
}
while (x != root[x]) {
aux = root[x];
root[x] = rx;
x = aux;
}
return rx;
}
void unite(int x, int y, vector<int> &root, vector<int> &size) {
int rx = find(x, root);
int ry = find(y, root);
if (size[rx] > size[ry]) {
root[ry] = rx;
size[rx] += size[ry];
} else {
root[rx] = ry;
size[ry] += size[rx];
}
}
void disjoint(int n, vector<pair<int, pair<int, int>>> &ops, ostream &out) {
vector<int> root(n + 1);
vector<int> size(n + 1, 1);
for (int i = 1; i <= n; ++i) {
root[i] = i;
}
for (auto &op : ops) {
if (op.first == 1) {
unite(op.second.first, op.second.second, root, size);
} else {
if (find(op.second.first, root) == find(op.second.second, root)) {
out << "DA\n";
} else {
out << "NU\n";
}
}
}
}
// apm
static bool comp(pair<pair<int, int>, int> &X, pair<pair<int, int>, int> &Y) {
return X.second < Y.second;
}
void minimumSubtree(int n, vector<pair<pair<int, int>, int>> &edges, ostream &out) {
int totalCost = 0;
vector<int> root(n + 1);
vector<int> size(n + 1, 1);
vector<pair<int, int>> sol;
sort(edges.begin(), edges.end(), comp);
for (int i = 1; i <= n; ++i) {
root[i] = i;
}
for (auto &edge : edges) {
if (sol.size() == n - 1) {
break;
}
int x = find(edge.first.first, root);
int y = find(edge.first.second, root);
if (root[x] != root[y]) {
unite(x, y, root, size);
totalCost += edge.second;
sol.push_back(edge.first);
}
}
out << totalCost << '\n' << sol.size() << '\n';
for (auto &e : sol) {
out << e.first << ' ' << e.second << '\n';
}
}
// dijkstra
void dijkstra(vector<vector<int>> &cost, ostream &out) {
vector<int> dist(m_n + 1, inf);
vector<bool> vis(m_n + 1, false);
priority_queue<pii, vector<pii>, greater<pii>> heap;
dist[1] = 0;
heap.push({0, 1});
while (!heap.empty()) {
int current = heap.top().second;
heap.pop();
if (!vis[current]) {
vis[current] = true;
for (auto &w : m_ad[current]) {
if (dist[current] + cost[current][w] < dist[w]) {
dist[w] = dist[current] + cost[current][w];
heap.push({dist[w], w});
}
}
}
}
for (int i = 2; i <= m_n; ++i) {
if (dist[i] != inf) {
out << dist[i] << ' ';
} else {
out << "0 ";
}
}
}
// bellman-ford
void bellmanFord(vector<vector<int>> &cost, ostream &out) {
vector<int> dist(m_n + 1, inf);
vector<bool> inHeap(m_n + 1, false);
vector<int> count(m_n + 1, 0);
priority_queue<pii, vector<pii>, greater<pii>> heap;
bool foundCycle = false;
dist[1] = 0;
inHeap[1] = true;
heap.push({0, 1});
while (!heap.empty() && !foundCycle) {
int current = heap.top().second;
heap.pop();
inHeap[current] = false;
for (auto &w : m_ad[current]) {
if (dist[current] + cost[current][w] < dist[w]) {
if (!inHeap[w]) {
++count[w];
inHeap[w] = true;
heap.push({dist[w], w});
if (count[w] > m_n) {
foundCycle = true;
}
}
dist[w] = dist[current] + cost[current][w];
}
}
}
if (foundCycle) {
out << "Ciclu negativ!";
return;
}
for (int i = 2; i <= m_n; ++i) {
if (dist[i] != inf) {
out << dist[i] << ' ';
} else {
out << "0 ";
}
}
}
// maxflow
bool foundPath(vector<vector<int>> &c, vector<vector<int>> &flow, vector<int> &parent) {
queue<int> Q;
vector<bool> vis(m_n + 1, false);
parent[1] = -1;
Q.push(1);
while (!Q.empty()) {
int current = Q.front(); Q.pop();
vis[current] = true;
if (current == m_n) {
continue;
}
for (auto &w : m_ad[current]) {
if (!vis[w] && flow[current][w] < c[current][w]) {
parent[w] = current;
Q.push(w);
}
}
}
return vis[m_n];
}
int getMaxFlow(vector<vector<int>> &c) {
int maxFlow = 0;
vector<int> parent(m_n + 1);
vector<vector<int>> flow(m_n + 1);
for (int i = 1; i <= m_n; ++i) {
flow[i].resize(m_n + 1, 0);
}
while (foundPath(c, flow, parent)) {
for (auto &w : m_ad[m_n]) {
if (c[w][m_n] == flow[w][m_n] || !parent[w]) {
continue;
}
int minFlow = c[w][m_n] - flow[w][m_n];
for (int v = w; v != 1; v = parent[v]) {
minFlow = min(minFlow, c[parent[v]][v] - flow[parent[v]][v]);
}
if (minFlow == 0) {
continue;
}
flow[w][m_n] += minFlow;
flow[m_n][w] -= minFlow;
for (int v = w; v != 1; v = parent[v]) {
flow[parent[v]][v] += minFlow;
flow[v][parent[v]] -= minFlow;
}
maxFlow += minFlow;
}
}
return maxFlow;
}
// Roy-Floyd
void royFloyd(ostream &out) {
int i, j, k;
for (k = 1; k <= m_n; ++k) {
for (i = 1; i <= m_n; ++i) {
for (j = 1; j <= m_n; ++j) {
m_ad[i][j] = min(m_ad[i][j], m_ad[i][k] + m_ad[k][j]);
}
}
}
for (i = 1; i <= m_n; ++i) {
for (j = 1; j <= m_n; ++j) {
if (m_ad[i][j] != inf) {
out << m_ad[i][j] << ' ';
} else {
out << 0 << ' ';
}
}
out << '\n';
}
}
// darb
void treeDFS(int v, int d, int &dMax, int &vMax, vector<bool> &vis) {
if (d > dMax) {
dMax = d;
vMax = v;
}
vis[v] = true;
for (auto &w : m_ad[v]) {
if (!vis[w]) {
treeDFS(w, d + 1, dMax, vMax, vis);
}
}
}
int diameter() {
int dMax = 1, vMax;
vector<bool> vis(m_n + 1, false);
treeDFS(1, 1, dMax, vMax, vis);
vis.assign(m_n + 1, false);
dMax = 1;
treeDFS(vMax, 1, dMax, vMax, vis);
return dMax;
}
// ciclu eulerian
vector<int> eulerianCycle(int edgeCount) {
for (int i = 1; i <= m_n; ++i) {
if (m_ad[i].size() & 1) {
return {-1};
}
}
vector<int> ans;
vector<bool> vis(edgeCount + 1);
stack<int> s;
s.push(1);
while (!s.empty()) {
int current = s.top();
while (!m_ad[current].empty() && vis[m_ad[current].back().second]) {
m_ad[current].pop_back();
}
if (!m_ad[current].empty()) {
pii edge = m_ad[current].back();
vis[edge.second] = true;
s.push(edge.first);
} else {
ans.push_back(current);
s.pop();
}
}
return ans;
}
// ciclu hamiltonian
// cuplaj
private:
int m_n;
vector<vector<T>> m_ad;
};
int main() {
int n, m, x, y;
fin >> n >> m;
Graph<pii> G(n);
for (int i = 1; i <= m; ++i) {
fin >> x >> y;
G.addEdge(x, y, i);
G.addEdge(y, x, i);
}
auto ans = G.eulerianCycle(m);
ans.pop_back();
for (auto &v : ans) {
fout << v << ' ';
}
return 0;
}