using System;
using System.Collections.Generic;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] a = Console.ReadLine().Split(' ');
            int m = Convert.ToInt32(a[0]);
            int n = Convert.ToInt32(a[1]);

            Dictionary<int, List<int>> network = new Dictionary<int, List<int>>();
            Dictionary<int, HashSet<int>> network2 = new Dictionary<int, HashSet<int>>();

            for (int i = 0; i < n; i++)
            {
                string[] data = Console.ReadLine().Split(' ');
                int a1 = Convert.ToInt32(data[0]);
                int b = Convert.ToInt32(data[1]);

                if (!network.ContainsKey(a1))
                {
                    network[a1] = new List<int>();
                    network2[a1] = new HashSet<int>();
                }

                if (!network.ContainsKey(b))
                {
                    network[b] = new List<int>();
                    network2[b] = new HashSet<int>();
                }

                network[a1].Add(b);
                network[b].Add(a1);

                network2[a1].Add(b);
                network2[b].Add(a1);
            }

            bool answered = false;
            foreach (var key in network.Keys)
            {
                for (int i = 0; i < network[key].Count; i++)
                {
                    var list1 = network[key];
                    var key2 = network[key][i];
                    var list2 = network[key2];

                    if (list1.Count != list2.Count)
                    {
                        answered = true;
                        Console.WriteLine("NO");
                        return;
                    }
                    else
                    {
                        foreach (var friend in network2[key])
                        {
                            if (!network2[key2].Contains(friend) && friend != key && friend != key2)
                            {
                                answered = true;
                                Console.WriteLine("NO");
                                return;
                            }
                        }
                    }
                }
            }

            if (!answered)
            {
                Console.WriteLine("YES");
            }
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;

namespace mo
{

    class Program
    {

        static long[] cost;
        static List<long>[] graph = new List<long>[150001];
        static long[] visited = new long[150001];

        public static List<long> Bfs(int from)
        {

            List<long> ls = new List<long>();

            Queue<long> queue = new Queue<long>();

            queue.Enqueue(from);
            visited[from] =1;

            ls.Add(from);

            while (queue.Count() > 0)
            {
                long front = queue.Peek();

                List<long> values = graph[front];

                if (values != null)
                {

                    foreach (var item in values)
                    {
                        if (visited[item] == 0)
                        {
                            visited[item] = 1;
                            ls.Add(item);
                            queue.Enqueue(item);
                        }
                    }
                }

                queue.Dequeue();

            }

            return ls;
        }

        private static bool IsPrime(int num)
        {
            if (num <= 1)
            {
                return false;
            }

            double num_sqrt = Math.Sqrt(num);
            int num_fl = Convert.ToInt32(Math.Floor(num_sqrt));

            for (int i = 2; i <= num_fl; i++)
            {
                if (num % i == 0)
                {
                    return false;
                }
            }
            return true;
        }

        static Int64 gcd(Int64 a, Int64 b)
        {
            if (b == 0) return a;
            return gcd(b, a % b);
        }

        static Int64 lcm(Int64 a, Int64 b)
        {
            return (a * b) / gcd(a, b);
        }

        static void Main(string[] args)
        {

            var input = GetIntegerInputsFromLine();

            int a = input[0];
            int b = input[1];

            for (int i = 1; i <= b; i++)
            {
                var gri = GetIntegerInputsFromLine();

                if (graph[gri[0]] == null)
                {
                    graph[gri[0]] = new List<long>();
                }

                graph[gri[0]].Add(gri[1]);

                if (graph[gri[1]] == null)
                {
                    graph[gri[1]] = new List<long>();
                }

                graph[gri[1]].Add(gri[0]);
            }

            bool res = true;

            for (int i = 1; i <= 150000; i++)
            {
                if(graph[i]!=null)
                {
                    if(visited[i]!=1)
                    {
                        var re = Bfs(i);

                        var checkd = checkedre(re);

                        if(checkd==false)
                        {
                            res = false;
                            break;
                        }
                    }
                }
            }

            if(res)
            {
                Console.WriteLine("YES");
            }
            else
            {
                Console.WriteLine("NO");
            }

        }

        private static bool checkedre(List<long> re)
        {
            var count = re.Count;

            bool res = true;

            for(int i=0;i<count;i++)
            {

                List<long> te = graph[re[i]];

                List<long> te2 = re.Where(x => x != re[i]).ToList();

                res = DoIdsMatchThoseFromXml(te,te2);

                if(res==false)
                {
                    return false;
                }
            }
            return res;
        }

        private static bool DoIdsMatchThoseFromXml(List<long> ids, List<long> xmlIds)
        {
            return ids.Count == xmlIds.Count // assumes unique values in each list
                && new HashSet<long>(ids).SetEquals(xmlIds);
        }

        public static IDictionary<TKey, List<TValue>> AddOrUpdate<TKey, TValue>(IDictionary<TKey, List<TValue>> dictionary, TKey key, TValue value)
        {
            List<TValue> values;

            if (dictionary.TryGetValue(key, out values))
            {
                values.Add(value);

                dictionary[key] = values;
            }
            else
            {
                values = new List<TValue>();
                values.Add(value);
                dictionary[key] = values;
            }

            return dictionary;
        }

        static int GetIntegerInputFromLine()
        {
            var input = Convert.ToInt32(Console.ReadLine().Trim());
            return input;
        }

        static List<int> GetIntegerInputsFromLine()
        {
            var inputs = Console.ReadLine().Split(' ').Select(x => Convert.ToInt32(x.Trim())).ToList();
            return inputs;
        }

        static long GetLongInputFromLine()
        {
            var input = Convert.ToInt64(Console.ReadLine().Trim());
            return input;
        }

        static List<Int64> GetLongInputsFromLine()
        {
            var inputs = Console.ReadLine().Split(' ').Select(x => Convert.ToInt64(x.Trim())).ToList();
            return inputs;
        }

        static double GetDoubleInputFromLine()
        {
            var input = Convert.ToDouble(Console.ReadLine().Trim());
            return input;
        }

        static double[] GetDoubleInputsFromLine()
        {
            var inputs = Console.ReadLine().Split(' ').Select(x => Convert.ToDouble(x.Trim())).ToArray();
            return inputs;
        }

        static string GetStringInputFromLine()
        {
            var input = Console.ReadLine();
            return input;
        }

        static string[] GetStringInputsFromLine()
        {
            var inputs = Console.ReadLine().Split(' ');
            return inputs;
        }
    }

    public class helper
    {
        public Int64 a;
        public Int64 b;
    }
}


using System;
using System.Linq;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;

namespace ConsoleApplication3
{
    class Program
    {
        static private Tokenizer input;
        static bool[] use;
        static List<int>[] g;
        static long r;
        static long c;
        static void Main(string[] args)
        {
            input = new Tokenizer(Console.In);
            int n = input.NextInt();
            int m = input.NextInt();
            g = new List<int>[n];
            for (int i = 0; i < m; i++)
            {
                int a = input.NextInt() - 1;
                int b = input.NextInt() - 1;
                if (g[a] == null) g[a] = new List<int>();
                if (g[b] == null) g[b] = new List<int>();
                g[a].Add(b);
                g[b].Add(a);
            }
            use = new bool[n];
            for (int i = 0; i < n; i++) {
                if (!use[i]) {
                    r = 0;
                    c = 0;
                    pass(i);
                    if((r/2)!=sum(c-1)) {
                        Console.WriteLine("NO");
                        return;
                    }
                }
            }
            Console.WriteLine("YES");
        }
        static void pass(int v)
        {
            c++;
            use[v] = true;
            if (g[v] != null) {
                for (int i = 0; i < g[v].Count; i++)
                {
                    r++;
                    if (!use[g[v][i]])
                    {
                        pass(g[v][i]);
                    }
                }
            }
        }
        static long sum(long k)
        {
            //((2a₁+d(n-1))/2)·n
            return (1 + k) * k / 2;
        }
    }
    public class Tokenizer
    {
        private TextReader reader;

        public int NextInt()
        {
            var c = SkipWS();
            if (c == -1)
                throw new EndOfStreamException();
            bool isNegative = false;
            if (c == '-' || c == '+')
            {
                isNegative = c == '-';
                c = this.reader.Read();
                if (c == -1)
                    throw new InvalidOperationException();
            }
            if (!char.IsDigit((char)c))
                throw new InvalidOperationException();
            int result = (char)c - '0';
            c = this.reader.Read();
            while (c > 0 && !char.IsWhiteSpace((char)c))
            {
                if (!char.IsDigit((char)c))
                    throw new InvalidOperationException();
                result = result * 10 + (char)c - '0';
                c = this.reader.Read();
            }
            if (isNegative)
                result = -result;
            return result;
        }

        public string ReadLine()
        {
            return reader.ReadLine();
        }

        public long NextLong()
        {
            return long.Parse(this.NextToken());
        }

        public double NextDouble()
        {
            return double.Parse(this.NextToken(), CultureInfo.InvariantCulture);
        }

        public int[] ReadIntArray(int n)
        {
            int[] a = new int[n];
            for (int i = 0; i < n; i++)
                a[i] = NextInt();
            return a;
        }

        public long[] ReadLongArray(int n)
        {
            long[] a = new long[n];
            for (int i = 0; i < n; i++)
                a[i] = NextLong();
            return a;
        }

        public double[] ReadDoubleArray(int n)
        {
            double[] a = new double[n];
            for (int i = 0; i < n; i++)
                a[i] = NextDouble();
            return a;
        }

        public string NextToken()
        {
            var c = SkipWS();
            if (c == -1)
                return null;
            var sb = new StringBuilder();
            while (c > 0 && !char.IsWhiteSpace((char)c))
            {
                sb.Append((char)c);
                c = this.reader.Read();
            }
            return sb.ToString();
        }

        private int SkipWS()
        {
            int c = this.reader.Read();
            if (c == -1)
                return c;
            while (c > 0 && char.IsWhiteSpace((char)c))
                c = this.reader.Read();
            return c;
        }

        public Tokenizer(TextReader reader)
        {
            this.reader = reader;
        }
    }

}


using System;
using System.IO;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;

class Program
{

    //////////////////////////////////////////////////
    void Solution()
    {
        var n = ri;
        var m = ri;
        var a = new int[m];
        var b = new int[m];
        var d = new List<int>[n];
        for (int i = 0; i < n; i++)
        {
            d[i] = new List<int>();
            d[i].Add(i);
        }
        for (int i = 0; i < m; i++)
        {
            a[i] = ri - 1;
            b[i] = ri - 1;
            d[a[i]].Add(b[i]);
            d[b[i]].Add(a[i]);
        }
        for (int i = 0; i < n; i++)
            d[i].Sort();
        var w = new bool[n];
        for (int i = 0; i < n; i++)
        {
            if (!w[i])
            {
                w[i] = true;
                var list = d[i];
                for (int p = 1; p < list.Count; p++)
                {
                    int ind = list[p];
                    w[ind] = true;
                    var y = d[ind];
                    if (y.Count != list.Count)
                    {
                        wln("NO");
                        return;
                    }
                    for (int k = p+1; k < y.Count; k++)
                    {
                        if (list[k]!=y[k])
                        {
                            wln("NO");
                            return;
                        }
                    }
                }
            }
        }
        wln("YES");
    }
    //////////////////////////////////////////////////

    static void swap<T>(ref T o1, ref T o2) { var o = o1; o1 = o2; o2 = o; }

    static void wln() { Console.WriteLine(); }
    static void wln<T>(T o) { Console.WriteLine(o); }
    static void wsp<T>(T o) { Console.Write(o + " "); }
    static void wrt<T>(T o) { Console.Write(o); }

    static void wln(double o) { Console.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:F12}", o)); }
    static void wsp(double o) { Console.Write(string.Format(CultureInfo.InvariantCulture, "{0:F12} ", o)); }
    static void wrt(double o) { Console.Write(string.Format(CultureInfo.InvariantCulture, "{0:F12}", o)); }

    static long gcd(long a, long b) { return (b != 0) ? gcd(b, a % b) : a; }
    static long lcm(long a, long b) { return a / gcd(a, b) * b; }

    int ri
    {
        get
        {
            _read(); while (_str[_ind] == ' ') ++_ind;
            int sign = 1; if (_str[_ind] == '-') { sign = -1; ++_ind; }
            int p = 0;
            while (_ind < _count && _str[_ind] != ' ') p = p * 10 + _str[_ind++] - '0';
            while (_ind < _count && _str[_ind] == ' ') ++_ind; return p * sign;
        }
    }
    long rl
    {
        get
        {
            _read(); while (_str[_ind] == ' ') ++_ind;
            int sign = 1; if (_str[_ind] == '-') { sign = -1; ++_ind; }
            long p = 0;
            while (_ind < _count && _str[_ind] != ' ') p = p * 10 + _str[_ind++] - '0';
            while (_ind < _count && _str[_ind] == ' ') ++_ind; return p * sign;
        }
    }
    double rd
    {
        get
        {
            _read(); while (_str[_ind] == ' ') ++_ind; int sign = 1; if (_str[_ind] == '-') { sign = -1; ++_ind; }
            long p = 0, q = 1; while (_ind < _count && _str[_ind] != ' ' && _str[_ind] != '.') p = p * 10 + _str[_ind++] - '0';
            if (_ind < _count && _str[_ind] == '.') { ++_ind; while (_ind < _count && _str[_ind] != ' ') { p = p * 10 + _str[_ind++] - '0'; q *= 10; } }
            while (_ind < _count && _str[_ind] == ' ') ++_ind; return (double)p / q * sign;
        }
    }
    string rs
    {
        get
        {
            _read(); while (_ind < _count && _str[_ind] == ' ') ++_ind;
            var tmp = _str.IndexOf(' ', _ind);
            if (tmp == -1) { _count = 0; _ind = 0; return _str.Substring(_ind); }
            var s = _str.Substring(_ind, tmp - _ind); _ind = tmp + 1;
            while (_ind < _count && _str[_ind] == ' ') ++_ind; return s;
        }
    }

