Bear Limak examines a social network. Its main functionality is that two members can become friends (then they can talk with each other and share funny pictures).

There are n members, numbered 1 through n. m pairs of members are friends. Of course, a member can't be a friend with themselves.

Let A-B denote that members A and B are friends. Limak thinks that a network is reasonable if and only if the following condition is satisfied: For every three distinct members (X, Y, Z), if X-Y and Y-Z then also X-Z.

For example: if Alan and Bob are friends, and Bob and Ciri are friends, then Alan and Ciri should be friends as well.

Can you help Limak and check if the network is reasonable? Print "YES" or "NO" accordingly, without the quotes.


-----Input-----

The first line of the input contain two integers n and m (3 ≤ n ≤ 150 000, $0 \leq m \leq \operatorname{min}(150000, \frac{n \cdot(n - 1)}{2})$) — the number of members and the number of pairs of members that are friends.

The i-th of the next m lines contains two distinct integers a_{i} and b_{i} (1 ≤ a_{i}, b_{i} ≤ n, a_{i} ≠ b_{i}). Members a_{i} and b_{i} are friends with each other. No pair of members will appear more than once in the input.


-----Output-----

If the given network is reasonable, print "YES" in a single line (without the quotes). Otherwise, print "NO" in a single line (without the quotes).


-----Examples-----
Input
4 3
1 3
3 4
1 4

Output
YES

Input
4 4
3 1
2 3
3 4
1 2

Output
NO

Input
10 4
4 3
5 10
8 9
1 2

Output
YES

Input
3 2
1 2
2 3

Output
NO



-----Note-----

The drawings below show the situation in the first sample (on the left) and in the second sample (on the right). Each edge represents two members that are friends. The answer is "NO" in the second sample because members (2, 3) are friends and members (3, 4) are friends, while members (2, 4) are not.

 [Image]

Difficulty: MEDIUM
Tags: Spanning trees

Graph algorithms

Graph traversal

Starter code:

Solutions:
from collections import defaultdict

class Graph:

	def __init__(self, n):
		self.graph = defaultdict(list)
		self.vertices = n
		self.visited = [False] * (n + 1)
		self.one = 0
		self.others = []

	def addEdge(self, fr, to):
		self.graph[fr].append(to)
		self.graph[to].append(fr)

	def solve(self):
		for i in range(1, self.vertices + 1):
			if self.visited[i] == False:
				self.visited[i] = True
				Set = set(self.graph[i])
				Set.add(i)
				for j in self.graph[i]:
					Set1 = Set.copy()
					Set1.remove(j)
					self.visited[j] = True
					if set(self.graph[j]) != Set1:
						return 'NO'
		return 'YES'
(n, m) = map(int, input().split())
G = Graph(n)
for i in range(m):
	(a, b) = map(int, input().split())
	G.addEdge(a, b)
print(G.solve())


class CodeforcesTask771ASolution:

	def __init__(self):
		self.result = ''
		self.n_m = []
		self.edges = []

	def read_input(self):
		self.n_m = [int(x) for x in input().split(' ')]
		for x in range(self.n_m[1]):
			self.edges.append([int(y) for y in input().split(' ')])

	def process_task(self):
		graph = [[] for x in range(self.n_m[0])]
		lens = [0] * self.n_m[0]
		for edge in self.edges:
			graph[edge[0] - 1].append(edge[1])
			graph[edge[1] - 1].append(edge[0])
			lens[edge[0] - 1] += 1
			lens[edge[1] - 1] += 1
		component = [0] * self.n_m[0]
		comp_cnt = 0
		can = True
		fixed = set()
		for x in range(self.n_m[0]):
			if not component[x] or self.n_m[0] < 1000:
				if not component[x]:
					comp_cnt += 1
					component[x] = comp_cnt
				for y in graph[x]:
					if lens[y - 1] != lens[x]:
						can = False
						break
					elif component[y - 1]:
						if component[y - 1] != component[x]:
							can = False
							break
					else:
						if comp_cnt in fixed:
							can = False
							break
						component[y - 1] = comp_cnt
				if not can:
					break
				fixed.add(comp_cnt)
		self.result = 'YES' if can else 'NO'

	def get_result(self):
		return self.result
Solution = CodeforcesTask771ASolution()
Solution.read_input()
Solution.process_task()
print(Solution.get_result())


(n, m) = [int(x) for x in input().split()]
d = {}
con = set()
for x in range(m):
	(a, b) = input().split()
	d.setdefault(a, {a}).add(b)
	d.setdefault(b, {b}).add(a)
res = None
for (x, y) in list(d.items()):
	if x not in con:
		if all([d[u] == y for u in y]):
			con.update(y)
		else:
			res = 'NO'
			break
if not res:
	res = 'YES'
print(res)


(n, m) = map(int, input().split())
marked = [0] * n
adjlist = [set([i]) for i in range(n)]
for i in range(m):
	(v1, v2) = map(int, input().split())
	v1 -= 1
	v2 -= 1
	adjlist[v1].add(v2)
	adjlist[v2].add(v1)
for i in range(n):
	if not marked[i]:
		for j in adjlist[i]:
			marked[j] = 1
			if adjlist[i] != adjlist[j]:
				print('NO')
				exit(0)
print('YES')


from collections import defaultdict
(n, m) = map(int, input().split())
d = defaultdict(list)
for i in range(m):
	(a, b) = map(int, input().split())
	a -= 1
	b -= 1
	d[a].append(b)
	d[b].append(a)
vis = [0] * n
for i in range(n):
	if vis[i] == 0:
		q = [i]
		ce = 0
		cv = 0
		vis[i] = 1
		while q:
			t = q.pop()
			cv += 1
			ce += len(d[t])
			for i in d[t]:
				if not vis[i]:
					vis[i] = 1
					q.append(i)
	if ce != cv * (cv - 1):
		print('NO')
		exit()
print('YES')


(n, m) = list(map(int, input().split()))
d = {}
for i in range(m):
	(a, b) = list(map(int, input().split()))
	if a not in d:
		d[a] = {b}
	else:
		d[a].add(b)
	if b not in d:
		d[b] = {a}
	else:
		d[b].add(a)
not_visited = set(range(2, n + 1))
visited = set()
current = set()
stack = [1]
succ = True
while len(visited) < n:
	if not stack:
		t = not_visited.pop()
		stack = [t]
		current = set()
	p = stack.pop()
	visited.add(p)
	if p in d:
		for y in current:
			if y not in d[p]:
				succ = False
				break
		if not succ:
			break
		current.add(p)
		for x in d[p]:
			if x in not_visited:
				stack.append(x)
				not_visited.remove(x)
if succ:
	print('YES')
else:
	print('NO')


from collections import Counter as cntr
from math import inf

