#include <bits/stdc++.h>
typedef long long i64;
using std::cout;
using std::endl;
using std::cin;

using namespace std;
struct UnionFind
{
  vector< int > data;
 
  UnionFind(int sz)
  {
    data.assign(sz, -1);
  }
 
  bool unite(int x, int y)
  {
    x = find(x), y = find(y);
    if(x == y) return (false);
    if(data[x] > data[y]) swap(x, y);
    data[x] += data[y];
    data[y] = x;
    return (true);
  }
 
  int find(int k)
  {
    if(data[k] < 0) return (k);
    return (data[k] = find(data[k]));
  }
 
  int size(int k)
  {
    return (-data[find(k)]);
  }
};
 
struct LowLink
{
  UnionFind uf;
  vector< vector< int > > g;
  vector< int > used, ord, low, parent;
 
  LowLink(size_t v) : g(v), used(v, 0), ord(v), low(v), uf(v), parent(v, -1) {}
 
  virtual void add_edge(int x, int y)
  {
    g[x].push_back(y);
    g[y].push_back(x);
  }
 
  void dfs(int idx, int &k, int par = -1)
  {
    used[idx] = true;
    ord[idx] = k++;
    low[idx] = ord[idx];
 
    for(auto &to : g[idx]) {
      if(!used[to]) {
        dfs(to, k, idx);
        low[idx] = min(low[idx], low[to]);
        parent[to] = idx;
        if(ord[idx] >= low[to]) uf.unite(idx, to);
      } else if(to != par) {
        low[idx] = min(low[idx], ord[to]);
      }
    }
  }
 
  void dfs()
  {
    int k = 0;
    for(int i = 0; i < g.size(); i++) {
      if(used[i]) continue;
      dfs(i, k);
    }
  }
};
 
struct BiConnectedComponents : LowLink
{
  vector< pair< int, int > > edges;
  vector< int > comp;
 
  BiConnectedComponents(size_t v) : LowLink(v), comp(v) {}
 
  void add_edge(int x, int y)
  {
    LowLink::add_edge(x, y);
    edges.push_back(minmax(x, y));
  }
 
  int operator[](int k)
  {
    return (comp[k]);
  }
 
  vector< pair< int, int > > build(vector< vector< int > > &t)
  {
    LowLink::dfs();
    int ptr = 0;
    vector< int > cc(g.size());
    for(int i = 0; i < g.size(); i++) {
      if(i == uf.find(i)) cc[i] = ptr++;
    }
 
    t.resize(ptr);
    for(int i = 0; i < g.size(); i++) {
      comp[i] = cc[uf.find(i)];
    }
    vector< pair< int, int > > vs;
    for(auto &e : edges) {
      int x = comp[e.first], y = comp[e.second];
      if(x == y) continue;
      vs.emplace_back(e.first, e.second);
      t[x].push_back(y);
      t[y].push_back(x);
    }
    sort(begin(vs), end(vs));
    return (vs);
  }
};
 

int n, m;
std::vector<int> w;
std::vector<std::vector<int>> g, dp, tree;
void solve(int v = 0, int par = -1) {
	dp[v][1] = w[v];
	dp[v][0] = 0;
	
	for(auto e : tree[v]) {
		if(e == par) continue; solve(e, v);
		dp[v][1] += dp[e][0];
		dp[v][0] += std::max(dp[e][0], dp[e][1]);
	}
};

int main() {
	cin >> n >> m; g.resize(n);
	BiConnectedComponents bcc(n);
	for(int i = 0; i < m; i++) {
		int a, b; cin >> a >> b;
		bcc.add_edge(a, b);
	}
	bcc.build(tree);
	
	w.resize(tree.size(), 0);
	for(int i = 0; i < n; i++) w[bcc[i]]++;
	
	int ans = 0;
	dp.resize(tree.size(), std::vector<int>(2, -1));
	for(int i = 0; i < tree.size(); i++) {
		if(~dp[i][0]) continue; solve(i);
		ans += std::max(dp[i][0], dp[i][1]);
	}
	cout << ans << endl;
	return 0;
}