    int[] ria(int n)
    {
        var res = new int[n];
        for (int k = 0; k < n;)
        {
            var s = Console.ReadLine(); var m = s.Length;
            for (int i = 0; i < m && k < n; ++i)
            {
                while (i < m && s[i] == ' ') ++i; if (i == m) break; int sign = 1; if (s[i] == '-') { sign = -1; ++i; }
                int p = 0; while (i < m && s[i] != ' ') p = p * 10 + s[i++] - '0'; res[k++] = p * sign;
            }
        }
        _count = 0; _ind = 0; return res;
    }
    long[] rla(int n)
    {
        var res = new long[n];
        for (int k = 0; k < n;)
        {
            var s = Console.ReadLine(); var m = s.Length;
            for (int i = 0; i < m && k < n; ++i)
            {
                while (i < m && s[i] == ' ') ++i; if (i == m) break; int sign = 1; if (s[i] == '-') { sign = -1; ++i; }
                long p = 0; while (i < m && s[i] != ' ') p = p * 10 + s[i++] - '0'; res[k++] = p * sign;
            }
        }
        _count = 0; _ind = 0; return res;
    }
    double[] rda(int n)
    {
        var res = new double[n];
        for (int k = 0; k < n;)
        {
            var s = Console.ReadLine(); var m = s.Length;
            for (int i = 0; i < m && k < n; ++i)
            {
                while (i < m && s[i] == ' ') ++i; if (i == m) break; int sign = 1; if (s[i] == '-') { sign = -1; ++i; }
                long p = 0, q = 1; while (i < m && s[i] != ' ' && s[i] != '.') p = p * 10 + s[i++] - '0';
                if (i < m && s[i] == '.') { ++i; while (i < m && s[i] != ' ') { p = p * 10 + s[i++] - '0'; q *= 10; } }
                res[k++] = (double)p / q * sign;
            }
        }
        _count = 0; _ind = 0; return res;
    }
    string[] rsa(int n) { var res = new string[n]; for (int k = 0; k < n; ++k) res[k] = Console.ReadLine(); _count = 0; _ind = 0; return res; }
    string _str = null; int _count = 0; int _ind = 0;
    void _read() { if (_ind == _count) { _str = Console.ReadLine(); _count = _str.Length; _ind = 0; } }
    static void Main()
    {
        new Program().Solution();
    }
}


#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>

#define MAXN 150002
#define MAXM 150002

typedef unsigned int u32;

struct node {
	u32 degree; // cant. de vecinos del nodo / tamaño de la lista
	u32 filled; //cant. de slots ocupados
	u32 color;
	u32* neighbors;
};

struct graph {
	u32 n; // #nodos
	u32 m; // #aristas
	struct node** AdjList; //lista de adyacencia de grafo
};

struct graph* empty_graph(u32 n) { //crea un grafo vacio con n nodos
	struct graph* g = calloc(1,sizeof(struct graph));
	assert(g!=NULL);
	g->n=n;
	g->m=0;
	g->AdjList = (struct node**) malloc(n*sizeof(struct node*));
	return g;
}

struct node* empty_node(u32 v) { //crea una lista con espacio para v vecinos
	struct node* vertex=calloc(1,sizeof(struct node));
	vertex->degree=v;
	vertex->filled=0;
	vertex->color=0;
	vertex->neighbors = (u32*) malloc(v*sizeof(u32));
	return vertex;
}

struct node* add_neighbor(struct node* vertex, u32 v) {
	vertex->neighbors[vertex->filled]=v;
	vertex->filled++;
	return vertex;
}

struct graph* append_edge(struct graph* g, u32 a, u32 b) {
	g->m++;
	g->AdjList[a]=add_neighbor(g->AdjList[a],b);
	g->AdjList[b]=add_neighbor(g->AdjList[b],a);
	return g;
}

void print_graph(struct graph* g) {
	for(int i=0;i<g->n;i++) {
		printf("neighbors of vertex %u are: ",i);
		for(int j=0;j<g->AdjList[i]->degree;j++) {
			printf("%u ",g->AdjList[i]->neighbors[j]);
		}
		puts("");
	}
}

bool vis[MAXN];
long long co=0;
u32 cc[MAXN];

void dfs(struct graph* g, u32 node) {
	if(!vis[node]) {
		cc[co]=node;
		co++;
		vis[node]=true;
		for(int i=0;i<g->AdjList[node]->degree;i++) {
			dfs(g,g->AdjList[node]->neighbors[i]);
		}
	}
}

int main() {
	u32 n,m;
	scanf("%u %u",&n,&m); //n es la cantidad de nodos y m la de aristas que me van a inputear
	struct graph* g = empty_graph(n);
	u32* degrees=malloc(n*sizeof(u32)); //acá voy a guardar los degrees de todos los nodos
	memset(degrees,0,n*sizeof(u32));
	u32 edges[150001][2]; //acá voy a guardarme cuales son las aristas que me inputearon
	for(int i=0;i<m;i++) {
		u32 a,b;
		scanf("%u %u",&a,&b);
		a--;b--;
		edges[i][0]=a,edges[i][1]=b;
		degrees[a]++,degrees[b]++;
	}
	for(int i=0;i<n;i++) {
		g->AdjList[i]=empty_node(degrees[i]);
	}
	for(int i=0;i<m;i++) {
		g = append_edge(g,edges[i][0],edges[i][1]);
	}
	for(int k=0;k<n;k++) {
			if(!vis[k]) {
				co=0;
				dfs(g,k);
				long long S=0;
				for(int i=0;i<co;i++) {
					S+=g->AdjList[cc[i]]->degree;
				}
				if(S!=co*(co-1)) {
					puts("NO");
					return 0;
				}
			}
	}
	puts("YES");
	return 0;
}


#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>

#define MAXN 150002
#define MAXM 150002

typedef unsigned int u32;

struct list {
	u32 degree; // cant. de vecinos del nodo / tamaño de la lista
	u32 busy; //cant. de slots ocupados
	u32 color_of_node;
	u32* neighbors;
};

struct graph {
	u32 n; // #nodos
	u32 m; // #aristas
	struct list* AdjList; //lista de adyacencia de grafo
};

struct graph empty_graph(u32 n) { //crea un grafo vacio con n nodos
	struct graph g;
	g.n=n;
	g.m=0;
	g.AdjList = (struct list*) malloc(n*sizeof(struct list));
	return g;
}

struct list empty_list(u32 v) { //crea una lista con espacio para v vecinos
	struct list list;
	list.degree=v;
	list.busy=0;
	list.color_of_node=0;
	list.neighbors = (u32*) malloc(v*sizeof(u32));
	return list;
}

struct list add_neighbor(struct list list, u32 v) {
	list.neighbors[list.busy]=v;
	list.busy++;
	return list;
}

struct graph append_edge(struct graph g, u32 a, u32 b) {
	g.m++;
	g.AdjList[a]=add_neighbor(g.AdjList[a],b);
	g.AdjList[b]=add_neighbor(g.AdjList[b],a);
	return g;
}

void print_graph(struct graph g) {
	for(int i=0;i<g.n;i++) {
		printf("neigbors of vertex %u are: ",i);
		for(int j=0;j<g.AdjList[i].degree;j++) {
			printf("%u ",g.AdjList[i].neighbors[j]);
		}
		puts("");
	}
}

int main() {
	u32 n,m;
	scanf("%u %u",&n,&m); //n es la cantidad de nodos y m la de aristas que me van a inputear
	struct graph g = empty_graph(n);
	u32* degrees=malloc(n*sizeof(u32)); //acá voy a guardar los degrees de todos los nodos
	memset(degrees,0,sizeof(degrees));
	u32** edges=malloc(m*sizeof(2*u32)); //acá voy a guardarme cuales son las aristas que me inputearon
	for(int i=0;i<m;i++) {
		u32 a,b;
		scanf("%u %u",&a,&b);
		a--,b--;
		edges[i][0]=a,edges[i][1]=b;
		degrees[a]++,degrees[b]++;
	}
	for(int i=0;i<n;i++) {
		g.AdjList[i]=empty_list(degrees[i]);
	}
	for(int i=0;i<m;i++) {
		g = append_edge(g,edges[i][0],edges[i][1]);
	}
	print_graph(g); //imprimo el grafo para chequear que todo este ok
	return 0;
}


#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>

const int MAXN = 1000;
const int MAXM = 1000;

typedef unsigned int u32;

struct list {
	u32 degree; // cant. de vecinos del nodo / tamaño de la lista
	u32 busy; //cant. de slots ocupados
	u32 color_of_node;
	u32* neighbors;
};

struct graph {
	u32 n; // #nodos
	u32 m; // #aristas
	struct list* AdjList; //lista de adyacencia de grafo
};

struct graph empty_graph(u32 n) { //crea un grafo vacio con n nodos
	struct graph g;
	g.n=n;
	g.m=0;
	g.AdjList = (struct list*) malloc(n*sizeof(list));
	return g;
}

struct list empty_list(u32 v) { //crea una lista con espacio para v vecinos
	struct list list;
	list.degree=v;
	list.busy=0;
	list.color_of_node=0;
	list.neighbors = (u32*) malloc(v*sizeof(u32));
	return list;
}

struct list add_neighbor(struct list list, u32 v) {
	list.neighbors[list.busy]=v;
	list.busy++;
	return list;
}

struct graph append_edge(struct graph g, u32 a, u32 b) {
	g.m++;
	g.AdjList[a]=add_neighbor(g.AdjList[a],b);
	g.AdjList[b]=add_neighbor(g.AdjList[b],a);
	return g;
}

void print_graph(struct graph g) {
	for(int i=0;i<g.n;i++) {
		printf("neigbors of vertex %u are: ",i);
		for(int j=0;j<g.AdjList[i].degree;j++) {
			//printf("%u ",g.AdjList[i].neighbors[j]);
		}
		puts("");
	}
}

bool vis[MAXN];
long long co=0;
u32 cc[MAXN];

void dfs(struct graph g, u32 node) {
	if(!vis[node]) {
		cc[co]=node;
		co++;
		vis[node]=true;
		for(int i=0;i<g.AdjList[node].degree;i++) {
			dfs(g,g.AdjList[node].neighbors[i]);
		}
	}
}

int main() {
	u32 n,m;
	scanf("%u %u",&n,&m); //n es la cantidad de nodos y m la de aristas que me van a inputear
	struct graph g = empty_graph(n);
	u32 degrees[MAXN]; //acá voy a guardar los degrees de todos los nodos
	memset(degrees,0,sizeof(degrees));
	u32 edges[MAXM][2]; //acá voy a guardarme cuales son las aristas que me inputearon
	for(int i=0;i<m;i++) {
		u32 a,b;
		scanf("%u %u",&a,&b);
		a--,b--;
		edges[i][0]=a,edges[i][1]=b;
		degrees[a]++,degrees[b]++;
	}
	for(int i=0;i<n;i++) {
		g.AdjList[i]=empty_list(degrees[i]);
	}
	for(int i=0;i<m;i++) {
		g = append_edge(g,edges[i][0],edges[i][1]);
	}
	for(int k=0;k<n;k++) {
		if(!vis[k]) {
			co=0;
			dfs(g,k);
			long long S=0;
			for(int i=0;i<co;i++) {
				S+=g.AdjList[cc[i]].degree;
			}
			if(S!=co*(co-1)) {
				puts("NO");
				return 0;
			}
		}
	}
	puts("YES");
	return 0;
}


#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>

#define MAXN 150002
#define MAXM 150002

typedef unsigned int u32;

struct node {
	u32 degree; // cant. de vecinos del nodo / tamaño de la lista
	u32 filled; //cant. de slots ocupados
	u32 color;
	u32* neighbors;
};

struct graph {
	u32 n; // #nodos
	u32 m; // #aristas
	struct node** AdjList; //lista de adyacencia de grafo
};

struct graph* empty_graph(u32 n) { //crea un grafo vacio con n nodos
	struct graph* g = calloc(1,sizeof(struct graph));
	assert(g!=NULL);
	g->n=n;
	g->m=0;
	g->AdjList = (struct node**) malloc(n*sizeof(struct node*));
	return g;
}

struct node* empty_node(u32 v) { //crea una lista con espacio para v vecinos
	struct node* vertex=(struct node*) malloc(1*sizeof(struct node));
	vertex->degree=v;
	vertex->filled=0;
	vertex->color=0;
	vertex->neighbors = (u32*) malloc(v*sizeof(u32));
	return vertex;
}

void add_neighbor(struct node* vertex, u32 v) {
	vertex->neighbors[vertex->filled]=v;
	vertex->filled++;
}

void append_edge(struct graph* g, u32 a, u32 b) {
	g->m++;
	add_neighbor(g->AdjList[a],b);
	add_neighbor(g->AdjList[b],a);
}

void print_graph(struct graph* g) {
	for(int i=0;i<g->n;i++) {
		printf("neighbors of vertex %u are: ",i);
		for(int j=0;j<g->AdjList[i]->degree;j++) {
			printf("%u ",g->AdjList[i]->neighbors[j]);
		}
		puts("");
	}
}