def cin():
	return list(map(int, input().split(' ')))

def dfs(graph, src, n):
	q = [src]
	h = 0
	nonlocal visited
	edges = 0
	while q:
		idx = q.pop()
		h += 1
		for v in graph[idx]:
			edges += 1
			if visited[v] == False:
				visited[v] = True
				q.append(v)
	return (h, edges)
(n, m) = cin()
g = {i: [] for i in range(n)}
for i in range(m):
	(a, b) = cin()
	a -= 1
	b -= 1
	g[a].append(b)
	g[b].append(a)
visited = [False for i in range(n)]
for i in range(n):
	if visited[i] == False:
		visited[i] = True
		(v, e) = dfs(g, i, n)
		e = e // 2
		if e != v * (v - 1) // 2:
			print('NO')
			return
print('YES')


from collections import defaultdict
g = defaultdict(set)
(n, m) = map(int, input().split())
for j in range(m):
	(u, v) = map(int, input().split())
	g[u].add(v)
	g[v].add(u)
visited = [0] * (n + 1)
f = 0
for j in range(1, n + 1):
	if visited[j] != 1:
		g[j].add(j)
		visited[j] = 1
		for v in g[j]:
			if visited[v] == 0:
				visited[v] = 1
				g[v].add(v)
				if g[v] != g[j]:
					f = 1
					break
if f == 0:
	print('YES')
else:
	print('NO')


import math, string, itertools, fractions, heapq, collections, re, array, bisect, sys, copy, functools
inf = 10 ** 20
eps = 1.0 / 10 ** 10
mod = 10 ** 9 + 7
mod2 = 998244353
dd = [(-1, 0), (0, 1), (1, 0), (0, -1)]
ddn = [(-1, 0), (-1, 1), (0, 1), (1, 1), (1, 0), (1, -1), (0, -1), (-1, -1)]

def LI():
	return list(map(int, sys.stdin.readline().split()))

def LLI():
	return [list(map(int, l.split())) for l in sys.stdin.readlines()]

def LI_():
	return [int(x) - 1 for x in sys.stdin.readline().split()]

def LF():
	return [float(x) for x in sys.stdin.readline().split()]

def LS():
	return sys.stdin.readline().split()

def I():
	return int(sys.stdin.readline())

def F():
	return float(sys.stdin.readline())

def S():
	return input()

def pf(s):
	return print(s, flush=True)

def pe(s):
	return print(str(s), file=sys.stderr)

def JA(a, sep):
	return sep.join(map(str, a))

def JAA(a, s, t):
	return s.join((t.join(map(str, b)) for b in a))

def IF(c, t, f):
	return t if c else f

def YES(c):
	return IF(c, 'YES', 'NO')

def Yes(c):
	return IF(c, 'Yes', 'No')

class UnionFind:

	def __init__(self, size):
		self.table = [-1 for _ in range(size)]

	def find(self, x):
		if self.table[x] < 0:
			return x
		else:
			self.table[x] = self.find(self.table[x])
			return self.table[x]

	def union(self, x, y):
		s1 = self.find(x)
		s2 = self.find(y)
		if s1 != s2:
			if self.table[s1] <= self.table[s2]:
				self.table[s1] += self.table[s2]
				self.table[s2] = s1
			else:
				self.table[s2] += self.table[s1]
				self.table[s1] = s2
			return True
		return False

	def same(self, x, y):
		return self.find(x) == self.find(y)

	def subsetall(self):
		a = []
		for i in range(len(self.table)):
			if self.table[i] < 0:
				a.append((i, -self.table[i]))
		return a

def main():
	t = 1
	rr = []
	for _ in range(t):
		(n, m) = LI()
		ab = [LI_() for _ in range(m)]
		uf = UnionFind(n)
		for (a, b) in ab:
			uf.union(a, b)
		t = 0
		for i in range(n):
			k = -uf.table[i]
			if k > 0:
				t += k * (k - 1) // 2
		rr.append(YES(t == m))
	return JA(rr, '\n')
print(main())


from collections import deque

def bfs(start):
	res = []
	queue = deque([start])
	while queue:
		vertex = queue.pop()
		if not vis[vertex]:
			vis[vertex] = 1
			res.append(vertex)
			for i in s[vertex]:
				if not vis[i]:
					queue.append(i)
	return res
(n, m) = [int(i) for i in input().split()]
s = [[] for i in range(n)]
for i in range(m):
	(a, b) = [int(i) for i in input().split()]
	s[a - 1].append(b - 1)
	s[b - 1].append(a - 1)
vis = [0 for i in range(n)]
r = 0
for i in range(n):
	if not vis[i]:
		d = bfs(i)
		for j in d:
			if len(s[j]) != len(d) - 1:
				r = 1
				print('NO')
				break
	if r:
		break
else:
	print('YES')


inp = lambda : list(map(int, input().split()))
(n, m) = inp()
lines = [set([i]) for i in range(n + 1)]
for i in range(m):
	(x, y) = inp()
	lines[x].add(y)
	lines[y].add(x)
f = [True] * (n + 1)
for i in range(n):
	if f[i]:
		f[i] = False
		for j in lines[i]:
			f[j] = False
			if lines[i] != lines[j]:
				print('NO')
				quit()
print('YES')


(n, m) = map(int, input().split(' '))
edges = [[] for i in range(n + 1)]
vis = [False] * (n + 1)

def dfs(a):
	nonlocal cnt_vertices
	nonlocal cnt_edges
	stack = [a]
	while len(stack) > 0:
		a = stack.pop()
		if vis[a]:
			continue
		vis[a] = True
		cnt_vertices += 1
		cnt_edges += len(edges[a])
		for b in edges[a]:
			if not vis[b]:
				stack.append(b)
while m > 0:
	(a, b) = map(int, input().split(' '))
	edges[a].append(b)
	edges[b].append(a)
	m -= 1
for i in range(1, n + 1):
	if vis[i] == False:
		cnt_vertices = 0
		cnt_edges = 0
		dfs(i)
		if cnt_edges != cnt_vertices * (cnt_vertices - 1):
			print('NO')
			return
print('YES')


from sys import stdin, stdout
import collections, heapq, bisect, math
input = stdin.readline

def rint():
	return int(input())

def rstr():
	return input().strip()

def rlstr():
	return list(input().strip().split())

def rlint():
	return list(map(int, input().split()))

def main():
	(n, m) = rlint()
	graph = collections.defaultdict(list)
	for _ in range(m):
		(u, v) = rlint()
		u -= 1
		v -= 1
		graph[u].append(v)
		graph[v].append(u)
	visit = [False] * n
	for i in range(n):
		if not visit[i]:
			queue = collections.deque()
			queue.append(i)
			visit[i] = True
			edges = 0
			nodes = 0
			while queue:
				u = queue.popleft()
				edges += len(graph[u])
				nodes += 1
				for v in graph[u]:
					if not visit[v]:
						visit[v] = True
						queue.append(v)
			if edges != nodes * (nodes - 1):
				return False
	return True
