Imagine a city with n junctions and m streets. Junctions are numbered from 1 to n.

In order to increase the traffic flow, mayor of the city has decided to make each street one-way. This means in the street between junctions u and v, the traffic moves only from u to v or only from v to u. 

The problem is to direct the traffic flow of streets in a way that maximizes the number of pairs (u, v) where 1 ≤ u, v ≤ n and it is possible to reach junction v from u by passing the streets in their specified direction. Your task is to find out maximal possible number of such pairs.

Input

The first line of input contains integers n and m, (<image>), denoting the number of junctions and streets of the city.

Each of the following m lines contains two integers u and v, (u ≠ v), denoting endpoints of a street in the city.

Between every two junctions there will be at most one street. It is guaranteed that before mayor decision (when all streets were two-way) it was possible to reach each junction from any other junction.

Output

Print the maximal number of pairs (u, v) such that that it is possible to reach junction v from u after directing the streets.

Examples

Input

5 4
1 2
1 3
1 4
1 5


Output

13


Input

4 5
1 2
2 3
3 4
4 1
1 3


Output

16


Input

2 1
1 2


Output

3


Input

6 7
1 2
2 3
1 3
1 4
4 5
5 6
6 4


Output

27

Note

In the first sample, if the mayor makes first and second streets one-way towards the junction 1 and third and fourth streets in opposite direction, there would be 13 pairs of reachable junctions: {(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (2, 1), (3, 1), (1, 4), (1, 5), (2, 4), (2, 5), (3, 4), (3, 5)}
#include <bits/stdc++.h>
using namespace std;
const int MN = 2011;
int V;
vector<int> G[MN];
struct UndirectedDfs {
  vector<int> low, num, parent;
  vector<bool> articulation;
  int counter, root, children;
  vector<pair<int, int> > bridges;
  vector<int> cuts;
  UndirectedDfs()
      : low(V, 0),
        num(V, -1),
        parent(V, 0),
        articulation(V, false),
        counter(0),
        children(0) {
    for (int i = 0; i < V; ++i)
      if (num[i] == -1) {
        root = i;
        children = 0;
        dfs(i);
        articulation[root] = (children > 1);
      }
    for (int i = 0; i < V; ++i)
      if (articulation[i]) cuts.push_back(i);
  }

 private:
  void dfs(int u) {
    low[u] = num[u] = counter++;
    for (int j = 0; j < G[u].size(); ++j) {
      int v = G[u][j];
      if (num[v] == -1) {
        parent[v] = u;
        if (u == root) children++;
        dfs(v);
        if (low[v] >= num[u]) articulation[u] = true;
        if (low[v] > num[u]) bridges.push_back(make_pair(u, v));
        low[u] = min(low[u], low[v]);
      } else if (v != parent[u])
        low[u] = min(low[u], num[v]);
    }
  }
};
struct DSU {
  int lab[MN];
  void init() { memset(lab, -1, sizeof lab); }
  int getRoot(int u) {
    if (lab[u] < 0) return u;
    return lab[u] = getRoot(lab[u]);
  }
  bool merge(int u, int v) {
    u = getRoot(u);
    v = getRoot(v);
    if (u == v) return false;
    if (lab[u] > lab[v]) swap(u, v);
    lab[u] += lab[v];
    lab[v] = u;
    return true;
  }
};
int weight[MN], sz[MN];
vector<int> ke[MN];
int dfs(int u, int fu) {
  int res = weight[u] * weight[u];
  sz[u] = weight[u];
  vector<int> x;
  for (int v : ke[u]) {
    if (v == fu) continue;
    res += dfs(v, u);
    sz[u] += sz[v];
    res += sz[v] * weight[u];
    if (fu == -1) x.push_back(sz[v]);
  }
  if (fu == -1) {
    int sumx = 0;
    for (int t : x) sumx += t;
    vector<vector<bool> > f;
    f.resize(x.size() + 1);
    for (int i = 0, _a = (f.size()); i < _a; i++) {
      f[i].resize(sumx + 1);
      for (int j = 0, _a = (f[i].size()); j < _a; j++) f[i][j] = false;
    }
    f[0][0] = true;
    for (int i = 0, _a = (x.size()); i < _a; i++)
      for (int cur = (0), _b = (sumx); cur <= _b; cur++)
        if (f[i][cur]) {
          f[i + 1][cur] = true;
          f[i + 1][cur + x[i]] = true;
        }
    int best = 0;
    for (int in = (0), _b = (sumx); in <= _b; in++)
      if (f[x.size()][in]) {
        int out = sumx - in;
        best = max(best, in * out);
      }
    res += best;
  }
  return res;
}
int main() {
  ios ::sync_with_stdio(false);
  cout << (fixed) << setprecision(9);
  int m;
  while (cin >> V >> m) {
    for (int i = 0, _a = (V); i < _a; i++) {
      G[i].clear();
      ke[i].clear();
    }
    while (m--) {
      int u, v;
      cin >> u >> v;
      --u;
      --v;
      G[u].push_back(v);
      G[v].push_back(u);
    }
    UndirectedDfs tree;
    set<pair<int, int> > bridges;
    for (auto e : tree.bridges) {
      bridges.insert(e);
      bridges.insert(make_pair(e.second, e.first));
    }
    DSU dsu;
    dsu.init();
    for (int u = 0, _a = (V); u < _a; u++)
      for (int v : G[u]) {
        if (bridges.count(make_pair(u, v))) continue;
        dsu.merge(u, v);
      }
    for (int i = 0, _a = (V); i < _a; i++)
      if (dsu.lab[i] < 0)
        weight[i] = -dsu.lab[i];
      else
        weight[i] = 0;
    for (int u = 0, _a = (V); u < _a; u++)
      for (int v : G[u]) {
        int i = dsu.getRoot(u);
        int j = dsu.getRoot(v);
        if (i != j) {
          ke[i].push_back(j);
        }
      }
    int res = 0;
    for (int u = 0, _a = (V); u < _a; u++)
      if (dsu.lab[u] < 0) {
        res = max(res, dfs(u, -1));
      }
    cout << res << endl;
  }
  return 0;
}