bool vis[MAXN];
long long co=0;
u32 cc[MAXN];

void dfs(struct graph* g, u32 node) {
	if(!vis[node]) {
		cc[co]=node;
		co++;
		vis[node]=true;
		for(int i=0;i<g->AdjList[node]->degree;i++) {
			dfs(g,g->AdjList[node]->neighbors[i]);
		}
	}
}

int main() {
	u32 n,m;
	scanf("%u %u",&n,&m); //n es la cantidad de nodos y m la de aristas que me van a inputear
	struct graph* g = empty_graph(n);
	u32* degrees=malloc(n*sizeof(u32)); //acá voy a guardar los degrees de todos los nodos
	memset(degrees,0,n*sizeof(u32));
	u32 edges[m][2]; //acá voy a guardarme cuales son las aristas que me inputearon
	for(int i=0;i<m;i++) {
		u32 a,b;
		scanf("%u %u",&a,&b);
		a--;b--;
		edges[i][0]=a,edges[i][1]=b;
		degrees[a]++,degrees[b]++;
	}
	for(int i=0;i<n;i++) {
		g->AdjList[i]=empty_node(degrees[i]);
	}
	for(int i=0;i<m;i++) {
		append_edge(g,edges[i][0],edges[i][1]);
	}
	for(int k=0;k<n;k++) {
			if(!vis[k]) {
				co=0;
				dfs(g,k);
				long long S=0;
				for(int i=0;i<co;i++) {
					S+=g->AdjList[cc[i]]->degree;
				}
				if(S!=co*(co-1)) {
					puts("NO");
					return 0;
				}
			}
	}
	puts("YES");
	return 0;
}


#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>

#define MAXN 150002
#define MAXM 150002

typedef unsigned int u32;

struct node {
	u32 degree; // cant. de vecinos del nodo / tamaño de la lista
	u32 filled; //cant. de slots ocupados
	u32 color;
	u32* neighbors;
};

struct graph {
	u32 n; // #nodos
	u32 m; // #aristas
	struct node** AdjList; //lista de adyacencia de grafo
};

struct graph* empty_graph(u32 n) { //crea un grafo vacio con n nodos
	struct graph* g = calloc(1,sizeof(struct graph));
	assert(g!=NULL);
	g->n=n;
	g->m=0;
	g->AdjList = (struct node**) malloc(n*sizeof(struct node*));
	return g;
}

struct node* empty_node(u32 v) { //crea una lista con espacio para v vecinos
	struct node* vertex=calloc(1,sizeof(struct node));
	vertex->degree=v;
	vertex->filled=0;
	vertex->color=0;
	vertex->neighbors = (u32*) malloc(v*sizeof(u32));
	return vertex;
}

struct node* add_neighbor(struct node* vertex, u32 v) {
	vertex->neighbors[vertex->filled]=v;
	vertex->filled++;
	return vertex;
}

struct graph* append_edge(struct graph* g, u32 a, u32 b) {
	g->m++;
	g->AdjList[a]=add_neighbor(g->AdjList[a],b);
	g->AdjList[b]=add_neighbor(g->AdjList[b],a);
	return g;
}

void print_graph(struct graph* g) {
	for(int i=0;i<g->n;i++) {
		printf("neighbors of vertex %u are: ",i);
		for(int j=0;j<g->AdjList[i]->degree;j++) {
			printf("%u ",g->AdjList[i]->neighbors[j]);
		}
		puts("");
	}
}

bool vis[MAXN];
long long co=0;
u32 cc[MAXN];

void dfs(struct graph* g, u32 node) {
	if(!vis[node]) {
		cc[co]=node;
		co++;
		vis[node]=true;
		for(int i=0;i<g->AdjList[node]->degree;i++) {
			dfs(g,g->AdjList[node]->neighbors[i]);
		}
	}
}

int main() {
	u32 n,m;
	scanf("%u %u",&n,&m); //n es la cantidad de nodos y m la de aristas que me van a inputear
	struct graph* g = empty_graph(n);
	u32* degrees=malloc(n*sizeof(u32)); //acá voy a guardar los degrees de todos los nodos
	memset(degrees,0,n*sizeof(u32));
	u32 edges[1000][1000]; //acá voy a guardarme cuales son las aristas que me inputearon
	for(int i=0;i<m;i++) {
		u32 a,b;
		scanf("%u %u",&a,&b);
		a--;b--;
		edges[i][0]=a,edges[i][1]=b;
		degrees[a]++,degrees[b]++;
	}
	for(int i=0;i<n;i++) {
		g->AdjList[i]=empty_node(degrees[i]);
	}
	for(int i=0;i<m;i++) {
		g = append_edge(g,edges[i][0],edges[i][1]);
	}
	for(int k=0;k<n;k++) {
			if(!vis[k]) {
				co=0;
				dfs(g,k);
				long long S=0;
				for(int i=0;i<co;i++) {
					S+=g->AdjList[cc[i]]->degree;
				}
				if(S!=co*(co-1)) {
					puts("NO");
					return 0;
				}
			}
	}
	puts("YES");
	return 0;
}


#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>

#define MAXN 150002
#define MAXM 150002

typedef unsigned int u32;

struct list {
	u32 degree; // cant. de vecinos del nodo / tamaño de la lista
	u32 busy; //cant. de slots ocupados
	u32 color_of_node;
	u32* neighbors;
};

struct graph {
	u32 n; // #nodos
	u32 m; // #aristas
	struct list* AdjList; //lista de adyacencia de grafo
};

struct graph empty_graph(u32 n) { //crea un grafo vacio con n nodos
	struct graph g;
	g.n=n;
	g.m=0;
	g.AdjList = (struct list*) malloc(n*sizeof(struct list));
	return g;
}

struct list empty_list(u32 v) { //crea una lista con espacio para v vecinos
	struct list list;
	list.degree=v;
	list.busy=0;
	list.color_of_node=0;
	list.neighbors = (u32*) malloc(v*sizeof(u32));
	return list;
}

struct list add_neighbor(struct list list, u32 v) {
	list.neighbors[list.busy]=v;
	list.busy++;
	return list;
}

struct graph append_edge(struct graph g, u32 a, u32 b) {
	g.m++;
	g.AdjList[a]=add_neighbor(g.AdjList[a],b);
	g.AdjList[b]=add_neighbor(g.AdjList[b],a);
	return g;
}

void print_graph(struct graph g) {
	for(int i=0;i<g.n;i++) {
		printf("neigbors of vertex %u are: ",i);
		for(int j=0;j<g.AdjList[i].degree;j++) {
			//printf("%u ",g.AdjList[i].neighbors[j]);
		}
		puts("");
	}
}

bool vis[MAXN];
long long co=0;
u32 cc[MAXN];

void dfs(struct graph g, u32 node) {
	if(!vis[node]) {
		cc[co]=node;
		co++;
		vis[node]=true;
		for(int i=0;i<g.AdjList[node].degree;i++) {
			dfs(g,g.AdjList[node].neighbors[i]);
		}
	}
}

int main() {
	memset(vis,0,sizeof(vis));
	memset(cc,0,sizeof(cc));
	u32 n,m;
	scanf("%u %u",&n,&m); //n es la cantidad de nodos y m la de aristas que me van a inputear
	struct graph g = empty_graph(n);
	u32 degrees[MAXN]; //acá voy a guardar los degrees de todos los nodos
	memset(degrees,0,sizeof(degrees));
	u32 edges[MAXM][2]; //acá voy a guardarme cuales son las aristas que me inputearon
	for(int i=0;i<m;i++) {
		u32 a,b;
		scanf("%u %u",&a,&b);
		a--,b--;
		edges[i][0]=a,edges[i][1]=b;
		degrees[a]++,degrees[b]++;
	}
	for(int i=0;i<n;i++) {
		g.AdjList[i]=empty_list(degrees[i]);
	}
	for(int i=0;i<m;i++) {
		g = append_edge(g,edges[i][0],edges[i][1]);
	}
	for(int k=0;k<n;k++) {
		if(!vis[k]) {
			co=0;
			dfs(g,k);
			long long S=0;
			for(int i=0;i<co;i++) {
				S+=g.AdjList[cc[i]].degree;
			}
			if(S!=co*(co-1)) {
				puts("NO");
				return 0;
			}
		}
	}
	puts("YES");
	return 0;
}


#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>

int MAXN = 1000;

typedef unsigned int u32;

struct node {
	u32 label;
	u32 truename;
	u32 color;
};

struct node create_node(u32 truename, u32 label){
	struct node v;
	v.truename = truename;
	v.label = label;
	v.color = 0;
	return v;
}

struct node color_node(struct node v, u32 color) {
	v.color=color;
	return v;
}

struct ALN { //Adjacency list node
	struct node node;
	struct ALN* next;
};

struct ALN* create_ALN(struct node node) {
	struct ALN* v = (struct ALN*) malloc(sizeof(struct ALN));
	v->node = node;
	v->next = NULL;
	return v;
}

struct AdjacencyList {
	struct ALN* first;
	u32 length;
};

struct graph {
	u32 V;
	struct AdjacencyList* nodes;
};

struct graph* create_graph(int V) {
	struct graph* graph = (struct graph *) malloc(sizeof(struct graph));
	graph->V = V;
	graph->nodes = (struct AdjacencyList*) malloc(V*sizeof(struct AdjacencyList));
	for(int i=0;i<V;i++) {
		(graph->nodes[i]).first=NULL;
		graph->nodes[i].length=0;
	}
	return graph;
}

void add_edge(struct graph* graph, struct node fst, struct node snd) {
	struct ALN* v = create_ALN(snd);
	struct ALN* w = create_ALN(fst);
	v->next = graph->nodes[fst.label].first;
	graph->nodes[fst.label].first = v;
	graph->nodes[fst.label].length+=1;
	w->next = graph->nodes[snd.label].first;
	graph->nodes[snd.label].first = w;
	graph->nodes[snd.label].length+=1;
}

u32 non(struct graph* graph, struct node fst) {
	return graph->nodes[fst.label].length;
}

void printGraph(struct graph* graph) {
    for (int v = 0; v < graph->V; v++) {
        struct ALN* pCrawl = graph->nodes[v].first;
        printf("\n Adjacency list of vertex %d\n head ", v);
        while (pCrawl) {
            printf("-> %d", pCrawl->node.truename);
            pCrawl = pCrawl->next;
        }
        printf("\n");
    }
}

bool vis[150001];
long long pingot=0;
int comp[150001];

void dfs(struct graph* g, struct node v) {
	if(!vis[v.label]) {
		comp[pingot]=v.label;
		pingot++;
		vis[v.label]=true;
		struct ALN* hola = g->nodes[v.label].first;
		while(hola) {
			dfs(g,hola->node);
			hola = hola->next;
		}
	}
}

int main() {
	int n,m;
	scanf("%d %d",&n,&m);
	struct node pingo[150001];
	for(int i=0;i<n;i++) {
		pingo[i]=create_node(i,i);
	}
	struct graph* graph = create_graph(n);
	for(int i=0;i<m;i++) {
		int a,b;
		scanf("%d %d",&a,&b);
		add_edge(graph,pingo[a-1],pingo[b-1]);
	}
	for(int k=0;k<n;k++) {
		if(!vis[k]) {
			memset(comp,0,sizeof(comp));
			pingot=0;
			dfs(graph,pingo[k]);
			long long concha=0;
		    for(int i=0;i<pingot;i++) {
		    	concha+=non(graph,pingo[comp[i]]);
		    }
			if(concha!=pingot*(pingot-1)) {
				puts("NO");
				return 0;
			}
		}
	}
	puts("YES");
	return 0;
}

/*int main() {
	int V=5;
	struct graph* graph = create_graph(V);
	struct node pingo[8];
	for(int i=0;i<5;i++) {
		pingo[i]=create_node(19+i,i);
	}
	add_edge(graph, pingo[0], pingo[1]);
    //add_edge(graph, pingo[0], pingo[4]);
    add_edge(graph, pingo[1], pingo[2]);
    add_edge(graph, pingo[1], pingo[3]);
    //add_edge(graph, pingo[1], pingo[4]);
    add_edge(graph, pingo[2], pingo[3]);
    //add_edge(graph, pingo[3], pingo[4]);

	pingo[2]=color_node(pingo[2],19);

	printGraph(graph);
	dfs(graph,pingo[0]);
	for(int i=0;i<5;i++) {
		if(vis[i]) printf("visite el %u!\n",i);
	}

	printf("el color del nodo pintado es %u\n",pingo[2].color);
	for(int i=0;i<5;i++) printf("la cantidad de vecinos del nodo ese es %u\n",non(graph,pingo[i]));

	return 0;
}*/


#include <stdio.h>
#include <stdlib.h>

typedef struct ListNode
{
    int value;
    struct ListNode *next;
} ListNode;

ListNode* CreateListNode(int val)
{
    ListNode *new_node = (ListNode*)malloc(sizeof(ListNode));
    new_node->value = val;
    new_node->next = NULL;
    return new_node;
}

void AddToList(ListNode **l, int val)
{
    ListNode *new_node = CreateListNode(val);
    new_node->next = *l;
    *l = new_node;
}

typedef struct Node
{
    int distance;
    ListNode *edges;
} Node;

Node* CreateGraph(int n)
{
    Node *graph = (Node*)malloc(sizeof(Node) * n);
    int i;
    for (i = 0; i < n; ++i) {
        graph[i].distance = -1;
        graph[i].edges = NULL;
    }
    return graph;
}

