use std::io::*;
use std::str::FromStr;

#[allow(dead_code)]
fn read<T: FromStr>() -> T {
    let stdin = stdin();
    let stdin = stdin.lock();
    let token: String = stdin
        .bytes()
        .map(|c| c.expect("failed to read char") as char)
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect();
    token.parse().ok().expect("failed to parse token")
}

#[allow(dead_code)]
struct XorShift {
    x: u32,
    y: u32,
    z: u32,
    w: u32,
}
#[allow(dead_code)]
impl XorShift {
    fn new() -> XorShift {
        XorShift {
            x: 0x34fb2383,
            y: 0x327328fa,
            z: 0xabd4b54a,
            w: 0xa9dba8d1,
        }
    }
    fn seed(s: u32) -> XorShift {
        let mut rnd = XorShift::new();
        rnd.w = s;
        rnd
    }
    fn xor128(&mut self) -> u32 {
        let t = self.x ^ (self.x << 11);
        self.x = self.y;
        self.y = self.z;
        self.z = self.w;
        self.w = (self.w ^ (self.w >> 19)) ^ (t ^ (t >> 8));
        self.w
    }
    fn next_i32(&mut self, r: i32) -> i32 {
        (self.xor128() % r as u32) as i32
    }
    fn next_i32_lr(&mut self, l: i32, r: i32) -> i32 {
        self.next_i32(r - l + 1) + l
    }
    fn next_i64(&mut self, r: i64) -> i64 {
        ((((self.xor128() as u64) << 32) + self.xor128() as u64) % r as u64) as i64
    }
    fn next_i64_lr(&mut self, l: i64, r: i64) -> i64 {
        self.next_i64(r - l + 1) + l
    }
    fn next_f64(&mut self, r: f64) -> f64 {
        (self.xor128() as f64) / (0xffffffffu32 as f64) * r
    }
    fn next_f64_lr(&mut self, l: f64, r: f64) -> f64 {
        self.next_f64(r - l) + l
    }
}

type Weight = i32;
#[allow(dead_code)]
#[derive(Clone, Debug, Eq, PartialEq)]
struct Edge {
    index: usize,
    src: usize,
    dest: usize,
    weight: Weight,
}
#[allow(dead_code)]
impl Edge {
    fn new(index: usize, src: usize, dest: usize, weight: Weight) -> Edge {
        Edge {
            index: index,
            src: src,
            dest: dest,
            weight: weight,
        }
    }
}
impl std::cmp::Ord for Edge {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        (self.weight, self.src, self.dest).cmp(&(other.weight, other.src, other.dest))
    }
}
impl std::cmp::PartialOrd for Edge {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}
type Edges = Vec<Edge>;
type Graph = Vec<Edges>;
#[allow(dead_code)]
fn graph_new(n: usize) -> Graph {
    vec![vec![]; n]
}
#[allow(dead_code)]
fn add_bi_edge(graph: &mut Graph, index: &mut usize, src: usize, dest: usize, weight: Weight) {
    graph[src].push(Edge::new(*index, src, dest, weight));
    graph[dest].push(Edge::new(*index, dest, src, weight));
    *index += 1;
}
#[allow(dead_code)]
fn add_uni_edge(graph: &mut Graph, index: &mut usize, src: usize, dest: usize, weight: Weight) {
    graph[src].push(Edge::new(*index, src, dest, weight));
    *index += 1;
}

// return (find_loop, last_node, is_loop)
fn dfs(
    g: &Graph,
    from: usize,
    parent: usize,
    visit: &mut Vec<bool>,
    bans: &mut Vec<bool>,
) -> (bool, usize, bool) {
    if visit[from] {
        return (true, from, true);
    }
    visit[from] = true;
    for e in g[from].iter() {
        if bans[e.index] || e.dest == parent {
            continue;
        }
        let nret = dfs(g, e.dest, from, visit, bans);
        if nret.0 {
            if nret.2 {
                bans[e.index] = true;
            }
            return (true, nret.1, nret.2 && from != nret.1);
        }
    }
    return (false, 0, false);
}

fn main() {
    let n = read::<usize>();
    let m = read::<usize>();
    let mut g = graph_new(n);
    let mut index = 0;
    for _i in 0..m {
        let f = read::<usize>() - 1;
        let t = read::<usize>() - 1;
        add_bi_edge(&mut g, &mut index, f, t, 0);
    }
    for i in 0..n {
        if g[i].len() % 2 != 0 {
            println!("No");
            return;
        }
    }
    let mut rnd = XorShift::new();
    'random_loop: for _r in 0..20 {
        let mut bans = vec![false; m];
        for _iter in 0..3 {
            let mut ok = false;
            let mut visit = vec![false; n];
            for i in 0..n {
                if dfs(&g, i, i, &mut visit, &mut bans).0 {
                    // println!("{:?}", bans);
                    ok = true;
                    break;
                }
            }
            if !ok {
                for i in 0..n {
                    for j in 0..g[i].len() {
                        g[i].swap(j, rnd.next_i32(j as i32 + 1) as usize);
                    }
                }
                continue 'random_loop;
            }
        }
        println!("Yes");
        return;
    }
    println!("No");
}


Measured memory_bytes: 28156