{$apptype console}
{$r+,q+,o-}
const
MAXN = 100000; // Максимальное число вершин
MAXM = 1000000; // Максимальное число ребер
var
// head[i] - номер головы списка смежных с i-ой вершин
head: array [1..MAXN] of longint;
// Граф неориентированный, поэтому размеры массивов next и target
// в два раза больше максимального числа ребер
next, target: array [1..2 * MAXM] of longint;
// Номер свободной ячейки в массивах next и target
free: longint;
// Массив пометок для поиска в глубину
mark: array [1..MAXN] of boolean;
// Добавляет ребро u-v в граф
procedure addEdge(u, v: longint);
begin
// Добавляем вершину v в список смежности вершины u
inc(free);
target[free] := v;
next[free] := head[u];
head[u] := free;
// Добавляем вершину u в список смежности вершины v
inc(free);
target[free] := u;
next[free] := head[v];
head[v] := free;
end;
procedure dfs(u: longint);
var
cur, v: longint;
begin
mark[u] := true;
// Проходимся по всем вершинам, смежным с u
cur := head[u];
while (cur <> -1) do begin
v := target[cur]; // v - очередная вершина в списке
// Если не были в вершине - идем в нее
if (not mark[v]) then
dfs(v);
cur := next[cur]; // переходим к следующему элементу списка
end;
end;
var
n, m, u, v, i, answer: longint;
begin
reset(input, 'dfs.in');
rewrite(output, 'dfs.out');
// Инициализация списков
free := 0;
fillchar(head, sizeof(head), -1);
// Читаем число вершин и число ребер
read(n, m);
for i := 1 to m do begin
read(u, v);
addEdge(u, v);
end;
fillchar(mark, sizeof(mark), false);
answer := 0;
for i := 1 to n do begin
if (not mark[i]) then begin
inc(answer);
dfs(i);
end;
end;
writeln(answer);
end.