void Dfs(Node g[], int node)
{
    ListNode *it = g[node].edges;
    int next;

    while (it) {
        next = it->value;
        if (g[next].distance == -1 || g[next].distance > g[node].distance + 1) {
            g[next].distance = g[node].distance + 1;
            Dfs(g, next);
        }
        it = it->next;
    }
}

int main()
{
    int n, m, x, y, i, correct;
    scanf("%d%d", &n, &m);

    Node *graph = CreateGraph(n);
    while (m--) {
        scanf("%d%d", &x, &y);
        AddToList(&graph[x - 1].edges, y - 1);
        AddToList(&graph[y - 1].edges, x - 1);
    }

    for (i = 0; i < n; ++i) {
        if (graph[i].distance == -1) {
            graph[i].distance = 0;
            Dfs(graph, i);
        }
    }

    correct = 1;
    for (i = 0; i < n && correct == 1; ++i) {
        if (graph[i].distance > 1) {
            correct = 0;
        }
    }

    printf("%s\n", (correct ? "YES" : "NO"));
    return 0;
}


#include <stdio.h>
#include <stdlib.h>

typedef struct ListNode
{
    int value;
    struct ListNode *next;
} ListNode;

ListNode* CreateListNode(int val)
{
    ListNode *new_node = (ListNode*)malloc(sizeof(ListNode));
    new_node->value = val;
    new_node->next = NULL;
    return new_node;
}

void AddToList(ListNode *l, int val)
{
    ListNode *new_node = CreateListNode(val);
    new_node->next = l;
    l = new_node;
}

typedef struct Node
{
    int distance;
    ListNode edges;
} Node;

Node* CreateGraph(int n)
{
    Node *graph = (Node*)malloc(sizeof(Node) * n);
    int i;
    for (i = 0; i < n; ++i) {
        graph[i].distance = -1;
        graph[i].edges = NULL;
    }
    return graph;
}

void Dfs(Node g[], int node)
{
    ListNode *it = g[node].edges;
    int next;

    while (it) {
        next = it->value;
        if (g[next].distance == -1 || g[next].distance > g[node].distance + 1) {
            g[next].distance = g[node].distance + 1;
            Dfs(g, next);
        }
        it = it->next;
    }
}

int main()
{
    int n, m, x, y, i, correct;
    scanf("%d%d", &n, &m);

    Node *graph = CreateGraph(n);
    while (m--) {
        scanf("%d%d", &x, &y);
        AddToList(&graph[x - 1].edges, y - 1);
        AddToList(&graph[y - 1].edges, x - 1);
    }

    for (i = 0; i < n; ++i) {
        if (graph[i].distance == -1) {
            graph[i].distance = 0;
            Dfs(graph, i);
        }
    }

    correct = 1;
    for (i = 0; i < n && correct == 1; ++i) {
        if (graph[i].distance > 1) {
            correct = 0;
        }
    }

    printf("%s\n", (correct ? "YES" : "NO"));
    return 0;
}


#include <stdio.h>
#include <stdlib.h>

typedef struct ListNode
{
    int value;
    struct ListNode *next;
} ListNode;

ListNode* CreateListNode(int val)
{
    ListNode *new_node = (ListNode*)malloc(sizeof(ListNode));
    new_node->value = val;
    new_node->next = NULL;
    return new_node;
}

void AddToList(ListNode **l, int val)
{
    ListNode *new_node = CreateListNode(val);
    new_node->next = *l;
    *l = new_node;
}

typedef struct Node
{
    int distance;
    ListNode *edges;
} Node;

Node* CreateGraph(int n)
{
    Node *graph = (Node*)malloc(sizeof(Node) * n);
    int i;
    for (i = 0; i < n; ++i) {
        graph[i].distance = -1;
        graph[i].edges = NULL;
    }
    return graph;
}

typedef struct List
{
    ListNode *left, *right;
} List;

void QueueAdd(List *l, int val)
{
    ListNode *new_node = CreateListNode(val);
    if (!l->left) {
        l->left = l->right = new_node;
    } else {
        l->right->next = new_node;
        l->right = new_node;
    }
}

int QueuePop(List *l)
{
    int val = l->left->value;
    ListNode *to_delete = l->left;

    l->left = l->left->next;
    free(to_delete);

    return val;
}

int Bfs(Node g[], int n, int node)
{
    List q;
    q.left = q.right = NULL;

    int i;
    for (i = 0; i < n; ++i) {
        g[i].distance = -1;
    }

    g[node].distance = 0;
    QueueAdd(&q, node);

    while (q.left) {
        node = QueuePop(&q);

        ListNode *it = g[node].edges;
        while (it) {
            int next = it->value;
            it = it->next;

            if (g[next].distance == -1) {
                g[next].distance = g[node].distance + 1;
                if (g[next].distance > 1) {
                    return 0;
                }
                QueueAdd(&q, next);
            }
        }
    }
    return 1;
}

int main()
{
    int n, m, x, y, i, correct;
    scanf("%d%d", &n, &m);

    Node *graph = CreateGraph(n);
    while (m--) {
        scanf("%d%d", &x, &y);
        AddToList(&graph[x - 1].edges, y - 1);
        AddToList(&graph[y - 1].edges, x - 1);
    }

    correct = 1;
    for (i = 0; i < n && correct == 1; ++i) {
        correct = Bfs(graph, n, i);
    }

    printf("%s\n", (correct ? "YES" : "NO"));
    return 0;
}


#include <stdio.h>
#include <stdlib.h>

typedef struct ListNode
{
    int value;
    struct ListNode *next;
} ListNode;

ListNode* CreateListNode(int val)
{
    ListNode *new_node = (ListNode*)malloc(sizeof(ListNode));
    new_node->value = val;
    new_node->next = NULL;
    return new_node;
}

void AddToList(ListNode **l, int val)
{
    ListNode *new_node = CreateListNode(val);
    new_node->next = *l;
    *l = new_node;
}

typedef struct Node
{
    int distance;
    ListNode *edges;
} Node;

Node* CreateGraph(int n)
{
    Node *graph = (Node*)malloc(sizeof(Node) * n);
    int i;
    for (i = 0; i < n; ++i) {
        graph[i].distance = -1;
        graph[i].edges = NULL;
    }
    return graph;
}

typedef struct List
{
    ListNode *left, *right;
} List;

void QueueAdd(List *l, int val)
{
    ListNode *new_node = CreateListNode(val);
    if (!l->left) {
        l->left = l->right = new_node;
    } else {
        l->right->next = new_node;
        l->right = new_node;
    }
}

int QueuePop(List *l)
{
    int val = l->left->value;
    ListNode *to_delete = l->left;

    l->left = l->left->next;
    free(to_delete);

    return val;
}

int Bfs(Node g[], int node)
{
    List q;
    q.left = q.right = NULL;

    int i;
    for (i = 0; i < sizeof(g) / sizeof(g[0]); ++i) {
        g[i].distance = -1;
    }

    g[node].distance = 0;
    QueueAdd(&q, node);

    while (q.left) {
        node = QueuePop(&q);

        ListNode *it = g[node].edges;
        while (it) {
            int next = it->value;
            it = it->next;

            if (g[next].distance == -1) {
                g[next].distance = g[node].distance + 1;
                if (g[next].distance > 1) {
                    return 0;
                }
                QueueAdd(&q, next);
            }
        }
    }
    return 1;
}

int main()
{
    int n, m, x, y, i, correct;
    scanf("%d%d", &n, &m);

    Node *graph = CreateGraph(n);
    while (m--) {
        scanf("%d%d", &x, &y);
        AddToList(&graph[x - 1].edges, y - 1);
        AddToList(&graph[y - 1].edges, x - 1);
    }

    correct = 1;
    for (i = 0; i < n && correct == 1; ++i) {
        correct = Bfs(graph, i);
    }

    printf("%s\n", (correct ? "YES" : "NO"));
    return 0;
}


#include <stdio.h>
#include <stdlib.h>

typedef struct ListNode
{
    int value;
    struct ListNode *next;
} ListNode;

ListNode* CreateListNode(int val)
{
    ListNode *new_node = (ListNode*)malloc(sizeof(ListNode));
    new_node->value = val;
    new_node->next = NULL;
    return new_node;
}

void AddToList(ListNode **l, int val)
{
    ListNode *new_node = CreateListNode(val);
    new_node->next = *l;
    *l = new_node;
}

typedef struct Node
{
    int component;
    int n_edges;
    ListNode *edges;
} Node;

Node* CreateGraph(int n)
{
    Node *graph = (Node*)malloc(sizeof(Node) * n);
    int i;
    for (i = 0; i < n; ++i) {
        graph[i].component = -1;
        graph[i].n_edges = 0;
        graph[i].edges = NULL;
    }
    return graph;
}

int Dfs(Node g[], int node, int comp)
{
    int visited = 1, next;
    g[node].component = comp;

    ListNode *it = g[node].edges;
    while (it) {
        next = it->value;
        it = it->next;

        if (g[next].component == -1) {
            visited += Dfs(g, next, comp);
        }
    }
    return visited;
}

int main()
{
    int n, m, x, y, i, correct, comps;
    scanf("%d%d", &n, &m);

    Node *graph = CreateGraph(n);
    while (m--) {
        scanf("%d%d", &x, &y);
        AddToList(&graph[x - 1].edges, y - 1);
        ++graph[x - 1].n_edges;
        AddToList(&graph[y - 1].edges, x - 1);
        ++graph[y - 1].n_edges;
    }

    int *comp_sizes = (int*)malloc(sizeof(int) * n);
    comps = 0;
    for (i = 0; i < n; ++i) {
        if (graph[i].component == -1) {
            comp_sizes[comps] = Dfs(graph, i, comps);
            ++comps;
        }
    }

    correct = 1;
    for (i = 0; i < n && correct; ++i) {
        if (graph[i].n_edges != comp_sizes[graph[i].component] - 1) {
            correct = 0;
        }
    }

    printf("%s\n", (correct ? "YES" : "NO"));
    return 0;
}


#include <stdio.h>
#include <stdlib.h>

typedef struct ListNode
{
    int value;
    struct ListNode *next;
} ListNode;

ListNode* CreateListNode(int val)
{
    ListNode *new_node = (ListNode*)malloc(sizeof(ListNode));
    new_node->value = val;
    new_node->next = NULL;
    return new_node;
}

void AddToList(ListNode **l, int val)
{
    ListNode *new_node = CreateListNode(val);
    new_node->next = *l;
    *l = new_node;
}

typedef struct Node
{
    int distance;
    ListNode *edges;
} Node;

Node* CreateGraph(int n)
{
    Node *graph = (Node*)malloc(sizeof(Node) * n);
    int i;
    for (i = 0; i < n; ++i) {
        graph[i].distance = -1;
        graph[i].edges = NULL;
    }
    return graph;
}

typedef struct List
{
    ListNode *left, *right;
} List;

void QueueAdd(List *l, int val)
{
    ListNode *new_node = CreateListNode(val);
    if (!l->left) {
        l->left = l->right = new_node;
    } else {
        l->right->next = new_node;
        l->right = new_node;
    }
}

int QueuePop(List *l)
{
    int val = l->left->value;
    ListNode *to_delete = l->left;

    l->left = l->left->next;
    free(to_delete);

    return val;
}

void Bfs(Node g[], int node)
{
    List q;
    q.left = q.right = NULL;

    g[node].distance = 0;
    QueueAdd(&q, node);

    while (q.left) {
        node = QueuePop(&q);

        ListNode *it = g[node].edges;
        while (it) {
            int next = it->value;
            it = it->next;

            if (g[next].distance == -1) {
                g[next].distance = g[node].distance + 1;
                QueueAdd(&q, next);
            }
        }
    }
}

int main()
{
    int n, m, x, y, i, correct;
    scanf("%d%d", &n, &m);

    Node *graph = CreateGraph(n);
    while (m--) {
        scanf("%d%d", &x, &y);
        AddToList(&graph[x - 1].edges, y - 1);
        AddToList(&graph[y - 1].edges, x - 1);
    }

    for (i = 0; i < n; ++i) {
        if (graph[i].distance == -1) {
            Bfs(graph, i);
        }
    }

    correct = 1;
    for (i = 0; i < n && correct == 1; ++i) {
        if (graph[i].distance > 1) {
            correct = 0;
        }
    }

    printf("%s\n", (correct ? "YES" : "NO"));
    return 0;
}


#include <stdio.h>

#define N	150000

int dsu[N], kk[N];

int find(int i) {
	return dsu[i] < 0 ? i : (dsu[i] = find(dsu[i]));
}

void join(int i, int j) {
	i = find(i);
	j = find(j);
	if (i == j)
		return;
	if (dsu[i] > dsu[j])
		dsu[i] = j;
	else {
		if (dsu[i] == dsu[j])
			dsu[i]--;
		dsu[j] = i;
	}
}

int main() {
	long long sum;
	int n, m, h, i, j;

	scanf("%d%d", &n, &m);
	for (i = 0; i < n; i++)
		dsu[i] = -1;
	for (h = 0; h < m; h++) {
		scanf("%d%d", &i, &j);
		i--, j--;
		join(i, j);
	}
	for (i = 0; i < n; i++)
		kk[find(i)]++;
	sum = 0;
	for (i = 0; i < n; i++)
		sum += (long long) kk[i] * (kk[i] - 1) / 2;
	printf("%s\n", sum == m ? "YES" : "NO");
	return 0;
}


