#include <bits/stdc++.h>

using namespace std;

#define cin_desync()                                                           \
    do {                                                                       \
        ios_base::sync_with_stdio(false);                                      \
        cin.tie(0);                                                            \
    } while (0)

#ifndef ONLINE_JUDGE
#define trace(...) __f(#__VA_ARGS__, __VA_ARGS__)
template <typename Arg1> void __f(const char *name, Arg1 &&arg1) {
    cerr << name << " : " << arg1 << std::endl;
}
template <typename Arg1, typename... Args>
void __f(const char *names, Arg1 &&arg1, Args &&... args) {
    const char *comma = strchr(names + 1, ',');
    cerr.write(names, comma - names) << " : " << arg1 << " | ";
    __f(comma + 1, args...);
}

#else
#define trace(...)
#endif // ifndef ONLINE_JUDGE

typedef long double ld;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;

// Eulerian path/circuit in an undirected graph. TODO: Does this handle self-edges?
// NOTE(Brian): This looks like it could theoretically degrade to quadratic time in, say, a graph where we keep going back and forth between two vertices; in this case a lot of time could be wasted searching for an unused edge.
struct EulerianPath {
	int n;
	vector<vector<int> > adj;
	vector<pair<int, int> > edges;
	vector<int> valid;
	vector<int> circuit;

	EulerianPath(int n): n(n), adj(n) {}

	// Call this to construct the graph.
	// Edges are zero-based and undirected (only add each edge once!)
	void add_edge(int x, int y) {
        --x; --y;
		adj[x].push_back(edges.size());
		adj[y].push_back(edges.size());
		edges.push_back(make_pair(x, y));
		valid.push_back(1);
	}
	
	void find_path(int x){
	  for(int i = 0; i < adj[x].size(); i++){
		int e = adj[x][i];
		if(!valid[e]) continue;
		int v = edges[e].first;
		if(v == x) v = edges[e].second;
		valid[e] = 0;
		find_path(v);
	  }
	  circuit.push_back(x);
	}

	// Call this to find the path/circuit (autodetects)
	// Returns the path/circuit itself in "circuit" variable
	// Initial node is repeated at end if it's a circuit.
	void find_euler_path() {
	  circuit.clear();
	  //supposes graph is connected and has correct degree
	  for(int i = 0; i < n; i++)
		if(adj[i].size()%2){
		  find_path(i);
		  return;
		}
	  find_path(0);
	}
};

const int max_N = 1e5 + 10;
int seen[max_N];

int main() {
    int N, M;
    cin >> N >> M;

    EulerianPath G(N);
    for (int i = 1; i <= M; ++i) {
        int x, y;
        cin >> x >> y;
        G.add_edge(x, y);
    }

    for (int i = 0; i < N; ++i) {
        if (G.adj[i].size() % 2) {
            cout << "No" << endl;
            return 0;
        }
    }

    vector<int> C1, C2;
    G.find_euler_path();
    C1 = G.circuit;

    memset(seen, -1, sizeof(seen));
    bool ok = false;
    vector<pii> intervals;
    for (int i = 0; i < C1.size(); ++i) {
        int v = C1[i];
        if (seen[v] != -1 && (i - seen[v] + 1) != C1.size()) {
            intervals.push_back({seen[v], i});
        }
        seen[v] = i;
    }

    sort(intervals.begin(), intervals.end());

    int mx = -1;
    int mn = C1.size() + 500;
    for (auto &I : intervals) {
        if (mx >= I.second) {
            ok = true;
            break;
        } else {
            mx = I.second;
        }

        if (mn <= I.first) {
            ok = true;
            break;
        } else {
            mn = min(mn, I.second);
        }
    }

    if (ok) {
        cout << "Yes" << endl;
    } else {
        cout << "No" << endl;
    }
}


Measured memory_bytes: 9716