print('YES' if main() else 'NO')


import sys

def count_dfs(adj_list, visited, stack, c):
	node = stack.pop()
	if visited[node]:
		return
	visited[node] = True
	c[0] += 1
	c[1] += len(adj_list[node])
	for e in adj_list[node]:
		if visited[e] == False:
			stack.append(e)
	return

def answer2(n, m, a, b):
	adj_list = [[] for _ in range(n + 1)]
	visited = [False for _ in range(n + 1)]
	for i in range(m):
		adj_list[a[i]].append(b[i])
		adj_list[b[i]].append(a[i])
	for i in range(1, n + 1):
		if visited[i] == False:
			stack = [i]
			c = [0, 0]
			while len(stack) > 0:
				count_dfs(adj_list, visited, stack, c)
			if c[0] * (c[0] - 1) != c[1]:
				return 'NO'
	return 'YES'

def main():
	(n, m) = map(int, sys.stdin.readline().split())
	a = [0 for _ in range(m)]
	b = [0 for _ in range(m)]
	for i in range(m):
		(a[i], b[i]) = map(int, sys.stdin.readline().split())
	print(answer2(n, m, a, b))
	return
main()


import os
import sys
from io import BytesIO, IOBase
import math
from decimal import Decimal
from decimal import *
from collections import defaultdict, deque
import heapq
getcontext().prec = 25
abcd = 'abcdefghijklmnopqrstuvwxyz'
MOD = pow(10, 9) + 7
BUFSIZE = 8192
from bisect import bisect_left, bisect_right

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')

def dfs(i):
	visited[i] = True
	an = True
	f = g[i]
	for j in g[i]:
		if not visited[j]:
			visited[j] = True
			if g[j] != g[i]:
				an = False
				break
	return an
(n, k) = map(int, input().split(' '))
g = [set() for i in range(n + 1)]
for i in range(k):
	(x, y) = map(int, input().split(' '))
	g[x].add(x)
	g[y].add(y)
	g[x].add(y)
	g[y].add(x)
ans = 'YES'
visited = [False] * (n + 1)
for i in range(1, n + 1):
	if not visited[i]:
		test = dfs(i)
		if not test:
			ans = 'NO'
			break
print(ans)


def read():
	(n, m) = list(map(int, input().rstrip().split()))
	graph = [set() for _ in range(n + 1)]
	for _ in range(m):
		(a, b) = list(map(int, input().rstrip().split()))
		graph[a].add(b)
		graph[b].add(a)
		graph[a].add(a)
		graph[b].add(b)
	return (graph, n)

def main():
	(graph, n) = read()
	seen = set()
	for i in range(1, n + 1):
		if len(graph[i]) > 0 and i not in seen:
			if not all((graph[i] == graph[j] for j in graph[i])):
				return False
			seen |= graph[i]
	return True

def __starting_point():
	if main():
		print('YES')
	else:
		print('NO')
__starting_point()


import sys
from math import sqrt, gcd, ceil, log
from collections import defaultdict, Counter, deque
input = sys.stdin.readline
read = lambda : list(map(int, input().strip().split()))

def main():
	(n, m) = read()
	adj = [set([i]) for i in range(n + 1)]
	for i in range(m):
		(u, v) = read()
		adj[u].add(v)
		adj[v].add(u)
	visited = [0] * (n + 1)
	for i in range(1, n + 1):
		if not visited[i]:
			for child in adj[i]:
				if not visited[child]:
					visited[child] = 1
					if adj[i] != adj[child]:
						print('NO')
						exit()
	print('YES')
main()


def li():
	return list(map(int, input().split()))

def ls():
	return list(map(int, list(input())))

def i():
	return int(input())
from collections import defaultdict
graph = defaultdict(list)
(n, m) = li()
for _ in range(m):
	(x, y) = li()
	graph[x].append(y)
	graph[y].append(x)
visited = [False] * (n + 1)
flag = 1
for i in range(n + 1):
	if graph[i + 1]:
		graph[i + 1].append(i + 1)
		graph[i + 1].sort()
for i in range(n):
	if visited[i + 1] == False:
		visited[i + 1] = True
		for x in graph[i + 1]:
			if visited[x] == False:
				visited[x] = True
				if graph[x] != graph[i + 1]:
					flag = 0
					break
if flag == 1:
	print('YES')
else:
	print('NO')


from collections import defaultdict, deque

def is_reasonable(graph):
	to_visit = set(graph.keys())
	while to_visit:
		count_nodes = count_edges = 0
		queue = deque([to_visit.pop()])
		while queue:
			node = queue.pop()
			count_nodes += 1
			for child in graph[node]:
				count_edges += 1
				if child in to_visit:
					queue.appendleft(child)
					to_visit.remove(child)
		if count_edges != count_nodes * (count_nodes - 1):
			return False
	return True

def main():
	(n, m) = map(int, input().split())
	graph = defaultdict(list)
	for _ in range(m):
		(u, v) = map(int, input().split())
		graph[u].append(v)
		graph[v].append(u)
	print('YES' if is_reasonable(graph) else 'NO')
main()


from sys import stdin, stdout

def INI():
	return int(stdin.readline())

def INL():
	return [int(_) for _ in stdin.readline().split()]

def INS():
	return stdin.readline()

def MOD():
	return pow(10, 9) + 7

def OPS(ans):
	stdout.write(str(ans) + '\n')

def OPL(ans):
	[stdout.write(str(_) + ' ') for _ in ans]
	stdout.write('\n')
from types import GeneratorType

def bootstrap(f, stack=[]):

	def wrappedfunc(*args, **kwargs):
		if stack:
			return f(*args, **kwargs)
		else:
			to = f(*args, **kwargs)
			while True:
				if type(to) is GeneratorType:
					stack.append(to)
					to = next(to)
				else:
					stack.pop()
					if not stack:
						break
					to = stack[-1].send(to)
			return to
	return wrappedfunc

@bootstrap
def dfs(v):
	V[v] = True
	S.append(v)
	global c
	c += 1
	for _ in X[v]:
		if not V[_]:
			yield dfs(_)
	yield
(n, m) = INL()
X = [[] for _ in range(n + 1)]
V = [False for _ in range(n + 1)]
C = [0 for _ in range(n + 1)]
for _ in range(m):
	(u, v) = INL()
	X[u].append(v)
	X[v].append(u)
	C[u] += 1
	C[v] += 1
for _ in range(1, n + 1):
	S = []
	c = 0
	if not V[_]:
		dfs(_)
		for _ in S:
			if C[_] != c - 1:
				OPS('NO')
				break
		else:
			continue
		break
