#include <bits/stdc++.h>
#pragma GCC target("avx2")
#pragma GCC optimization("O3")
#pragma GCC optimization("unroll-loops")
using namespace std;
template <typename T>
void DBG(const char* name, T&& H) {
  cerr << name << " = " << H << ')' << '\n';
}
template <typename T, typename... Args>
void DBG(const char* names, T&& H, Args&&... args) {
  const char* NEXT = strchr(names + 1, ',');
  cerr.write(names, NEXT - names) << " = " << H << " |";
  DBG(NEXT + 1, args...);
}
using ll = long long;
using ld = long double;
const long long mod = 1e9 + 7;
const long double PI = acos(-1.0);
const long long INF = 4e18;
const int maxN = 4e5 + 1;
int N, M, componentSize;
vector<pair<int, int>> edge;
vector<pair<int, int>> ans;
vector<vector<pair<int, int>>> graph(maxN);
vector<bool> isBridge(maxN, false), vis(maxN, false);
template <typename second, typename T>
void Bridges(second start) {
  int sz = N + 1;
  vector<bool> isVisited(sz, false);
  vector<second> tIn(sz, -1), tLow(sz, -1);
  second timer = 0;
  function<void(second, second)> dfs = [&](second node, second parent) {
    isVisited[node] = true;
    tIn[node] = tLow[node] = timer++;
    int parentNotVisited = 1;
    for (auto i : graph[node]) {
      if ((i.first == parent) && parentNotVisited) {
        parentNotVisited = 0;
        continue;
      }
      if (isVisited[i.first])
        tLow[node] = min(tLow[node], tIn[i.first]);
      else {
        dfs(i.first, node);
        tLow[node] = min(tLow[node], tLow[i.first]);
        if (tLow[i.first] > tIn[node]) {
          isBridge[i.second] = true;
        }
      }
    }
  };
  for (second i = start; i < sz; i++) {
    if (!isVisited[i]) dfs(i, -1);
  }
}
void dfs1(int node) {
  componentSize++;
  vis[node] = 1;
  for (auto i : graph[node]) {
    if (isBridge[i.second]) continue;
    if (vis[i.first]) continue;
    dfs1(i.first);
  }
}
void dfs2(int node, int parent) {
  vis[node] = 1;
  for (auto i : graph[node]) {
    if (i.first == parent) continue;
    if (vis[i.first]) {
      if (ans[i.second].first == -1) ans[i.second] = {node, i.first};
      continue;
    }
    if (isBridge[i.second])
      ans[i.second] = {i.first, node};
    else
      ans[i.second] = {node, i.first};
    dfs2(i.first, node);
  }
}
void Solve() {
  cin >> N >> M;
  edge.resize(M);
  ans.assign(M, {-1, -1});
  for (int i = 0; i < M; i++) {
    cin >> edge[i].first >> edge[i].second;
    graph[edge[i].first].push_back({edge[i].second, i});
    graph[edge[i].second].push_back({edge[i].first, i});
  }
  Bridges<int, int>(1);
  int maxSize = 0, node = -1;
  for (int i = 1; i <= N; i++) {
    if (!vis[i]) {
      componentSize = 0;
      dfs1(i);
      if (componentSize >= maxSize) {
        maxSize = componentSize;
        node = i;
      }
    }
  }
  vis.assign(maxN, false);
  dfs2(node, -1);
  cout << maxSize << '\n';
  for (auto i : ans) {
    cout << i.first << " " << i.second << '\n';
  }
}
int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  int tt = 1;
  while (tt--) {
    Solve();
  }
  return 0;
}
