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;
int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
struct {
  int n, m;
  int fst[2000];
  int to[4000000];
  int nxt[4000000];
  int nid;
  int id[2000];
  int id2node[2000];
  int par[2000];
  int paredge[2000];
  bool been[2000];
  bool isbridge[2000000];
  int ncomp;
  int comp[2000];
  void init(int n) {
    this->n = n;
    m = 0;
    for (int i = (0); i < (n); ++i) fst[i] = -1;
  }
  void addedge(int a, int b) {
    to[2 * m + 0] = b;
    nxt[2 * m + 0] = fst[a];
    fst[a] = 2 * m + 0;
    to[2 * m + 1] = a;
    nxt[2 * m + 1] = fst[b];
    fst[b] = 2 * m + 1;
    ++m;
  }
  void iddfs(int at) {
    id[at] = nid;
    id2node[nid] = at;
    ++nid;
    for (int x = fst[at]; x != -1; x = nxt[x])
      if (id[to[x]] == -1) {
        par[to[x]] = at;
        paredge[to[x]] = x ^ 1;
        iddfs(to[x]);
      }
  }
  void calcbridges() {
    nid = 0;
    for (int i = (0); i < (n); ++i) par[i] = paredge[i] = -1, id[i] = -1;
    iddfs(0);
    for (int i = (0); i < (m); ++i) isbridge[i] = true;
    for (int i = (0); i < (n); ++i) been[i] = false;
    for (int i = (0); i < (n); ++i) {
      int at = id2node[i];
      been[at] = true;
      for (int x = fst[at]; x != -1; x = nxt[x]) {
        if (to[x] == par[at] || par[to[x]] == at) continue;
        if (id[to[x]] < id[at]) continue;
        isbridge[x >> 1] = false;
        for (int y = to[x]; !been[y] && y != at; y = par[y])
          been[y] = true, isbridge[paredge[y] >> 1] = false;
      }
    }
  }
  void compdfs(int at, int c) {
    comp[at] = c;
    for (int x = fst[at]; x != -1; x = nxt[x])
      if (!isbridge[x >> 1] && comp[to[x]] == -1) compdfs(to[x], c);
  }
  void calccomponents() {
    ncomp = 0;
    for (int i = (0); i < (n); ++i) comp[i] = -1;
    for (int i = (0); i < (n); ++i)
      if (comp[i] == -1) compdfs(i, ncomp++);
  }
} graph;
struct {
  int n, m;
  int w[2000], wsum;
  int fst[2000];
  int to[4000];
  int nxt[4000];
  int sz[4000];
  int res[4000];
  bool can[2001];
  void addedge(int a, int b) {
    to[2 * m + 0] = b;
    nxt[2 * m + 0] = fst[a];
    fst[a] = 2 * m + 0;
    to[2 * m + 1] = a;
    nxt[2 * m + 1] = fst[b];
    fst[b] = 2 * m + 1;
    ++m;
  }
  void createfromgraph() {
    n = graph.ncomp;
    m = 0;
    for (int i = (0); i < (n); ++i) w[i] = 0, fst[i] = -1;
    wsum = 0;
    for (int i = (0); i < (graph.n); ++i) ++w[graph.comp[i]], ++wsum;
    for (int i = (0); i < (graph.m); ++i)
      if (graph.isbridge[i])
        addedge(graph.comp[graph.to[2 * i + 1]],
                graph.comp[graph.to[2 * i + 0]]);
  }
  void calcsubtree(int x) {
    if (sz[x] != -1 || res[x] != -1) return;
    int at = to[x];
    sz[x] = w[at];
    res[x] = w[at] * w[at];
    for (int y = fst[at]; y != -1; y = nxt[y])
      if (y != (x ^ 1)) {
        calcsubtree(y);
        sz[x] += sz[y];
        res[x] += res[y] + sz[y] * w[at];
      }
  }
  void calcsubtrees() {
    for (int i = (0); i < (2 * m); ++i) sz[i] = res[i] = -1;
    for (int i = (0); i < (2 * m); ++i) calcsubtree(i);
  }
  int calc(int at) {
    memset(can, false, sizeof(can));
    can[0] = true;
    int ret = w[at] * wsum;
    for (int x = fst[at]; x != -1; x = nxt[x]) {
      ret += res[x];
      for (int i = wsum - w[at]; i >= 0; --i)
        if (can[i]) can[i + sz[x]] = true;
    }
    int extra = 0;
    for (int i = (0); i <= (wsum); ++i)
      if (can[i] && i * (wsum - w[at] - i) > extra)
        extra = i * (wsum - w[at] - i);
    return ret + extra;
  }
  int calcbest() {
    int ret = 0;
    for (int i = (0); i < (n); ++i) {
      int cur = calc(i);
      if (cur > ret) ret = cur;
    }
    return ret;
  }
} tree;
void input() {
  int n, m;
  scanf("%d%d", &n, &m);
  graph.init(n);
  for (int i = (0); i < (m); ++i) {
    int a, b;
    scanf("%d%d", &a, &b);
    --a, --b;
    graph.addedge(a, b);
  }
  graph.calcbridges();
  graph.calccomponents();
  tree.createfromgraph();
  tree.calcsubtrees();
  int ret = tree.calcbest();
  printf("%d\n", ret);
}
void run() { input(); }
int main() {
  run();
  return 0;
}
