#include <string>
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <set>
#define llint long long
#define inf 1000000000

using namespace std;

struct UnionFind{
	int size;
	vector<int> parent;
	
	UnionFind(){}
	UnionFind(int size){
		this->size = size;
		parent.resize(size+1);
		init();
	}
	void init(){
		for(int i = 0; i <= size; i++) parent[i] = i;
	}
	int root(int i){
		if(parent[i] == i) return i;
		return parent[i] = root(parent[i]);
	}
	bool same(int i, int j){
		return root(i) == root(j);
	}
	void unite(int i, int j){
		int root_i = root(i), root_j = root(j);
		if(root_i == root_j) return;
		parent[root_i] = root_j;
	}
};

struct edge{
	int to, cap, rev;
	edge(){}
	edge(int a, int b, int c){
		to = a, cap = b, rev = c;
	}
};

llint n, m;
llint x[1005], y[1005];
vector<edge> G[2005];
vector<int> vecx[1005], vecy[1005];
UnionFind uf(1005);
set<llint> s;

int S, T;
bool used[2005];

int dfs(int v, int f)
{
	used[v] = true;
	if(v == T) return f;
	
	int ret;
	for(int i = 0; i < G[v].size(); i++){
		if(used[G[v][i].to] || G[v][i].cap <= 0) continue;
		ret = dfs(G[v][i].to, min(f, G[v][i].cap));
		if(ret > 0){
			G[v][i].cap -= ret;
			G[G[v][i].to][G[v][i].rev].cap += ret;
			return ret;
		}
	}
	return 0;
}

void add_edge(int s, int t, int cap)
{
	G[s].push_back(edge(t, cap, G[t].size()));
	G[t].push_back(edge(s, 0, G[s].size()-1));
}

int main(void)
{
	cin >> n >> m;
	for(int i = 1; i <= m; i++) cin >> x[i] >> y[i];
	
	for(int i = 1; i <= m; i++){
		vecx[x[i]].push_back(i);
		vecy[y[i]].push_back(i);
	}
	uf.init();
	for(int i = 1; i <= n; i++){
		for(int j = 1; j < vecx[i].size(); j++){
			uf.unite(vecx[i][j-1], vecx[i][j]);
		}
		for(int j = 1; j < vecy[i].size(); j++){
			uf.unite(vecy[i][j-1], vecy[i][j]);
		}
	}
	for(int i = 1; i <= m; i++) s.insert(uf.root(i));
	llint ansy = m - s.size();
	
	S = 2*n+1, T = 2*n+2;
	for(int i = 1; i <= m; i++){
		add_edge(x[i], n+y[i], 1);
	}
	for(int i = 1; i <= n; i++){
		add_edge(S, i, 1);
		add_edge(n+i, T, 1);
	}
	
	int ansx = 0, flow;
	while(1){
		for(int i = 1; i <= T; i++) used[i] = false;
		flow = dfs(S, inf);
		if(flow <= 0) break;
		ansx += flow;
	}
	ansx = m - ansx;
	
	cout << ansx << " " << ansy << endl;
	
	return 0;
}
