#include <bits/stdc++.h>
void Get(int &T) {
  char C;
  bool F = 0;
  for (; C = getchar(), C < '0' || C > '9';)
    if (C == '-') F = 1;
  for (T = C - '0'; C = getchar(), C >= '0' && C <= '9'; T = T * 10 + C - '0')
    ;
  F && (T = -T);
}
int N, M;
struct E {
  int V, Next;
} Edge[600005];
int EdgeTop;
int Head[100005];
void Add(int U, int V) {
  Edge[++EdgeTop] = (E){V, Head[U]};
  Head[U] = EdgeTop;
}
int D[100005];
void Init() {
  Get(N);
  Get(M);
  for (int i = 1, U, V; i <= M; i++) {
    Get(U);
    Get(V);
    Add(U, V);
    Add(V, U);
    D[U]++;
    D[V]++;
  }
}
bool Visited[100005];
int Fa[100005];
int Depth[100005];
int Ans1, Ans2;
int StackX[100005];
int Stacki[100005];
void DFS(int X) {
  int Top = 1, i;
  StackX[1] = X;
Call:
  X = StackX[Top];
  Visited[X] = 1;
  for (i = Head[X]; i; i = Edge[i].Next) {
    if (Fa[X] == Edge[i].V) continue;
    if (Visited[Edge[i].V] == 0) {
      Fa[Edge[i].V] = X;
      Depth[Edge[i].V] = Depth[X] + 1;
      StackX[Top + 1] = Edge[i].V;
      Stacki[Top] = i;
      Top++;
      goto Call;
    Return:
      Top--;
      X = StackX[Top];
      i = Stacki[Top];
    } else {
      if (Depth[Edge[i].V] > Depth[X]) continue;
      int Cnt = 0;
      for (int k = X;; k = Fa[k]) {
        if (D[k] > 2) Cnt++;
        if (Edge[i].V == k) break;
        if (k == 0) break;
      }
      if (Cnt <= 1) Ans1++;
    }
  }
  if (Top >= 2) goto Return;
}
void Work() {
  for (int i = 1; i <= N; i++) Ans1 += ((D[i] & 1) == 1);
  Ans1 >>= 1;
  Ans2 = M;
  for (int i = 1; i <= N; i++)
    if (Visited[i] == 0) {
      DFS(i);
    }
}
void Output() { printf("%d %d\n", Ans1, Ans2); }
int main() {
  Init();
  Work();
  Output();
  return 0;
}
