#include<iostream>
#include<map>
#include<vector>
#include<queue>
#include<string>
#include<set>
std::map<int, std::vector<int>*> adjList;
int edgeCnt;
int vtxCnt;
std::vector<int> visited;
std::queue<int> queue;
std::set<int> looper;
int isolated = 0;//고립된 연결요소의 개수
auto contains(std::vector<int> v, int integer)
-> bool
{
int size = v.size();
for(int i = 0; i < size; ++i){ if(v.at(i) == integer){ return true; } }
return false;
}
void bfs(){
if(queue.empty()){++isolated; return;}
auto qSize = queue.size();
for(int i = 0; i < qSize; ++i){
int val = queue.front();
auto toList = adjList[val];
int tlSize = toList->size();
for(int j = 0; j < tlSize; ++j){
auto to = toList->at(j);
if(contains(visited, to)){continue;}
visited.emplace_back(to);
queue.push(to);
}
queue.pop();
}
bfs();
}
int main(){
std::cin >> vtxCnt;
std::cin >> edgeCnt;
if(vtxCnt == 1){ std::cout << "1" << std::endl; return 0; }
for(int i = 0; i < edgeCnt; ++i){
int from = 0;
int to = 0;
std::cin >> from;
std::cin >> to;
//Key가 존재하지 않을 경우(from -> to)
if(adjList.end() == adjList.find(from)){
std::vector<int>* v = new std::vector<int>;
adjList.insert(std::make_pair(from, v));
}
adjList.at(from)->emplace_back(to);
//Key가 존재하지 않을 경우(to -> from)
if(adjList.end() == adjList.find(to)){
std::vector<int>* v = new std::vector<int>;
adjList.insert(std::make_pair(to, v));
}
adjList.at(to)->emplace_back(from);
looper.insert(to);
looper.insert(from);
}
for(auto it = looper.begin(); it != looper.end(); ++it){
auto val = *it;
if(contains(visited, val)){continue;}
queue.push(val);
visited.emplace_back(val);
bfs();
}
std::cout << isolated << std::endl;
/*int pause;
std::cin >> pause;*/
}