#include <stdio.h>

#define N	150000

int dsu[N + 1], kk[N + 1];

int find(int i) {
	return dsu[i] <= 0 ? i : (dsu[i] = find(dsu[i]));
}

void join(int i, int j) {
	i = find(i);
	j = find(j);
	if (i == j) {
		dsu[i]--;
		return;
	}
	if (dsu[i] <= dsu[j]) {
		dsu[i] += dsu[j] - 1;
		kk[i] += kk[j];
		dsu[j] = i;
	} else {
		dsu[j] += dsu[i] - 1;
		kk[j] += kk[i];
		dsu[i] = j;
	}
}

int main() {
	int n, m, i, j;

	scanf("%d%d", &n, &m);
	for (i = 1; i <= n; i++)
		dsu[i] = 0, kk[i] = -1;
	while (m-- > 0) {
		scanf("%d%d", &i, &j);
		join(i, j);
	}
	for (i = 1; i <= n; i++) {
		int r = find(i);
		int k = -kk[r];

		if (-dsu[r] != (long long) k * (k - 1) / 2) {
			printf("NO\n");
			return 0;
		}
	}
	printf("YES\n");
	return 0;
}


#include <stdio.h>
#include <stdlib.h>

typedef struct TYPEEDGE {
	int u, v;
} typEdge;

void Swap(int *a, int *b) {
	int t;
	t = *a;
	*a = *b;
	*b = t;
}

int EdgeCmp(const void *a, const void *b) {
	if (((typEdge*)a)->u < ((typEdge *)b)->u) return -1;
	if (((typEdge*)a)->u > ((typEdge *)b)->u) return 1;
	if (((typEdge*)a)->v < ((typEdge *)b)->v) return -1;
	if (((typEdge*)a)->v > ((typEdge *)b)->v) return 1;
	return 0;
}

int eCnt, eLast[150005], ePrev[300005], eTar[300005];
void AddEdge(int u, int v) {
	ePrev[++eCnt] = eLast[u];
	eTar[eCnt] = v;
	eLast[u] = eCnt;
}

int m;
typEdge e[300005];
int EdgeFind(int u, int v) {
	typEdge eTmp;
	int l, r;
	eTmp.u = u;
	eTmp.v = v;
	for (l = 1, r = 2 * m; l <= r; )
		if (EdgeCmp(&eTmp, &e[(l + r) / 2]) <= 0)
			r = (l + r) / 2 - 1;
		else
			l = (l + r) / 2 + 1;
	return !EdgeCmp(&eTmp, &e[r + 1]);
}

int main(int argc, char *argv[]) {
	int n, i, j, u, v;
	scanf("%d%d", &n, &m);
	for (i = 1; i <= m; ++i) {
		scanf("%d%d", &u, &v);
		AddEdge(e[i].u = u, e[i].v = v);
		AddEdge(e[m + i].u = v, e[m + i].v = u);
	}
	qsort(e + 1, 2 * m, sizeof(e[0]), EdgeCmp);
	for (i = 1; i <= n; ++i) {
		if (!eLast[i]) continue;
		for (j = eLast[i]; ePrev[j]; j = ePrev[j])
			if (!EdgeFind(eTar[j], eTar[ePrev[j]])) break;
		if (ePrev[j]) break;
	}
	puts(i > n ? "YES" : "NO");
	return 0;
}


#include <stdio.h>
#include <stdlib.h>

typedef struct TYPEEDGE {
	int u, v;
} typEdge;

void Swap(int *a, int *b) {
	int t;
	t = *a;
	*a = *b;
	*b = t;
}

int EdgeCmp(const void *a, const void *b) {
	if (((typEdge*)a)->u < ((typEdge *)b)->u) return -1;
	if (((typEdge*)a)->u > ((typEdge *)b)->u) return 1;
	if (((typEdge*)a)->v < ((typEdge *)b)->v) return -1;
	if (((typEdge*)a)->v > ((typEdge *)b)->v) return 1;
	return 0;
}

int m;
typEdge e[300005];
int EdgeFind(int u, int v) {
	typEdge eTmp;
	int l, r;
	if (u == v) return 1;
	eTmp.u = u;
	eTmp.v = v;
	for (l = 1, r = 2 * m; l <= r; )
		if (EdgeCmp(&eTmp, &e[(l + r) / 2]) <= 0)
			r = (l + r) / 2 - 1;
		else
			l = (l + r) / 2 + 1;
	return !EdgeCmp(&eTmp, &e[r + 1]);
}

int main(int argc, char *argv[]) {
	int n, i, j;
	scanf("%d%d", &n, &m);
	for (i = 1; i <= m; ++i) {
		scanf("%d%d", &e[i].u, &e[i].v);
		e[m + i].u = e[i].v;
		e[m + i].v = e[i].u;
	}
	qsort(e + 1, 2 * m, sizeof(e[0]), EdgeCmp);
	for (i = 1; i < 2 * m; ++i)
		if (e[i].u == e[i + 1].u)
			if (!EdgeFind(e[i].v, e[i + 1].v)) break;
	puts(i == 2 * m ? "YES" : "NO");
	return 0;
}


#include <stdio.h>
#include <stdlib.h>

typedef struct TYPEEDGE {
	int u, v;
} typEdge;

void Swap(int *a, int *b) {
	int t;
	t = *a;
	*a = *b;
	*b = t;
}

int EdgeCmp(const void *a, const void *b) {
	if (((typEdge*)a)->u < ((typEdge *)b)->u) return -1;
	if (((typEdge*)a)->u > ((typEdge *)b)->u) return 1;
	if (((typEdge*)a)->v < ((typEdge *)b)->v) return -1;
	if (((typEdge*)a)->v > ((typEdge *)b)->v) return 1;
	return 0;
}

int eCnt, eLast[100005], ePrev[300005], eTar[300005];
void AddEdge(int u, int v) {
	ePrev[++eCnt] = eLast[u];
	eTar[eCnt] = v;
	eLast[u] = eCnt;
}

int m;
typEdge e[150005];
int EdgeFind(int u, int v) {
	typEdge eTmp;
	int l, r;
	if (u > v) Swap(&u, &v);
	eTmp.u = u;
	eTmp.v = v;
	for (l = 1, r = m; l <= r; )
		if (EdgeCmp(&eTmp, &e[(l + r) / 2]) <= 0)
			r = (l + r) / 2 - 1;
		else
			l = (l + r) / 2 + 1;
	return !EdgeCmp(&eTmp, &e[r + 1]);
}

int main(int argc, char *argv[]) {
	int n, i, j;
	scanf("%d%d", &n, &m);
	for (i = 1; i <= m; ++i) {
		scanf("%d%d", &e[i].u, &e[i].v);
		if (e[i].u > e[i].v) Swap(&e[i].u, &e[i].v);
		AddEdge(e[i].u, e[i].v);
		AddEdge(e[i].v, e[i].u);
	}
	qsort(e + 1, m, sizeof(e[0]), EdgeCmp);
	for (i = 1; i <= n; ++i) {
		if (!eLast[i]) continue;
		for (j = eLast[i]; ePrev[j]; j = ePrev[j])
			if (!EdgeFind(eTar[j], eTar[ePrev[j]])) break;
		if (ePrev[j]) break;
	}
	puts(i > n ? "YES" : "NO");
	return 0;
}


#include <stdio.h>
#include <stdlib.h>

typedef struct TYPEEDGE {
	int u, v;
} typEdge;

void Swap(int *a, int *b) {
	int t;
	t = *a;
	*a = *b;
	*b = t;
}

int EdgeCmp(const void *a, const void *b) {
	if (((typEdge*)a)->u < ((typEdge *)b)->u) return -1;
	if (((typEdge*)a)->u > ((typEdge *)b)->u) return 1;
	if (((typEdge*)a)->v < ((typEdge *)b)->v) return -1;
	if (((typEdge*)a)->v > ((typEdge *)b)->v) return 1;
	return 0;
}

int m;
typEdge e[300005];
int EdgeFind(int u, int v) {
	typEdge eTmp;
	int l, r;
	eTmp.u = u;
	eTmp.v = v;
	for (l = 1, r = 2 * m; l <= r; )
		if (EdgeCmp(&eTmp, &e[(l + r) / 2]) <= 0)
			r = (l + r) / 2 - 1;
		else
			l = (l + r) / 2 + 1;
	return !EdgeCmp(&eTmp, &e[r + 1]);
}

int main(int argc, char *argv[]) {
	int n, i, j;
	scanf("%d%d", &n, &m);
	for (i = 1; i <= m; ++i) {
		scanf("%d%d", &e[i].u, &e[i].v);
		e[m + i].u = e[i].v;
		e[m + i].v = e[i].u;
	}
	qsort(e + 1, 2 * m, sizeof(e[0]), EdgeCmp);
	for (i = 1; i < 2 * m; ++i)
		if (e[i].u == e[i + 1].u)
			if (!EdgeFind(e[i].v, e[i + 1].v)) break;
	puts(i == 2 * m ? "YES" : "NO");
	return 0;
}


#include <stdio.h>

int usPar[150005];
int usFind(int x) {
	if (usPar[x] == x) return x;
	return usPar[x] = usFind(usPar[x]);
}

int deg[150005], usCnt[150005];
int main(int argc, char *argv[]) {
	int n, m, i, u, v, parU, parV;
	scanf("%d%d", &n, &m);
	for (i = 1; i <= n; ++i) usPar[i] = i;
	for (i = 1; i <= m; ++i) {
		scanf("%d%d", &u, &v);
		++deg[u];
		++deg[v];
		if ((parU = usFind(u)) != (parV = usFind(v)))
			usPar[parV] = parU;
	}
	for (i = 1; i <= n; ++i) ++usCnt[usFind(i)];
	for (i = 1; i <= n; ++i)
		if (deg[i] != usCnt[usFind(i)] - 1) break;
	puts(i > n ? "YES" : "NO");
	return 0;
}


import java.io.*;
import java.util.StringTokenizer;
public class Main{
    public static void main(String[] args)throws IOException {
        FastReader sc=new FastReader();
        OutputStream output=System.out;
        PrintWriter out=new PrintWriter(output);
        //InputStream input = System.in;
        //Scanner sc = new Scanner(input);
        int n=sc.nextInt();
        int m=sc.nextInt();
        int[] arr=new int[n+1];
        arr[0]=0;
        for(int i=0;i<2*m;i++) {
            int a=sc.nextInt();
            arr[a]++;
        }
        long add=0;
        long count=0;
        for(int i=0;i<n+1;i++) {
            if(arr[i]==2)
                add++;
            if(arr[i]==1)
                count++;
        }
        if(add==m||count==2*m)
            out.println("YES");
        else
            out.println("NO");
        out.close();
    }

    static class FastReader
    {
        BufferedReader br;
        StringTokenizer st;

        public FastReader()
        {
            br = new BufferedReader(new
                    InputStreamReader(System.in));
        }

