#include <bits/stdc++.h>
using namespace std;
template <class X, class Y>
void minimize(X &x, const Y &y) {
  if (x > y) x = y;
}
template <class X, class Y>
void maximize(X &x, const Y &y) {
  if (x < y) x = y;
}
class DisjointSet {
 private:
  vector<int> label;

 public:
  DisjointSet() {}
  DisjointSet(int n) { label.assign(n + 7, -1); }
  int find(int x) {
    if (label[x] < 0) return (x);
    label[x] = find(label[x]);
    return (label[x]);
  }
  bool join(int a, int b) {
    int x = find(a);
    int y = find(b);
    if (x == y) return (false);
    if (label[x] > label[y]) swap(x, y);
    label[x] += label[y];
    label[y] = x;
    return (true);
  }
  int getSize(int x) { return (-label[find(x)]); }
};
int cntEdge[200200];
int n, m;
pair<int, int> edge[200200];
void init(void) {
  scanf("%d%d", &n, &m);
  for (int i = (1), _b = (m); i <= _b; i = i + 1)
    scanf("%d%d", &edge[i].first, &edge[i].second);
}
void process(void) {
  DisjointSet dsu(n);
  for (int i = (1), _b = (m); i <= _b; i = i + 1)
    dsu.join(edge[i].first, edge[i].second);
  for (int i = (1), _b = (m); i <= _b; i = i + 1)
    cntEdge[dsu.find(edge[i].first)]++;
  int numTree = 0;
  for (int i = (1), _b = (n); i <= _b; i = i + 1)
    if (dsu.find(i) == i && cntEdge[i] < dsu.getSize(i)) numTree++;
  printf("%d\n", numTree);
}
int main(void) {
  init();
  process();
  return 0;
}