else:
	OPS('YES')


(n, m) = map(int, input().split())
v = [0] * 150005
s = [set([i]) for i in range(150005)]
for _ in ' ' * m:
	(a, b) = map(int, input().split())
	s[a].add(b)
	s[b].add(a)
for i in range(n):
	if not v[i]:
		for j in s[i]:
			v[j] = 1
			if s[j] != s[i]:
				print('NO')
				exit(0)
print('YES')


import sys, os, io
import math, bisect, operator
(inf, mod) = (float('inf'), 10 ** 9 + 7)
from itertools import groupby, accumulate
from heapq import heapify, heappop, heappush
from collections import deque, Counter, defaultdict
input = iter(sys.stdin.buffer.read().decode().splitlines()).__next__
Neo = lambda : list(map(int, input().split()))
G = defaultdict(list)

def addEdge(a, b):
	G[a].append(b)
	G[b].append(a)
(N, M) = Neo()
vis = [False] * (N + 1)

def dfs(node):
	s = deque()
	vis[node] = True
	s.append(node)
	C = []
	while s:
		x = s.pop()
		C.append(x)
		for i in G.get(x, []):
			if not vis[i]:
				vis[i] = True
				s.append(i)
	return C
edge = set()
for i in range(M):
	(u, v) = Neo()
	edge.add((u, v))
	edge.add((v, u))
	addEdge(u, v)
for i in range(1, N + 1):
	if not vis[i]:
		C = dfs(i)
		n = len(C)
		for i in range(n):
			for j in range(i + 1, n):
				if not (C[i], C[j]) in edge:
					print('NO')
					exit(0)
print('YES')


import sys, os, io

def rs():
	return sys.stdin.readline().rstrip()

def ri():
	return int(sys.stdin.readline())

def ria():
	return list(map(int, sys.stdin.readline().split()))

def ws(s):
	sys.stdout.write(s + '\n')

def wi(n):
	sys.stdout.write(str(n) + '\n')

def wia(a):
	sys.stdout.write(' '.join([str(x) for x in a]) + '\n')
import math, datetime, functools, itertools, operator, bisect, fractions, statistics
from collections import deque, defaultdict, OrderedDict, Counter
from fractions import Fraction
from decimal import Decimal
from sys import stdout
from heapq import heappush, heappop, heapify, _heapify_max, _heappop_max, nsmallest, nlargest
INF = 99999999999999999999999999999999

def main():
	mod = 1000000007
	starttime = datetime.datetime.now()
	if os.path.exists('input.txt'):
		sys.stdin = open('input.txt', 'r')
		sys.stdout = open('output.txt', 'w')
	tc = 1
	for _ in range(tc):
		(n, m) = ria()
		graph = [[] for i in range(n + 1)]
		visited = [False] * (n + 1)
		col = [-1] * (n + 1)
		for i in range(m):
			(a, b) = ria()
			graph[a].append(b)
			graph[b].append(a)

		def dfs(start):
			comp = []
			stack = [start]
			while stack:
				start = stack[-1]
				if not visited[start]:
					comp.append(start)
					visited[start] = True
					for child in graph[start]:
						if not visited[child]:
							stack.append(child)
				else:
					stack.pop()
			for i in comp:
				if len(graph[i]) != len(comp) - 1:
					return False
			return True
		cc = 0
		d = {}
		ans = 'YES'
		for i in range(1, n + 1):
			if not visited[i] and (not dfs(i)):
				ans = 'NO'
				break
		print(ans)
	endtime = datetime.datetime.now()
	time = (endtime - starttime).total_seconds() * 1000
	if os.path.exists('input.txt'):
		print('Time:', time, 'ms')

class FastReader(io.IOBase):
	newlines = 0

	def __init__(self, fd, chunk_size=1024 * 8):
		self._fd = fd
		self._chunk_size = chunk_size
		self.buffer = io.BytesIO()

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, self._chunk_size))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self, size=-1):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, self._chunk_size if size == -1 else size))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

class FastWriter(io.IOBase):

	def __init__(self, fd):
		self._fd = fd
		self.buffer = io.BytesIO()
		self.write = self.buffer.write

	def flush(self):
		os.write(self._fd, self.buffer.getvalue())
		(self.buffer.truncate(0), self.buffer.seek(0))

class FastStdin(io.IOBase):

	def __init__(self, fd=0):
		self.buffer = FastReader(fd)
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')

class FastStdout(io.IOBase):

	def __init__(self, fd=1):
		self.buffer = FastWriter(fd)
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.flush = self.buffer.flush
sys.stdin = FastStdin()
sys.stdout = FastStdout()
main()


(n, m) = [int(x) for x in input().split()]
l = []
for i in range(m):
	(x, y) = [int(x) for x in input().split()]
	if x > y:
		(x, y) = (y, x)
	l.append((x, y))
l.sort(key=lambda x: x[0])
labels = {}
rels_count = {}
class_count = {}
for (x, y) in l:
	if x not in labels:
		labels[x] = len(rels_count)
		rels_count[labels[x]] = 0
		class_count[labels[x]] = 1
	if y not in labels:
		class_count[labels[x]] += 1
	labels[y] = labels[x]
	rels_count[labels[x]] += 1
flag = True
for i in range(len(rels_count)):
	l_n = class_count[i]
	l_m = rels_count[i]
	if l_n * (l_n - 1) != 2 * l_m:
		flag = False
		break
if flag:
	print('YES')
else:
	print('NO')


import sys

def main():
	(n, m) = map(int, sys.stdin.readline().split())
	l = [[] for i in range(n + 1)]
	u = [False] * (n + 1)
	for i in range(m):
		(a, b) = map(int, sys.stdin.readline().split())
		l[a].append(b)
		l[b].append(a)
	for i in range(n):
		j = i + 1
		if u[j]:
			continue
		u[j] = True
		q = []
		cl = len(l[j])
		cn = 1
		for a in l[j]:
			q.append(a)
		while len(q) != 0:
			cur = q.pop()
			if u[cur]:
				continue
			u[cur] = True
			cn += 1
			cl += len(l[cur])
			for a in l[cur]:
				if u[a]:
					continue
				q.append(a)
		if cl != cn * (cn - 1):
			print('NO')
			return
	print('YES')
main()


nax = 150123
edges = [[] for _ in range(nax)]
vis = [False for j in range(nax)]

def dfs(a, cnt_vertices, cnt_edges):
	stack = [a]
	while len(stack) > 0:
		a = stack.pop()
		if vis[a]:
			continue
		vis[a] = True
		cnt_vertices[0] += 1
		cnt_edges[0] += len(edges[a])
		for b in edges[a]:
			if not vis[b]:
				stack.append(b)

