#include <bits/stdc++.h>
#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
using namespace std;
mt19937 rando(chrono::steady_clock::now().time_since_epoch().count());
long long random(long long l, long long r) {
  return (rando() % (r - l + 1) + l);
}
long long getbit(long long a, long long b) { return a & (1 << b); }
long long onbit(long long a, long long b) { return a | (1 << b); }
long long offbit(long long a, long long b) {
  return (!getbit(a, b)) ? a : a ^ (1 << b);
}
template <typename T>
inline void read(T &x) {
  char c;
  bool neg = 0;
  while ((!isdigit(c = getchar())) && (c != '-'))
    ;
  if (c == '-') {
    neg = 1;
    c = getchar();
  }
  x = c - 48;
  while (isdigit(c = getchar())) x = x * 10 + c - 48;
  if (neg) x = -x;
}
const long long mxN = 2e5 + 5;
const long long oo = 1e18;
const long long MOD = 1e9 + 7;
const long long d4i[4] = {-1, 0, 1, 0}, d4j[4] = {0, 1, 0, -1};
const long long d8i[8] = {-1, -1, 0, 1, 1, 1, 0, -1},
                d8j[8] = {0, 1, 1, 1, 0, -1, -1, -1};
long long TestCase;
long long n, m, u, v, cnt;
vector<long long> path;
vector<long long> adj[mxN];
bool visited[mxN];
void dfs(long long node) {
  visited[node] = true;
  path.push_back(node);
  for (auto child : adj[node])
    if (!visited[child]) dfs(child);
}
void Solve() {
  read(n);
  read(m);
  for (long long i = (long long)1; i <= (long long)m; i++) {
    read(u);
    read(v);
    adj[u].push_back(v);
    adj[v].push_back(u);
  }
  for (long long i = (long long)1; i <= (long long)n; i++)
    if (!visited[i]) {
      path.clear();
      dfs(i);
      long long edges = 0, vertices = path.size();
      for (auto node : path) edges += adj[node].size();
      if ((vertices * (vertices - 1)) != edges) {
        cout << "NO";
        return;
      }
    }
  cout << "YES";
}
int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  cout.tie(nullptr);
  TestCase = 1;
  while (TestCase--) Solve();
  return 0;
}