        String next()
        {
            while (st == null || !st.hasMoreElements())
            {
                try
                {
                    st = new StringTokenizer(br.readLine());
                }
                catch (IOException  e)
                {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        int nextInt()
        {
            return Integer.parseInt(next());
        }

        long nextLong()
        {
            return Long.parseLong(next());
        }

        double nextDouble()
        {
            return Double.parseDouble(next());
        }

        String nextLine()
        {
            String str = "";
            try
            {
                str = br.readLine();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
            return str;
        }
    }
}


//package com.company;

import java.io.*;
import java.util.*;

public class Main{
    int v;long vertix,edge;
    LinkedList<Integer> adj[];
    Main(int V) {
        v=V;
        adj=new LinkedList[V];
        for(int i=0;i<V;i++)
            adj[i]=new LinkedList<>();
    }

    void addEdge(int x, int y) {
        adj[x].add(y);
    }

    void dfs(int s,boolean[] visited) {
        if (!visited[s]) {
            visited[s]=true;
            vertix++;
            edge+=adj[s].size();
            Iterator<Integer> itr=adj[s].listIterator();
            while (itr.hasNext()) {
                int n=itr.next();
                if(!visited[n])
                    dfs(n,visited);
            }
        }
    }
    public static void main(String[] args)throws IOException {
        FastReader sc = new FastReader();
        OutputStream output = System.out;
        PrintWriter out = new PrintWriter(output);
        //InputStream input = System.in;
        //Scanner sc = new Scanner(input);
        int n=sc.nextInt();
        int m=sc.nextInt();
        boolean[] visited=new boolean[n+1];
        Main g=new Main(n+1);
        for(int i=0;i<m;i++) {
            int x=sc.nextInt();
            int y=sc.nextInt();
            g.addEdge(x,y);
            g.addEdge(y,x);
        }
        for(int i=1;i<=n;i++) {
            if (!visited[i]) {
                g.vertix=0;
                g.edge=0;
                g.dfs(i,visited);
                //out.println(g.vertix+" "+g.edge);
                if (g.edge/2 != (g.vertix * (g.vertix - 1)) / 2) {
                    out.println("NO");
                    out.close();
                    return;
                }
            }
        }
        out.println("YES");
        out.close();
    }
    /*public static class Indexing{
        int row, column;
        Indexing(int a, int b){
            row = a;
            column = b;
        }
    }*/
    static class FastReader
    {
        BufferedReader br;
        StringTokenizer st;

        public FastReader()
        {
            br = new BufferedReader(new
                    InputStreamReader(System.in));
        }

        String next()
        {
            while (st == null || !st.hasMoreElements())
            {
                try
                {
                    st = new StringTokenizer(br.readLine());
                }
                catch (IOException  e)
                {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        int nextInt()
        {
            return Integer.parseInt(next());
        }

        long nextLong()
        {
            return Long.parseLong(next());
        }

        double nextDouble()
        {
            return Double.parseDouble(next());
        }

        String nextLine()
        {
            String str = "";
            try
            {
                str = br.readLine();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
            return str;
        }
    }
}


//package com.company;

import java.io.*;
import java.util.*;

public class Main{
    int v;int vertix,edge;
    LinkedList<Integer> adj[];
    Main(int V) {
        v=V;
        adj=new LinkedList[V];
        for(int i=0;i<V;i++)
            adj[i]=new LinkedList<>();
    }

    void addEdge(int x, int y) {
        adj[x].add(y);
    }

    void dfs(int s,boolean[] visited) {
        if (!visited[s]) {
            visited[s]=true;
            vertix++;
            edge+=adj[s].size();
            Iterator<Integer> itr=adj[s].listIterator();
            while (itr.hasNext()) {
                int n=itr.next();
                if(!visited[n])
                    dfs(n,visited);
            }
        }
    }
    public static void main(String[] args)throws IOException {
        FastReader sc = new FastReader();
        OutputStream output = System.out;
        PrintWriter out = new PrintWriter(output);
        //InputStream input = System.in;
        //Scanner sc = new Scanner(input);
        int n=sc.nextInt();
        int m=sc.nextInt();
        boolean[] visited=new boolean[n+1];
        Main g=new Main(n+1);
        for(int i=0;i<m;i++) {
            int x=sc.nextInt();
            int y=sc.nextInt();
            g.addEdge(x,y);
            g.addEdge(y,x);
        }
        for(int i=1;i<=n;i++) {
            if (!visited[i]) {
                g.vertix=0;
                g.edge=0;
                g.dfs(i,visited);
                //out.println(g.vertix+" "+g.edge);
                if (g.edge/2 != (g.vertix * (g.vertix - 1)) / 2) {
                    out.println("NO");
                    out.close();
                    return;
                }
            }
        }
        out.println("YES");
        out.close();
    }
    /*public static class Indexing{
        int row, column;
        Indexing(int a, int b){
            row = a;
            column = b;
        }
    }*/
    static class FastReader
    {
        BufferedReader br;
        StringTokenizer st;

        public FastReader()
        {
            br = new BufferedReader(new
                    InputStreamReader(System.in));
        }

        String next()
        {
            while (st == null || !st.hasMoreElements())
            {
                try
                {
                    st = new StringTokenizer(br.readLine());
                }
                catch (IOException  e)
                {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        int nextInt()
        {
            return Integer.parseInt(next());
        }

        long nextLong()
        {
            return Long.parseLong(next());
        }

        double nextDouble()
        {
            return Double.parseDouble(next());
        }

        String nextLine()
        {
            String str = "";
            try
            {
                str = br.readLine();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
            return str;
        }
    }
}


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.util.HashSet;
import java.util.Scanner;

/**
 * Created by drproduck on 3/18/17.
 */
public class B  {
    public static void main(String[] args){
        Scanner in = new Scanner(new BufferedReader(new InputStreamReader(System.in)));
        int n = in.nextInt();
        int m = in.nextInt();

        HashSet<Integer>[] a = new HashSet[n];
        for (int i = 0; i < n; i++) {
            a[i] = new HashSet<Integer>();
        }
        for (int i = 0; i < m; i++) {
            int x = in.nextInt()-1;
            int y = in.nextInt()-1;
            a[x].add(y);
            a[y].add(x);
        }
        SizedDisjointSets ds = new SizedDisjointSets(n);
        for (int i = 0; i < n; i++) {
            HashSet<Integer> s = a[i];
            for (Integer x:
                 s) {
                ds.union(i, x);
            }
        }

        boolean res = true;
        for (int i = 0; i < n; i++) {
            if (a[i].size() != ds.size(i)-1) {
                res = false;
                break;
            }
        }
        if (res) System.out.println("YES");
        else System.out.println("NO");
    }
}

abstract class DisjointSets {

    public int[] getParents() {
        return parents;
    }

    public int getNumElements() {
        return numElements;
    }

    protected int[] parents;
    protected int numElements;

    public DisjointSets(int numElements) {
        this.numElements = numElements;
        parents = new int[numElements];
    }

    abstract void union(int x, int y);

    abstract int find(int x);
}

class SizedDisjointSets extends DisjointSets {
    public SizedDisjointSets(int numElements) {
        super(numElements);
        for (int i = 0; i < numElements; i++) {
            parents[i]  = -1;
        }
    }
    public void union(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) ;
        else if (parents[y] < parents[x]) {
            parents[y] = parents[y] + parents[x];
            parents[x] = y;

        } else {
            parents[x] = parents[x] + parents[y];
            parents[y] = x;

        }
    }

    public int find( int x){
        if (parents[x] < 0) {
            return x;
        }
        return find(parents[x]);
    }

    public int size(int x) {
        return -1 * parents[find(x)];
    }
}


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.util.HashSet;
import java.util.Scanner;

/**
 * Created by drproduck on 3/18/17.
 */
public class B  {
    public static void main(String[] args){
        Scanner in = new Scanner(new BufferedReader(new InputStreamReader(System.in)));
        int n = in.nextInt();
        int m = in.nextInt();

        HashSet<Integer>[] a = new HashSet[n];
        for (int i = 0; i < n; i++) {
            a[i] = new HashSet<Integer>();
        }
        for (int i = 0; i < m; i++) {
            int x = in.nextInt()-1;
            int y = in.nextInt()-1;
            a[x].add(y);
            a[y].add(x);
        }
        RankedDisjointSets ds = new RankedDisjointSets(n);
        for (int i = 0; i < n; i++) {
            HashSet<Integer> s = a[i];
            for (Integer x:
                 s) {
                ds.union(i, x);
            }
        }

        boolean res = true;
        for (int i = 0; i < n; i++) {
            if (a[i].size() != ds.size(i)-1) {
                res = false;
                break;
            }
        }
        if (res) System.out.println("YES");
        else System.out.println("NO");
    }
}

abstract class DisjointSets {

    public int[] getParents() {
        return parents;
    }

    public int getNumElements() {
        return numElements;
    }

    protected int[] parents;
    protected int numElements;

    public DisjointSets(int numElements) {
        this.numElements = numElements;
        parents = new int[numElements];
    }

    abstract void union(int x, int y);

    abstract int find(int x);
}

class RankedDisjointSets extends DisjointSets {
    int[] size;
    public RankedDisjointSets(int numElements) {
        super(numElements);
        for (int i = 0; i < numElements; i++) {
            parents[i] = -1;
        }
        size = new int[numElements];
        for (int i = 0; i < numElements; i++) {
            size[i] = 1;
        }
    }

    /**
     * union-by-rank: each node initially has rank 1.Each time 2 trees are concatenated,
     * the root of the tree with smaller rank will be linked to the root of the bigger one
     * rank is not necessarily height as path compression with alter heights online
     */
    public void union(int x, int y) {
        x = find(x);
        y = find(y);
        if (x==y);
        else if (parents[y] < parents[x]) {
            parents[x] = y;
            size[y] += size[x];
        } else {
            if (parents[x] == parents[y]) {
                parents[x]--;
            }
            parents[y] = x;
            size[x] += size[y];
        }

    }

    /**
     * path-compression: Each time 2 trees are joined, the nodes that are traversed in the smaller tree
     * will be linked to the root of the larger tree. This makes the tree less deep, allowing faster
     * access in next find. It has been shown that the amortized find is practically below 5 (though unbounded)
     * @param x
     * @return
     */
    public int find(int x) {
        if (parents[x] < 0) {
            return x;
        } else {
            return parents[x] = find(parents[x]);
        }

    }

    public int size(int x) {
        return size[find(x)];
    }
}


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.util.HashSet;
import java.util.Scanner;

/**
 * Created by drproduck on 3/18/17.
 */
public class B  {
    public static void main(String[] args){
        Scanner in = new Scanner(new BufferedReader(new InputStreamReader(System.in)));
        int n = in.nextInt();
        int m = in.nextInt();

        HashSet<Integer>[] a = new HashSet[n];
        for (int i = 0; i < n; i++) {
            a[i] = new HashSet<Integer>();
        }
        for (int i = 0; i < m; i++) {
            int x = in.nextInt()-1;
            int y = in.nextInt()-1;
            a[x].add(y);
            a[y].add(x);
        }
        boolean[] vis = new boolean[n];
        boolean res = true;
        for (int i = 0; i < n; i++) {
            if (!vis[i]) {
                HashSet<Integer> s = a[i];
                vis[i] = true;
                for (Integer x :
                        s) {
                    if (!vis[x]) {
                        HashSet<Integer> t = a[x];
                        vis[x] = true;
                        if (s.size() != t.size()) res = false;
                        else {
                            for (Integer y :
                                    t) {
                                if (i!=y&&!s.contains(y)) {
                                    res = false;
                                    break;
                                }
                            }
                        }
                    }
                    if (!res) break;
                }
            }
            if (!res) break;
        }
        if (res) System.out.println("YES");
        else System.out.println("NO");
    }
}


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.util.HashSet;
import java.util.Scanner;

/**
 * Created by drproduck on 3/18/17.
 */
public class B  {
    public static void main(String[] args){
        Scanner in = new Scanner(new BufferedReader(new InputStreamReader(System.in)));
        int n = in.nextInt();
        int m = in.nextInt();

        int[] deg = new int[n];
        RankedDisjointSets ds = new RankedDisjointSets(n);
        for (int i = 0; i < m; i++) {
            int x = in.nextInt()-1;
            int y = in.nextInt()-1;
            ds.union(x, y);
            deg[x] ++;
            deg[y] ++;
        }
        boolean res = true;
        for (int i = 0; i < n; i++) {
            if (deg[i] != ds.size(i)-1) {
                res = false;
                break;
            }
        }
        if (res) System.out.println("YES");
        else System.out.println("NO");
    }
}

abstract class DisjointSets {

    public int[] getParents() {
        return parents;
    }

    public int getNumElements() {
        return numElements;
    }

    protected int[] parents;
    protected int numElements;

    public DisjointSets(int numElements) {
        this.numElements = numElements;
        parents = new int[numElements];
    }

    abstract void union(int x, int y);

    abstract int find(int x);

    abstract int size(int x);
}

class RankedDisjointSets extends DisjointSets {
    private int[] size;

    public RankedDisjointSets(int numElements) {
        super(numElements);
        for (int i = 0; i < numElements; i++) {
            parents[i] = -1;
        }
        size = new int[numElements];
        for (int i = 0; i < numElements; i++) {
            size[i] = 1;
        }
    }

    /**
     * union-by-rank: each node initially has rank 1.Each time 2 trees are concatenated,
     * the root of the tree with smaller rank will be linked to the root of the bigger one
     * rank is not necessarily height as path compression with alter heights online
     */
    public void union(int x, int y) {
        x = find(x);
        y = find(y);
        if (x != y) {
            if (parents[y] < parents[x]) {
                parents[x] = y;
                size[y] += size[x];
            } else {
                if (parents[x] == parents[y]) {
                    parents[x]--;
                }
                parents[y] = x;
                size[x] += size[y];
            }
        }
    }

    /**
     * path-compression: Each time 2 trees are joined, the nodes that are traversed in the smaller tree
     * will be linked to the root of the larger tree. This makes the tree less deep, allowing faster
     * access in next find. It has been shown that the amortized find is practically below 5 (though unbounded)
     *
     * @param x
     * @return
     */
    public int find(int x) {
        if (parents[x] < 0) {
            return x;
        } else {
            return parents[x] = find(parents[x]);
        }

    }

    public int size(int x) {
        return size[find(x)];
    }
}


//Codeforces Round 405 (Div. 2)
import java.io.*;
import java.util.*;

public class TaskB {

	public static void main(String[] args) throws IOException {
		FastScanner fs = new FastScanner(System.in);
		PrintWriter pw = new PrintWriter(new BufferedOutputStream(System.out));

		int n = fs.nextInt();
		int m = fs.nextInt();

		int[] d = new int[n];
		for (int i = 0; i < n; i++) {
			d[i] = -1;
		}

		long[] p = new long[n];

		for (int i = 0; i < m; i++) {
			int a = fs.nextInt()-1;
			int b = fs.nextInt()-1;
			int da = d[a];
			while (da >= 0) {
				int dda = d[da];
				if (dda >= 0) d[a] = dda;
				a = da;
				da = dda;
			}
			int db = d[b];
			while (db >= 0) {
				int ddb = d[db];
				if (ddb >= 0) d[b] = ddb;
				b = db;
				db = ddb;
			}
			if (a != b) {
				if (da > db) {
					int c = a;
					a = b;
					b = c;
				}
				d[a] += d[b];
				d[b] = a;
				p[a] += p[b];
			}
			p[a]++;
		}

		boolean ok = true;
		for (int i = 0; i < n; i++) {
			if (d[i] < 0) {
				long q = -d[i];
				q = (q*(q-1)) >> 1;
				if (q != p[i]) {
					ok = false;
					break;
				}
			}
		}

		pw.println(ok?"YES":"NO");

		pw.close();
	}

	static class FastScanner {
		BufferedReader reader;
		StringTokenizer tokenizer;
		FastScanner(InputStream i) {
			reader = new BufferedReader(new InputStreamReader(i));
			tokenizer = new StringTokenizer("");
		}
		String next() throws IOException {
			while(!tokenizer.hasMoreTokens()) tokenizer = new StringTokenizer(reader.readLine());
			return tokenizer.nextToken();
		}
		int nextInt() throws IOException {
			return Integer.parseInt(next());
		}
	}
}


//Codeforces Round 405 (Div. 2)
import java.io.*;
import java.util.*;

public class TaskB {

	public static void main(String[] args) throws IOException {
		FastScanner fs = new FastScanner(System.in);
		PrintWriter pw = new PrintWriter(new BufferedOutputStream(System.out));

		int n = fs.nextInt();
		int m = fs.nextInt();

		int[] d = new int[n];
		for (int i = 0; i < n; i++) {
			d[i] = -1;
		}

		long[] p = new long[n];

		for (int i = 0; i < m; i++) {
			int a = fs.nextInt()-1;
			int b = fs.nextInt()-1;
			int da = d[a];
			while (da >= 0) {
				int dda = d[da];
				if (dda >= 0) d[a] = dda;
				a = da;
				da = dda;
			}
			int db = d[b];
			while (db >= 0) {
				int ddb = d[db];
				if (ddb >= 0) d[b] = ddb;
				b = db;
				db = ddb;
			}
			if (a != b) {
				if (da > db) {
					int c = a;
					a = b;
					b = c;
				}
				d[a] += db;
				d[b] = a;
				p[a] += p[b];
			}
			p[a]++;
		}

		boolean ok = true;
		for (int i = 0; i < m; i++) {
			if (d[i] < 0) {
				long q = -d[i];
				q = (q*(q-1)) >> 1;
				if (q != p[i]) {
					ok = false;
					break;
				}
			}
		}

		pw.println(ok?"YES":"NO");

		pw.close();
	}

	static class FastScanner {
		BufferedReader reader;
		StringTokenizer tokenizer;
		FastScanner(InputStream i) {
			reader = new BufferedReader(new InputStreamReader(i));
			tokenizer = new StringTokenizer("");
		}
		String next() throws IOException {
			while(!tokenizer.hasMoreTokens()) tokenizer = new StringTokenizer(reader.readLine());
			return tokenizer.nextToken();
		}
		int nextInt() throws IOException {
			return Integer.parseInt(next());
		}
	}
}


//Codeforces Round 405 (Div. 2)
import java.io.*;
import java.util.*;

public class TaskB {

	public static void main(String[] args) throws IOException {
		FastScanner fs = new FastScanner(System.in);
		PrintWriter pw = new PrintWriter(new BufferedOutputStream(System.out));

		int n = fs.nextInt();
		int m = fs.nextInt();

		int[] d = new int[n];
		for (int i = 0; i < n; i++) {
			d[i] = -1;
		}

		long[] p = new long[n];

		for (int i = 0; i < m; i++) {
			int a = fs.nextInt()-1;
			int b = fs.nextInt()-1;
			int da = d[a];
			while (da >= 0) {
				int dda = d[da];
				if (dda >= 0) d[a] = dda;
				a = da;
				da = dda;
			}
			int db = d[b];
			while (db >= 0) {
				int ddb = d[db];
				if (ddb >= 0) d[b] = ddb;
				b = db;
				db = ddb;
			}
			if (a != b) {
				if (da > db) {
					int c = a;
					a = b;
					b = c;
				}
				d[a] += db;
				d[b] = a;
				p[a] += p[b];
			}
			p[a]++;
		}

		boolean ok = true;
		for (int i = 0; i < n; i++) {
			if (d[i] < 0) {
				long q = -d[i];
				q = (q*(q-1)) >> 1;
				if (q != p[i]) {
					ok = false;
					break;
				}
			}
		}

		pw.println(ok?"YES":"NO");

		pw.close();
	}

	static class FastScanner {
		BufferedReader reader;
		StringTokenizer tokenizer;
		FastScanner(InputStream i) {
			reader = new BufferedReader(new InputStreamReader(i));
			tokenizer = new StringTokenizer("");
		}
		String next() throws IOException {
			while(!tokenizer.hasMoreTokens()) tokenizer = new StringTokenizer(reader.readLine());
			return tokenizer.nextToken();
		}
		int nextInt() throws IOException {
			return Integer.parseInt(next());
		}
	}
}


import java.io.PrintWriter;
import java.util.Scanner;

public class B {

	public B() {
		Scanner sc = new Scanner(System.in);
		PrintWriter out = new PrintWriter(System.out);
		int n = sc.nextInt();
		int m = sc.nextInt();
		boolean[][] adj = new boolean[n + 1][n + 1];
		for (int i = 0; i < m; i++) {
			int a = sc.nextInt();
			int b = sc.nextInt();
			adj[a][b] = true;
			adj[b][a] = true;
		}
		for (int x = 1; x <= n; x++) {
			for (int y = 1; y <= n; y++) {
				if (!adj[x][y] || x == y)
					continue;
				for (int z = 1; z <= n; z++) {
					if (!adj[y][z] || x == z || y == z)
						continue;
					if (!adj[x][z]) {
						out.println("NO");
						out.close();
						System.exit(0);
					}
				}
			}
		}
		out.println("YES");
		sc.close();
		out.close();
	}

	public static void main(String[] args) {
		new B();
	}
}


import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Scanner;

public class B {
	ArrayList<Integer>[] adj;
	boolean[] vis;
	int n, m;
	long vert, edg;

	public B() {
		Scanner sc = new Scanner(System.in);
		PrintWriter out = new PrintWriter(System.out);
		n = sc.nextInt();
		m = sc.nextInt();
		vis = new boolean[n + 1];
		adj = new ArrayList[n + 1];
		for (int i = 1; i <= n; i++)
			adj[i] = new ArrayList<Integer>();
		for (int i = 0; i < m; i++) {
			int a = sc.nextInt();
			int b = sc.nextInt();
			adj[a].add(b);
			adj[b].add(a);
		}
		for (int x = 1; x <= n; x++) {
			if (vis[x])
				continue;
			dfs(x);
			if (edg != vert * (vert - 1)) {
				out.println("NO");
				out.close();
				System.exit(0);
			}
			vert = 0;
			edg = 0;
		}
		out.println("YES");
		sc.close();
		out.close();
	}

	private void dfs(int x) {
		if (vis[x])
			return;
		vert++;
		vis[x] = true;
		edg += adj[x].size();
		for (int y : adj[x])
			dfs(y);
	}

	public static void main(String[] args) {
		new B();
	}
}


import java.io.PrintWriter;
import java.util.Scanner;

public class B {

	public B() {
		Scanner sc = new Scanner(System.in);
		PrintWriter out = new PrintWriter(System.out);
		int n = sc.nextInt();
		int m = sc.nextInt();
		boolean[][] adj = new boolean[n + 1][n + 1];
		for (int i = 0; i < m; i++) {
			int a = sc.nextInt();
			int b = sc.nextInt();
			adj[a][b] = true;
			adj[b][a] = true;
		}
		for (int x = 1; x <= n; x++) {
			for (int y = x + 1; y <= n; y++) {
				if (!adj[x][y])
					continue;
				for (int z = y + 1; z <= n; z++) {
					if (!adj[y][z])
						continue;
					if (!adj[x][z]) {
						out.println("NO");
						out.close();
						System.exit(0);
					}
				}
			}
		}
		out.println("YES");
		sc.close();
		out.close();
	}

	public static void main(String[] args) {
		new B();
	}
}


import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Scanner;

public class B {

	public B() {
		Scanner sc = new Scanner(System.in);
		PrintWriter out = new PrintWriter(System.out);
		int n = sc.nextInt();
		int m = sc.nextInt();
		ArrayList<Integer>[] adj = new ArrayList[n + 1];
		for (int i = 1; i <= n; i++)
			adj[i] = new ArrayList<Integer>();
		for (int i = 0; i < m; i++) {
			int a = sc.nextInt();
			int b = sc.nextInt();
			adj[a].add(b);
			adj[b].add(a);
		}
		for (int x = 1; x <= n; x++) {
//			if (adj[x].size() % 2 == 0)
//				continue;
			int s = adj[x].size();
			for (int y: adj[x]) {
				if (adj[y].size() != s) {
					out.println("NO");
					out.close();
					System.exit(0);
				}
			}
		}
		out.println("YES");
		sc.close();
		out.close();
	}

	public static void main(String[] args) {
		new B();
	}
}


import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Scanner;

public class B {

	public B() {
		Scanner sc = new Scanner(System.in);
		PrintWriter out = new PrintWriter(System.out);
		int n = sc.nextInt();
		int m = sc.nextInt();
		ArrayList<Integer>[] adj = new ArrayList[n + 1];
		for (int i = 1; i <= n; i++)
			adj[i] = new ArrayList<Integer>();
		for (int i = 0; i < m; i++) {
			int a = sc.nextInt();
			int b = sc.nextInt();
			adj[a].add(b);
			adj[b].add(a);
		}
		for (int x = 1; x <= n; x++) {
			for (int y : adj[x]) {
				if (x == y)
					continue;
				boolean[] vis = new boolean[n + 1];
				for (int z : adj[x])
					vis[z] = true;
				for (int z : adj[y]) {
					if (x == z || y == z)
						continue;
					if (vis[z])
						continue;
					out.println("NO");
					out.close();
					System.exit(0);
				}
			}
		}
		out.println("YES");
		sc.close();
		out.close();
	}

	public static void main(String[] args) {
		new B();
	}
}


import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Scanner;

public class B {
	ArrayList<Integer>[] adj;
	boolean[] vis;
	Edge[] e;
	int n, m, vert, edg;

	public B() {
		Scanner sc = new Scanner(System.in);
		PrintWriter out = new PrintWriter(System.out);
		n = sc.nextInt();
		m = sc.nextInt();
		vis = new boolean[n + 1];
		e = new Edge[m];
		adj = new ArrayList[n + 1];
		for (int i = 1; i <= n; i++)
			adj[i] = new ArrayList<Integer>();
		for (int i = 0; i < m; i++) {
			int a = sc.nextInt();
			int b = sc.nextInt();
			e[i] = new Edge(a, b);
			adj[a].add(b);
			adj[b].add(a);
		}
		for (int x = 1; x <= n; x++) {
			if (vis[x])
				continue;
			dfs(x);
			if (edg != (vert * (vert - 1)) / 2) {
				out.println("NO");
				out.close();
				System.exit(0);
			}
			vert = 0;
			edg = 0;
		}
		out.println("YES");
		sc.close();
		out.close();
	}

	private void dfs(int x) {
		if (vis[x])
			return;
		vert++;
		vis[x] = true;
		for (int y : adj[x]) {
			for (int i = 0; i < m; i++) {
				if (e[i].vis)
					continue;
				if ((e[i].from == x && e[i].to == y)
						|| (e[i].to == x && e[i].from == y)) {
					edg++;
					e[i].vis = true;
					break;
				}
			}
			dfs(y);
		}
	}

	public static void main(String[] args) {
		new B();
	}

	class Edge {
		int from, to;
		boolean vis;

		public Edge(int from, int to) {
			this.from = from;
			this.to = to;
		}
	}
}


import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Scanner;

public class B {

	public B() {
		Scanner sc = new Scanner(System.in);
		PrintWriter out = new PrintWriter(System.out);
		int n = sc.nextInt();
		int m = sc.nextInt();
		ArrayList<Integer>[] adj = new ArrayList[n + 1];
		for (int i = 1; i <= n; i++)
			adj[i] = new ArrayList<Integer>();
		for (int i = 0; i < m; i++) {
			int a = sc.nextInt();
			int b = sc.nextInt();
			adj[a].add(b);
			adj[b].add(a);
		}
		for (int x = 1; x <= n; x++) {
			for (int y : adj[x]) {
				if (x == y)
					continue;
				for (int z : adj[y]) {
					if (x == z || y == z)
						continue;
					if (adj[x].contains(z))
						continue;
					out.println("NO");
					out.close();
					System.exit(0);
				}
			}
		}
		out.println("YES");
		sc.close();
		out.close();
	}

	public static void main(String[] args) {
		new B();
	}
}


import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Scanner;

public class B {
	ArrayList<Integer>[] adj;
	boolean[] vis;
	int n, m;
	long vert, edg;

	public B() {
		Scanner sc = new Scanner(System.in);
		PrintWriter out = new PrintWriter(System.out);
		n = sc.nextInt();
		m = sc.nextInt();
		vis = new boolean[n + 1];
		adj = new ArrayList[n + 1];
		for (int i = 0; i < m; i++) {
			int a = sc.nextInt();
			int b = sc.nextInt();
			if (adj[a] == null)
				adj[a] = new ArrayList<Integer>();
			if (adj[b] == null)
				adj[b] = new ArrayList<Integer>();
			adj[a].add(b);
			adj[b].add(a);
		}
		for (int x = 1; x <= n; x++) {
			if (vis[x] || adj[x] == null)
				continue;
			dfs(x);
			if (edg != vert * (vert - 1)) {
				out.println("NO");
				out.close();
				System.exit(0);
			}
			vert = 0;
			edg = 0;
		}
		out.println("YES");
		sc.close();
		out.close();
	}

	private void dfs(int x) {
		if (vis[x])
			return;
		vert++;
		vis[x] = true;
		edg += adj[x].size();
		for (int y : adj[x])
			if (!vis[y])
				dfs(y);
	}

	public static void main(String[] args) {
		new B();
	}
}


import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Scanner;

public class B {

	public B() {
		Scanner sc = new Scanner(System.in);
		PrintWriter out = new PrintWriter(System.out);
		int n = sc.nextInt();
		int m = sc.nextInt();
		ArrayList<Integer>[] adj = new ArrayList[n + 1];
		for (int i = 1; i <= n; i++)
			adj[i] = new ArrayList<Integer>();
		for (int i = 0; i < m; i++) {
			int a = sc.nextInt();
			int b = sc.nextInt();
			adj[a].add(b);
			adj[b].add(a);
		}
		for (int x = 1; x <= n; x++) {
			if (adj[x].size() % 2 == 0)
				continue;
			if (adj[x].size() == 1) {
				if (adj[adj[x].get(0)].size() == 1)
					continue;
				else {
					out.println("NO");
					out.close();
					System.exit(0);
				}
			}
			out.println("NO");
			out.close();
			System.exit(0);
		}
		out.println("YES");
		sc.close();
		out.close();
	}

	public static void main(String[] args) {
		new B();
	}
}


import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Scanner;

public class B {

	public B() {
		Scanner sc = new Scanner(System.in);
		PrintWriter out = new PrintWriter(System.out);
		int n = sc.nextInt();
		int m = sc.nextInt();
		ArrayList<Integer>[] adj = new ArrayList[n + 1];
		for (int i = 1; i <= n; i++)
			adj[i] = new ArrayList<Integer>();
		for (int i = 0; i < m; i++) {
			int a = sc.nextInt();
			int b = sc.nextInt();
			adj[a].add(b);
			adj[b].add(a);
		}
		for (int x = 1; x <= n; x++) {
			boolean[] vis = new boolean[n + 1];
			for (int z : adj[x])
				vis[z] = true;
			for (int y : adj[x]) {
				if (x == y)
					continue;
				for (int z : adj[y]) {
					if (x == z || y == z)
						continue;
					if (vis[z])
						continue;
					out.println("NO");
					out.close();
					System.exit(0);
				}
			}
		}
		out.println("YES");
		sc.close();
		out.close();
	}

	public static void main(String[] args) {
		new B();
	}
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.HashSet;
import java.util.StringTokenizer;

public class B {

	public static void main(String[] args) throws IOException {
		FastScanner scan = new FastScanner();
		PrintWriter out = new PrintWriter(System.out);
		int n = scan.nextInt(), m = scan.nextInt();
		int[] f = new int[n];
		HashSet<Integer>[] adj = new HashSet[n];
		for(int i = 0; i < n; i++) adj[i] = new HashSet<Integer>();
		for(int i = 0; i < n; i++) f[i] = i;
		for(int i = 0; i < m; i++){
			int x = scan.nextInt()-1, y = scan.nextInt()-1;
			adj[y].add(x);
			adj[x].add(y);
		}
		boolean good = true;
		boolean[] v = new boolean[n];
		for(int i = 0; i < n; i++){
			if(!v[i]){
				ArrayDeque<Integer> q = new ArrayDeque<>();
				q.add(i);
				v[i] = true;
				int nodes = 0, edges = 0;
				while(!q.isEmpty()){
					int at = q.poll();
					nodes++;
					for(int j : adj[at]) if(!v[j]){
						edges++;
						v[j] = true;
						q.add(j);
					}
				}
				if(nodes*(nodes+1)/2 > edges) good = false;
			}
		}
		out.println(good?"YES":"NO");
		out.close();
	}

	static class FastScanner {
		BufferedReader br;
		StringTokenizer st;

		public FastScanner() {
			try	{
				br = new BufferedReader(new InputStreamReader(System.in));
				st = new StringTokenizer(br.readLine());
			} catch (Exception e){e.printStackTrace();}
		}

		public String next() {
			if (st.hasMoreTokens())	return st.nextToken();
			try {st = new StringTokenizer(br.readLine());}
			catch (Exception e) {e.printStackTrace();}
			return st.nextToken();
		}

		public int nextInt() {return Integer.parseInt(next());}

		public long nextLong() {return Long.parseLong(next());}

		public double nextDouble() {return Double.parseDouble(next());}

		public String nextLine() {
			String line = "";
			try {line = br.readLine();}
			catch (Exception e) {e.printStackTrace();}
			return line;
		}

		public int[] nextIntArray(int n) {
			int[] a = new int[n];
			for(int i = 0; i < n; i++) a[i] = nextInt();
			return a;
		}

		public long[] nextLongArray(int n){
			long[] a = new long[n];
			for(int i = 0; i < n; i++) a[i] = nextLong();
			return a;
		}

		public double[] nextDoubleArray(int n){
			double[] a = new double[n];
			for(int i = 0; i < n; i++) a[i] = nextDouble();
			return a;
		}

		public char[][] nextGrid(int n, int m){
			char[][] grid = new char[n][m];
			for(int i = 0; i < n; i++) grid[i] = next().toCharArray();
			return grid;
		}
	}

}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.HashSet;
import java.util.StringTokenizer;
import java.util.concurrent.SynchronousQueue;

public class B {

	public static void main(String[] args) throws IOException {
		FastScanner scan = new FastScanner();
		PrintWriter out = new PrintWriter(System.out);
		int n = scan.nextInt(), m = scan.nextInt();
		int[] f = new int[n];
		HashSet<Integer>[] adj = new HashSet[n];
		for(int i = 0; i < n; i++) adj[i] = new HashSet<Integer>();
		for(int i = 0; i < n; i++) f[i] = i;
		for(int i = 0; i < m; i++){
			int x = scan.nextInt()-1, y = scan.nextInt()-1;
			adj[y].add(x);
			adj[x].add(y);
		}
		boolean good = true;
		boolean[] v = new boolean[n];
		for(int i = 0; i < n; i++){
			if(!v[i]){
				ArrayDeque<Integer> q = new ArrayDeque<>();
				q.add(i);
				v[i] = true;
				int nodes = 0, edges = 0;
				while(!q.isEmpty()){
					int at = q.poll();
					nodes++;
					edges += adj[at].size();
					for(int j : adj[at]) if(!v[j]){
						v[j] = true;
						q.add(j);
					}
				}
				edges = edges/2+edges%2;
				if(nodes > 2 && nodes*(nodes+1)/2 > edges) good = false;
			}
		}
		out.println(good?"YES":"NO");
		out.close();
	}

	static class FastScanner {
		BufferedReader br;
		StringTokenizer st;

		public FastScanner() {
			try	{
				br = new BufferedReader(new InputStreamReader(System.in));
				st = new StringTokenizer(br.readLine());
			} catch (Exception e){e.printStackTrace();}
		}

		public String next() {
			if (st.hasMoreTokens())	return st.nextToken();
			try {st = new StringTokenizer(br.readLine());}
			catch (Exception e) {e.printStackTrace();}
			return st.nextToken();
		}

		public int nextInt() {return Integer.parseInt(next());}

		public long nextLong() {return Long.parseLong(next());}

		public double nextDouble() {return Double.parseDouble(next());}

		public String nextLine() {
			String line = "";
			try {line = br.readLine();}
			catch (Exception e) {e.printStackTrace();}
			return line;
		}

		public int[] nextIntArray(int n) {
			int[] a = new int[n];
			for(int i = 0; i < n; i++) a[i] = nextInt();
			return a;
		}

		public long[] nextLongArray(int n){
			long[] a = new long[n];
			for(int i = 0; i < n; i++) a[i] = nextLong();
			return a;
		}

		public double[] nextDoubleArray(int n){
			double[] a = new double[n];
			for(int i = 0; i < n; i++) a[i] = nextDouble();
			return a;
		}

		public char[][] nextGrid(int n, int m){
			char[][] grid = new char[n][m];
			for(int i = 0; i < n; i++) grid[i] = next().toCharArray();
			return grid;
		}
	}

}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.HashSet;
import java.util.StringTokenizer;
import java.util.concurrent.SynchronousQueue;

public class B {

	public static void main(String[] args) throws IOException {
		FastScanner scan = new FastScanner();
		PrintWriter out = new PrintWriter(System.out);
		int n = scan.nextInt(), m = scan.nextInt();
		int[] f = new int[n];
		HashSet<Integer>[] adj = new HashSet[n];
		for(int i = 0; i < n; i++) adj[i] = new HashSet<Integer>();
		for(int i = 0; i < n; i++) f[i] = i;
		for(int i = 0; i < m; i++){
			int x = scan.nextInt()-1, y = scan.nextInt()-1;
			adj[y].add(x);
			adj[x].add(y);
		}
		boolean good = true;
		boolean[] v = new boolean[n];
		for(int i = 0; i < n; i++){
			if(!v[i]){
				ArrayDeque<Integer> q = new ArrayDeque<>();
				q.add(i);
				v[i] = true;
				int nodes = 0, edges = 0;
				while(!q.isEmpty()){
					int at = q.poll();
					nodes++;
					edges += adj[at].size();
					for(int j : adj[at]) if(!v[j]){
						v[j] = true;
						q.add(j);
					}
				}
				edges = edges/2 + edges%2;
				if(nodes > 2 && nodes*(nodes-1)/2 > edges) good = false;
			}
		}
		out.println(good?"YES":"NO");
		out.close();
	}

	static class FastScanner {
		BufferedReader br;
		StringTokenizer st;

		public FastScanner() {
			try	{
				br = new BufferedReader(new InputStreamReader(System.in));
				st = new StringTokenizer(br.readLine());
			} catch (Exception e){e.printStackTrace();}
		}

		public String next() {
			if (st.hasMoreTokens())	return st.nextToken();
			try {st = new StringTokenizer(br.readLine());}
			catch (Exception e) {e.printStackTrace();}
			return st.nextToken();
		}

		public int nextInt() {return Integer.parseInt(next());}

		public long nextLong() {return Long.parseLong(next());}

		public double nextDouble() {return Double.parseDouble(next());}

		public String nextLine() {
			String line = "";
			try {line = br.readLine();}
			catch (Exception e) {e.printStackTrace();}
			return line;
		}

		public int[] nextIntArray(int n) {
			int[] a = new int[n];
			for(int i = 0; i < n; i++) a[i] = nextInt();
			return a;
		}

		public long[] nextLongArray(int n){
			long[] a = new long[n];
			for(int i = 0; i < n; i++) a[i] = nextLong();
			return a;
		}

		public double[] nextDoubleArray(int n){
			double[] a = new double[n];
			for(int i = 0; i < n; i++) a[i] = nextDouble();
			return a;
		}

		public char[][] nextGrid(int n, int m){
			char[][] grid = new char[n][m];
			for(int i = 0; i < n; i++) grid[i] = next().toCharArray();
			return grid;
		}
	}

}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.HashSet;
import java.util.StringTokenizer;
import java.util.concurrent.SynchronousQueue;

public class B {

	public static void main(String[] args) throws IOException {
		FastScanner scan = new FastScanner();
		PrintWriter out = new PrintWriter(System.out);
		int n = scan.nextInt(), m = scan.nextInt();
		int[] f = new int[n];
		HashSet<Integer>[] adj = new HashSet[n];
		for(int i = 0; i < n; i++) adj[i] = new HashSet<Integer>();
		for(int i = 0; i < n; i++) f[i] = i;
		for(int i = 0; i < m; i++){
			int x = scan.nextInt()-1, y = scan.nextInt()-1;
			adj[y].add(x);
			adj[x].add(y);
		}
		boolean good = true;
		boolean[] v = new boolean[n];
		for(int i = 0; i < n; i++){
			if(!v[i]){
				ArrayDeque<Integer> q = new ArrayDeque<>();
				q.add(i);
				v[i] = true;
				int nodes = 0, edges = 0;
				while(!q.isEmpty()){
					int at = q.poll();
					nodes++;
					edges += adj[at].size();
					for(int j : adj[at]) if(!v[j]){
						v[j] = true;
						q.add(j);
					}
				}
				edges = edges/2+edges%2;
				if(nodes > 2 && nodes*(nodes-1)/2 > edges) good = false;
			}
		}
		out.println(good?"YES":"NO");
		out.close();
	}

	static class FastScanner {
		BufferedReader br;
		StringTokenizer st;

		public FastScanner() {
			try	{
				br = new BufferedReader(new InputStreamReader(System.in));
				st = new StringTokenizer(br.readLine());
			} catch (Exception e){e.printStackTrace();}
		}

		public String next() {
			if (st.hasMoreTokens())	return st.nextToken();
			try {st = new StringTokenizer(br.readLine());}
			catch (Exception e) {e.printStackTrace();}
			return st.nextToken();
		}

		public int nextInt() {return Integer.parseInt(next());}

		public long nextLong() {return Long.parseLong(next());}

		public double nextDouble() {return Double.parseDouble(next());}

		public String nextLine() {
			String line = "";
			try {line = br.readLine();}
			catch (Exception e) {e.printStackTrace();}
			return line;
		}

		public int[] nextIntArray(int n) {
			int[] a = new int[n];
			for(int i = 0; i < n; i++) a[i] = nextInt();
			return a;
		}

		public long[] nextLongArray(int n){
			long[] a = new long[n];
			for(int i = 0; i < n; i++) a[i] = nextLong();
			return a;
		}

		public double[] nextDoubleArray(int n){
			double[] a = new double[n];
			for(int i = 0; i < n; i++) a[i] = nextDouble();
			return a;
		}

		public char[][] nextGrid(int n, int m){
			char[][] grid = new char[n][m];
			for(int i = 0; i < n; i++) grid[i] = next().toCharArray();
			return grid;
		}
	}

}