def main():
	(n, m) = list(map(int, str(input()).strip().split()))
	for _ in range(m):
		(a, b) = list(map(int, str(input()).strip().split()))
		edges[a].append(b)
		edges[b].append(a)
	for i in range(1, n + 1):
		if not vis[i]:
			cnt_vertices = [0]
			cnt_edges = [0]
			dfs(i, cnt_vertices, cnt_edges)
			if cnt_edges[0] != cnt_vertices[0] * (cnt_vertices[0] - 1):
				print('NO')
				return 0
	print('YES')

def __starting_point():
	main()
__starting_point()


from sys import stdin
from collections import deque

def ii():
	return int(stdin.readline())

def fi():
	return float(stdin.readline())

def mi():
	return map(int, stdin.readline().split())

def fmi():
	return map(float, stdin.readline().split())

def li():
	return list(mi())

def lsi():
	x = list(stdin.readline())
	x.pop()
	return x

def si():
	return stdin.readline()
(n, m) = mi()
a = [{i} for i in range(n + 1)]
v = [True] * (n + 1)
for _ in range(m):
	(x, y) = mi()
	a[x].add(y)
	a[y].add(x)
for i in range(1, n + 1):
	if v[i]:
		for j in a[i]:
			if a[i] != a[j]:
				print('NO')
				exit()
			v[j] = False
print('YES')


import sys
input = sys.stdin.buffer.readline

def dfs(adj, vis, i):
	count = 0
	c = 0
	stack = [i]
	while len(stack) > 0:
		u = stack[-1]
		if vis[u] == 0:
			vis[u] = 1
			c += 1
			count += len(adj[u])
			for v in adj[u]:
				if vis[v] == 0:
					stack.append(v)
		else:
			stack.pop()
	return (c, count)
(n, m) = map(int, input().split())
adj = [[] for i in range(0, n + 1)]
for _ in range(0, m):
	(u, v) = map(int, input().split())
	adj[u].append(v)
	adj[v].append(u)
vis = [0] * (n + 1)
f = 0
for i in range(1, n + 1):
	if vis[i] == 0:
		(c, count) = dfs(adj, vis, i)
		if count != c * (c - 1):
			f = 1
			break
	if f == 1:
		break
if f == 1:
	print('NO')
else:
	print('YES')


import sys
import math
import heapq
import bisect
from collections import Counter
from collections import defaultdict
from io import BytesIO, IOBase
import string

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		import os
		self.os = os
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None
		self.BUFSIZE = 8192

	def read(self):
		while True:
			b = self.os.read(self._fd, max(self.os.fstat(self._fd).st_size, self.BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = self.os.read(self._fd, max(self.os.fstat(self._fd).st_size, self.BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			self.os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')

def get_int():
	return int(input())

def get_ints():
	return list(map(int, input().split(' ')))

def get_int_grid(n):
	return [get_ints() for _ in range(n)]

def get_str():
	return input().split(' ')

def yes_no(b):
	if b:
		return 'YES'
	else:
		return 'NO'

def binary_search(good, left, right, delta=1, right_true=False):
	limits = [left, right]
	while limits[1] - limits[0] > delta:
		if delta == 1:
			mid = sum(limits) // 2
		else:
			mid = sum(limits) / 2
		if good(mid):
			limits[int(right_true)] = mid
		else:
			limits[int(~right_true)] = mid
	if good(limits[int(right_true)]):
		return limits[int(right_true)]
	else:
		return False

def prefix_sums(a, drop_zero=False):
	p = [0]
	for x in a:
		p.append(p[-1] + x)
	if drop_zero:
		return p[1:]
	else:
		return p

def prefix_mins(a, drop_zero=False):
	p = [float('inf')]
	for x in a:
		p.append(min(p[-1], x))
	if drop_zero:
		return p[1:]
	else:
		return p

class DSU:

	def __init__(self, nodes):
		self.p = [i for i in range(nodes)]
		self.r = [0 for i in range(nodes)]
		self.s = [1 for i in range(nodes)]

	def get(self, u):
		if u != self.p[u]:
			self.p[u] = self.get(self.p[u])
		return self.p[u]

	def union(self, u, v):
		u = self.get(u)
		v = self.get(v)
		if u != v:
			if self.r[u] > self.r[v]:
				(u, v) = (v, u)
			self.p[u] = v
			if self.r[u] == self.r[v]:
				self.r[v] += 1
			self.s[v] += self.s[u]

	def size(self, u):
		return self.s[self.get(u)]

def solve_a():
	(n, m) = get_ints()
	dsu = DSU(n)
	for i in range(m):
		(a, b) = get_ints()
		dsu.union(a - 1, b - 1)
	S = sum([dsu.size(u) * (dsu.size(u) - 1) // 2 for u in range(n) if dsu.get(u) == u])
	return yes_no(S == m)
print(solve_a())


from collections import defaultdict
from sys import stdin
input = stdin.readline

class UnionFind:

	def __init__(self, n):
		self.n = n
		self.parents = [-1] * n

	def find(self, x):
		if self.parents[x] < 0:
			return x
		else:
			self.parents[x] = self.find(self.parents[x])
			return self.parents[x]

	def union(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return
		if self.parents[x] > self.parents[y]:
			(x, y) = (y, x)
		self.parents[x] += self.parents[y]
		self.parents[y] = x

	def size(self, x):
		return -self.parents[self.find(x)]

	def same(self, x, y):
		return self.find(x) == self.find(y)

	def members(self, x):
		root = self.find(x)
		return [i for i in range(self.n) if self.find(i) == root]

	def roots(self):
		return [i for (i, x) in enumerate(self.parents) if x < 0]

	def group_count(self):
		return len(self.roots())

	def all_group_members(self):
		group_members = defaultdict(list)
		for member in range(self.n):
			group_members[self.find(member)].append(member)
		return group_members
(n, m) = map(int, input().split())
g = [[] for i in range(n)]
uf = UnionFind(n)
for _ in range(m):
	(u, v) = map(int, input().split())
	g[u - 1].append(v - 1)
	g[v - 1].append(u - 1)
	uf.union(u - 1, v - 1)
ss = [0] * n
for i in range(n):
	ss[uf.find(i)] += len(g[i])
for r in uf.roots():
	s = uf.size(r)
	if ss[r] != s * (s - 1):
		print('NO')
		exit()
print('YES')


import os
import sys
from io import BytesIO, IOBase
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
import sys
import math
from math import gcd
import bisect
import heapq
from collections import deque

def dfs(v):
	s = deque([v])
	vis[v] = 1
	cv = 0
	ce = 0
	while s:
		v = s.pop()
		cv += 1
		ce += len(g[v])
		for i in g[v]:
			if not vis[i]:
				vis[i] = 1
				s.appendleft(i)
	if cv * (cv - 1) != ce:
		return False
	return True
(n, m) = map(int, input().split())
g = [[] for i in range(n + 1)]
for _ in range(m):
	(u, v) = map(int, input().split())
	g[u].append(v)
	g[v].append(u)
vis = [0] * (n + 1)
sign = 1
for i in range(1, n + 1):
	if not vis[i]:
		flag = dfs(i)
		if not flag:
			sign = 0
			print('NO')
			break
if sign:
	print('YES')


(n, m) = [int(x) for x in input().split()]
d = {}
visited = set()
for x in range(m):
	(a, b) = input().split()
	d.setdefault(a, {a}).add(b)
	d.setdefault(b, {b}).add(a)
for (x, y) in d.items():
	if x not in visited:
		if all([d[u] == y for u in y]):
			visited.update(y)
		else:
			print('NO')
			return
			break
print('YES')


import io, os
input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline
from collections import defaultdict
(n, m) = map(int, input().split())
adj = defaultdict(list)
for i in range(m):
	(a, b) = map(int, input().split())
	adj[a].append(b)
	adj[b].append(a)
v = [0] * (n + 1)
ok = True
for i in range(1, 1 + n):
	if not v[i]:
		ct = 0
		q = [i]
		ml = 1e+18
		mxl = 0
		while q:
			e = q.pop()
			if not v[e]:
				ml = min(ml, len(adj[e]))
				mxl = max(mxl, len(adj[e]))
				ct += 1
			v[e] = 1
			for j in adj[e]:
				if not v[j]:
					q.append(j)
		if ct != 1 and (ml != ct - 1 or mxl != ct - 1):
			ok = False
			break
print('YES' if ok else 'NO')


import sys

def answer(n, m, a, b):
	adj_list = [[] for _ in range(n + 1)]
	visited = [False for _ in range(n + 1)]
	for i in range(m):
		adj_list[a[i]].append(b[i])
		adj_list[b[i]].append(a[i])
	for i in range(1, n + 1):
		if visited[i] == False:
			visited[i] = True
			s = set(adj_list[i])
			s.add(i)
			for e in adj_list[i]:
				visited[e] = True
				sc = set(adj_list[e])
				sc.add(e)
				if s != sc:
					return 'NO'
	return 'YES'

def main():
	(n, m) = map(int, sys.stdin.readline().split())
	a = [0 for _ in range(m)]
	b = [0 for _ in range(m)]
	for i in range(m):
		(a[i], b[i]) = map(int, sys.stdin.readline().split())
	print(answer(n, m, a, b))
	return
main()


from types import GeneratorType

def bootstrap(f, stack=[]):

	def wrappedfunc(*args, **kwargs):
		if stack:
			return f(*args, **kwargs)
		else:
			to = f(*args, **kwargs)
			while True:
				if type(to) is GeneratorType:
					stack.append(to)
					to = next(to)
				else:
					stack.pop()
					if not stack:
						break
					to = stack[-1].send(to)
			return to
	return wrappedfunc
import io, os
input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline
(n, m) = map(int, input().split())
adj = [[] for i in range(n + 1)]
for i in range(m):
	(s, e) = map(int, input().split())
	adj[s].append(e)
	adj[e].append(s)

@bootstrap
def dfs(node):
	global res, cou
	if visited[node]:
		yield
	res += len(adj[node])
	cou += 1
	visited[node] = 1
	for i in adj[node]:
		yield dfs(i)
	yield
visited = [0] * (n + 1)
f = True
for a in range(1, n + 1):
	if visited[a] == 0:
		cou = 0
		res = 0
		dfs(a)
		if cou * (cou - 1) != res:
			print('NO')
			f = False
			break
if f:
	print('YES')


import sys
import collections

def bfs(u, adjList, vis):
	dq = collections.deque()
	dq.append(u)
	vis[u] = True
	edgeCnt = 0
	vertexCnt = 0
	while dq:
		u = dq.popleft()
		vertexCnt += 1
		edgeCnt += len(adjList[u])
		for v in adjList[u]:
			if not vis[v]:
				vis[v] = True
				dq.append(v)
	edgeCnt = edgeCnt // 2
	return bool(edgeCnt == (vertexCnt * vertexCnt - vertexCnt) // 2)

def main():
	it = iter(map(int, sys.stdin.read().split()))
	n = next(it)
	m = next(it)
	adjList = [[] for _ in range(n + 3)]
	for _ in range(m):
		u = next(it)
		v = next(it)
		adjList[u].append(v)
		adjList[v].append(u)
	vis = [False] * (n + 3)
	for u in range(1, n + 1):
		if not vis[u]:
			if not bfs(u, adjList, vis):
				sys.stdout.write('NO\n')
				return
	sys.stdout.write('YES\n')

def __starting_point():
	main()
__starting_point()


from collections import defaultdict, deque
from sys import *

def bfs(graph, vis, node):
	q = deque()
	q.append(node)
	vis[node] = 0
	cnt = 1
	while q:
		s = q.popleft()
		for i in graph[s]:
			if vis[i] == 1:
				vis[i] = 0
				cnt += 1
				if len(graph[s]) != len(graph[i]):
					return -1
				q.append(i)
	return cnt
(n, m) = map(int, stdin.readline().split())
graph = defaultdict(list)
here = [0] * (n + 1)
for i in range(m):
	(u, v) = map(int, stdin.readline().split())
	graph[u].append(v)
	graph[v].append(u)
	here[u] = 1
	here[v] = 1
ver = 0
for i in range(n):
	if here[i] == 0:
		continue
	ver = bfs(graph, here, i)
	if ver == -1:
		break
	if ver - 1 != len(graph[i]):
		ver = -1
		break
if ver == -1:
	stdout.write('NO\n')
else:
	stdout.write('YES\n')


from sys import stdin
input = lambda : stdin.readline().strip()
from math import ceil, sqrt, factorial, gcd
from collections import deque

def traverse(x):
	global count
	stack = [x]
	while stack:
		x = stack.pop()
		if x not in visited:
			for i in graph[x]:
				count += 1
				stack.append(i)
				graph[i].remove(x)
			visited.add(x)
(n, m) = map(int, input().split())
graph = [set([i]) for i in range(n + 1)]
s = set()
ans = [0 for i in range(n + 1)]
for i in range(m):
	(a, b) = map(int, input().split())
	graph[a].add(b)
	graph[b].add(a)
	s.add(a)
	s.add(b)
count = 0
visi = set()
for i in range(n):
	if ans[i] == 0:
		ans[i] = 1
		for j in graph[i]:
			ans[j] = 1
			if graph[i] != graph[j]:
				print('NO')
				exit()
print('YES')


(n, m) = map(int, input().split())
dic = {}
edges = []
from collections import Counter

def find(node):
	tmp = node
	while node != dic[node]:
		node = dic[node]
	while tmp != dic[tmp]:
		(dic[tmp], tmp) = (node, dic[tmp])
	return node
for _ in range(m):
	(p1, p2) = map(int, input().split())
	dic.setdefault(p1, p1)
	dic.setdefault(p2, p2)
	edges.append(p1)
	lp = find(p1)
	rp = find(p2)
	if lp != rp:
		dic[rp] = lp
for k in dic:
	find(k)

def judge():
	counter = Counter([dic[i] for i in edges])
	s = Counter(dic.values())
	for k in counter:
		(en, nn) = (counter[k], s[k])
		if (nn ** 2 - nn) // 2 != en:
			return False
	return True
if judge():
	print('YES')
else:
	print('NO')


from sys import stdin
input = stdin.readline
R = lambda : map(int, input().split())
I = lambda : int(input())
S = lambda : input().rstrip('\n')
(n, m) = R()
v = [[i] for i in range(n)]
vst = [0] * n
for _ in range(m):
	(a, b) = R()
	v[a - 1] += (b - 1,)
	v[b - 1] += (a - 1,)
for i in v:
	i.sort()
for i in range(n):
	if vst[i]:
		continue
	vst[i] = 1
	if len(v[i]) > 2:
		for j in v[i]:
			vst[j] = 1
			if v[j] != v[i]:
				exit(print('NO'))
print('YES')


import math, sys, bisect, heapq
from collections import defaultdict, Counter, deque
from itertools import groupby, accumulate
from functools import lru_cache
int1 = lambda x: int(x) - 1
input = iter(sys.stdin.buffer.read().decode().splitlines()).__next__
aj = lambda : list(map(int, input().split()))

def list3d(a, b, c, d):
	return [[[d] * c for j in range(b)] for i in range(a)]

def Y(c):
	print(['NO', 'YES'][c])

def y(c):
	print(['no', 'yes'][c])

def Yy(c):
	print(['No', 'Yes'][c])
G = defaultdict(list)

def addEdge(a, b):
	G[a].append(b)
	G[b].append(a)
(N, M) = aj()
vis = [False] * (N + 1)

def dfs(node):
	s = deque()
	vis[node] = True
	s.append(node)
	C = []
	while s:
		x = s.pop()
		C.append(x)
		for i in G.get(x, []):
			if not vis[i]:
				vis[i] = True
				s.append(i)
	return C
edge = set()
for i in range(M):
	(u, v) = aj()
	edge.add((u, v))
	edge.add((v, u))
	addEdge(u, v)
for i in range(1, N + 1):
	if not vis[i]:
		C = dfs(i)
		n = len(C)
		for i in range(n):
			for j in range(i + 1, n):
				if not (C[i], C[j]) in edge:
					Y(0)
					exit(0)
Y(1)


from collections import defaultdict
import sys
input = __import__('sys').stdin.readline
(n, m) = map(int, input().split())
adj = defaultdict(set)
vis = [False] * (n + 1)
for i in range(m):
	(u, v) = map(int, input().split())
	adj[u].add(v)
	adj[v].add(u)
for x in adj:
	adj[x].add(x)
for i in range(1, n + 1):
	if not vis[i]:
		for j in adj[i]:
			vis[j] = True
			if adj[i] != adj[j]:
				print('NO')
				exit()
print('YES')


from sys import *
f = lambda : map(int, stdin.readline().split())
(n, m) = f()
g = [[i] for i in range(n + 1)]
for j in range(m):
	(u, v) = f()
	g[u].append(v)
	g[v].append(u)
k = 'YES'
for t in g:
	t.sort()
for t in g:
	s = len(t)
	if s > 1 and (not all((g[x] == t for x in t))):
		k = 'NO'
		break
	for j in t:
		g[j] = []
print(k)


import sys
(n, m) = map(int, input().split())
q = {i: set([i]) for i in range(1, n + 1)}
v = set()
for i in range(m):
	(a, b) = map(int, input().split())
	q[a].add(b)
	q[b].add(a)
for (k, w) in q.items():
	if k not in v:
		z = [q[i] == w for i in w]
		if 0 not in z:
			v.update(w)
		else:
			print('NO')
			sys.exit()
print('YES')


import sys, math
input = sys.stdin.readline

def getInts():
	return [int(s) for s in input().split()]

def getInt():
	return int(input())

def getStrs():
	return [s for s in input().split()]

def getStr():
	return input().strip()

def listStr():
	return list(input().strip())
import collections as col
import math

def solve():

	def bfs(graph, visited, node, queue, nodes):
		visited.add(node)
		nodes.remove(node)
		queue.append(node)
		queue = col.deque(queue)
		while queue:
			s = queue.popleft()
			for neighbour in graph[s]:
				if neighbour not in visited:
					visited.add(neighbour)
					nodes.remove(neighbour)
					queue.append(neighbour)
		return (visited, nodes)
	(N, M) = getInts()
	graph = col.defaultdict(set)
	edges = 0
	for m in range(M):
		(U, V) = getInts()
		edges += 1
		graph[U].add(V)
		graph[V].add(U)
	nodes = set([j + 1 for j in range(N)])
	max_edges = 0
	while nodes:
		node = next(iter(nodes))
		(visited, nodes) = bfs(graph, set(), node, [], nodes)
		L = len(visited)
		max_edges += L * (L - 1) // 2
	return 'YES' if edges == max_edges else 'NO'
print(solve())


from collections import defaultdict, deque
nodes = 0
edges = 0

def dfs(node):
	global nodes, edges
	q = deque()
	q.append(node)
	while q:
		s1 = q.popleft()
		if not visit[s1]:
			nodes += 1
			visit[s1] = True
			for i in g[s1]:
				edges += 1
				q.append(i)
(n, m) = map(int, input().split())
g = defaultdict(list)
for i in range(m):
	(u, v) = map(int, input().split())
	g[u].append(v)
	g[v].append(u)
visit = [False] * (n + 1)
ans = 'YES'
for i in range(1, n + 1):
	if not visit[i]:
		(nodes, edges) = (0, 0)
		dfs(i)
		if edges > 0:
			edges //= 2
			if edges != nodes * (nodes - 1) // 2:
				ans = 'NO'
print(ans)


from sys import *
f = lambda : map(int, stdin.readline().split())
(n, m) = f()
g = [[x] for x in range(n + 1)]
p = [0] * (n + 1)
for j in range(m):
	(u, v) = f()
	g[u].append(v)
	g[v].append(u)
k = 'YES'
for (y, t) in enumerate(g):
	if not p[y]:
		if any((len(g[x]) != len(t) or any((p[y] for y in g[x])) for x in t)):
			k = 'NO'
			break
		for x in t:
			p[x] = 1
print(k)


import sys
inf = float('inf')
sys.setrecursionlimit(1000000)
abc = 'abcdefghijklmnopqrstuvwxyz'
abd = {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 5, 'g': 6, 'h': 7, 'i': 8, 'j': 9, 'k': 10, 'l': 11, 'm': 12, 'n': 13, 'o': 14, 'p': 15, 'q': 16, 'r': 17, 's': 18, 't': 19, 'u': 20, 'v': 21, 'w': 22, 'x': 23, 'y': 24, 'z': 25}
(mod, MOD) = (1000000007, 998244353)
vow = ['a', 'e', 'i', 'o', 'u']
(dx, dy) = ([-1, 1, 0, 0], [0, 0, 1, -1])

def dfs(start):
	stack = [start]
	ct_vertex = 1
	ct_edges = 0
	while stack:
		x = stack.pop()
		visited[x] = True
		for i in graph[x]:
			ct_edges += 1
			if not visited[i]:
				visited[i] = True
				ct_vertex += 1
				stack.append(i)
	if ct_edges == ct_vertex * (ct_vertex - 1):
		return True
	else:
		return False

def get_array():
	return list(map(int, sys.stdin.readline().strip().split()))

def get_ints():
	return map(int, sys.stdin.readline().strip().split())

def input():
	return sys.stdin.readline().strip()
(n, m) = get_ints()
graph = {i: [] for i in range(1, n + 1)}
for i in range(m):
	(x, y) = get_ints()
	graph[x].append(y)
	graph[y].append(x)
visited = [False] * (n + 1)
flag = 0
for i in range(1, n + 1):
	if not visited[i]:
		if not dfs(i):
			flag = 1
			break
if flag == 0:
	print('YES')
else:
	print('NO')


import sys
input = sys.stdin.readline
from collections import defaultdict
from collections import deque
(n, m) = list(map(int, input().split()))
d = defaultdict(list)
for i in range(m):
	(x, y) = list(map(int, input().split()))
	d[x].append(y)
	d[y].append(x)
visited = [0] * (n + 1)
f = 0
for i in d:
	if visited[i] == 0:
		q = deque()
		q.append(i)
		c = 0
		t = len(d[i])
		visited[i] = 1
		while q:
			j = q.popleft()
			if t != len(d[j]):
				f = 1
			c = c + 1
			for k in d[j]:
				if visited[k] == 0:
					if c > 1:
						f = 1
						break
					else:
						q.append(k)
						visited[k] = 1
			if f:
				break
	if f:
		break
if f:
	print('NO')
else:
	print('YES')


from sys import stdin

def main():
	(n, m) = map(int, input().split())
	(n, m) = (n + 1, m * 2)
	g = [[] for _ in range(n)]
	for s in stdin.read().splitlines():
		(u, v) = map(int, s.split())
		g[u].append(v)
		g[v].append(u)
	avail = [True] * n
	for u in range(1, n):
		if avail[u]:
			(stack, avail[u], cnt) = ([u], False, 0)
			while stack:
				u = stack.pop()
				cnt += 1
				for v in g[u]:
					if avail[v]:
						avail[v] = False
						stack.append(v)
			m -= cnt * (cnt - 1)
	print(('NO', 'YES')[not m])
main()


from sys import stdin, stdout
import collections, heapq, bisect, math
input = stdin.readline

def rint():
	return int(input())

def rstr():
	return input().strip()

def rlstr():
	return list(input().strip().split())

def rlint():
	return list(map(int, input().split()))

def main():
	(n, m) = rlint()
	graph = collections.defaultdict(list)
	indegree = [0] * n
	for _ in range(m):
		(u, v) = rlint()
		u -= 1
		v -= 1
		indegree[u] += 1
		indegree[v] += 1
		graph[u].append(v)
		graph[v].append(u)
	visit = [False] * n
	for i in range(n):
		if not visit[i]:
			queue = collections.deque()
			queue.append(i)
			visit[i] = True
			no_nodes = 0
			maxin = 0
			minin = n
			while queue:
				u = queue.popleft()
				no_nodes += 1
				maxin = max(maxin, indegree[u])
				minin = min(minin, indegree[u])
				for v in graph[u]:
					if not visit[v]:
						visit[v] = True
						queue.append(v)
			if maxin != minin or maxin != no_nodes - 1:
				return False
	return True
print('YES' if main() else 'NO')


from types import GeneratorType
import sys
input = sys.stdin.readline

def bootstrap(f, stack=[]):

	def wrappedfunc(*args, **kwargs):
		if stack:
			return f(*args, **kwargs)
		else:
			to = f(*args, **kwargs)
			while True:
				if type(to) is GeneratorType:
					stack.append(to)
					to = next(to)
				else:
					stack.pop()
					if not stack:
						break
					to = stack[-1].send(to)
			return to
	return wrappedfunc

class Graph:

	def __init__(self, V):
		self.V = V
		self.adj = [[] for i in range(V)]

	@bootstrap
	def DFSUtil(self, temp, v, visited):
		visited[v] = True
		temp.append(v)
		for i in self.adj[v]:
			if visited[i] == False:
				temp = (yield self.DFSUtil(temp, i, visited))
		yield temp

	def addEdge(self, v, w):
		self.adj[v].append(w)
		self.adj[w].append(v)

	def connectedComponents(self):
		visited = []
		cc = []
		for i in range(self.V):
			visited.append(False)
		for v in range(self.V):
			if visited[v] == False:
				temp = []
				cc.append(self.DFSUtil(temp, v, visited))
		return cc
(n, m) = list(map(int, input().split()))
G = Graph(n)
for _ in range(m):
	(u, v) = list(map(int, input().split()))
	u -= 1
	v -= 1
	G.addEdge(u, v)
c = G.connectedComponents()
ans = 'YES'
for i in c:
	for j in i:
		if len(G.adj[j]) != len(i) - 1:
			ans = 'NO'
			break
print(ans)


from collections import Counter, defaultdict, deque
(n, m) = [int(x) for x in input().split()]
connections = [[] for i in range(n)]
for i in range(m):
	(a, b) = [int(x) - 1 for x in input().split()]
	connections[a].append(b)
	connections[b].append(a)
globalvisited = [False for i in range(n)]

def DFS(cmap, v):
	stack = deque([v])
	vcount = 0
	ecount = len(cmap[v])
	while len(stack) != 0:
		vertex = stack.pop()
		if not globalvisited[vertex]:
			vcount += 1
			globalvisited[vertex] = True
			if len(cmap[vertex]) != ecount:
				return False
			stack.extend(cmap[vertex])
	return vcount - 1 == ecount
for i in range(n):
	if not globalvisited[i]:
		cur = DFS(connections, i)
		if not cur:
			print('NO')
			exit()
print('YES')