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;
struct NODE;
struct EDGE;
typedef struct NODE {
  int no;
  EDGE *head;
  int DFN, low;
  NODE *bcc;
  bool vis;
  int size, W;
} * PNODE;
typedef struct EDGE {
  NODE *a, *b;
  EDGE *next;
} * PEDGE;
class GRAPH {
 private:
  std::stack<PNODE> oplst;
  NODE node[2005], node2[2005];
  EDGE edge[4000005], edge2[4000005];
  bool e2map[2005][2005];
  int ncnt, ecnt, bcnt, becnt;
  void Tarjan(PNODE cur, int dep, PNODE par) {
    PEDGE j;
    PNODE ed;
    cur->DFN = cur->low = dep;
    cur->vis = true;
    oplst.push(cur);
    for (j = cur->head; j; j = j->next) {
      ed = j->b;
      if (!ed->vis) {
        Tarjan(ed, dep + 1, cur);
        cur->low = std::min(cur->low, ed->low);
      } else if (ed != par) {
        cur->low = std::min(cur->low, ed->DFN);
      }
    }
    if (cur->DFN == cur->low) {
      bcnt++;
      cur->bcc = node2 + bcnt;
      node2[bcnt].no = bcnt;
      node2[bcnt].size = 1;
      while (oplst.top() != cur) {
        oplst.top()->bcc = node2 + bcnt;
        oplst.pop();
        node2[bcnt].size++;
      }
      oplst.pop();
    }
  }

 public:
  void Decompose() {
    int i, j;
    bcnt = 0;
    while (!oplst.empty()) oplst.pop();
    memset(e2map, 0, sizeof(e2map));
    for (i = 1; i <= ncnt; i++) {
      if (!node[i].vis) Tarjan(node + i, 1, nullptr);
    }
    for (i = 0; i < ecnt; i++) {
      if (edge[i].a->bcc != edge[i].b->bcc) {
        e2map[edge[i].a->bcc->no][edge[i].b->bcc->no] = true;
      }
    }
    for (i = 1; i <= bcnt; i++) {
      node2[i].head = nullptr;
    }
    for (i = 1; i <= bcnt; i++) {
      for (j = 1; j <= bcnt; j++) {
        if (e2map[i][j]) {
          DoAdd(node2 + i, node2 + j, edge2, becnt);
        }
      }
    }
  }
  void Init(int n) {
    ncnt = n;
    ecnt = 0;
    for (int i = 1; i <= n; i++) {
      node[i].head = nullptr;
      node[i].no = i;
      node[i].vis = false;
    }
  }
  static void DoAdd(PNODE p, PNODE q, EDGE edge[], int &ecnt) {
    edge[ecnt].a = p;
    edge[ecnt].b = q;
    edge[ecnt].next = p->head;
    p->head = edge + ecnt;
    ecnt++;
  }
  void AddEdge(int a, int b) {
    DoAdd(node + a, node + b, edge, ecnt);
    DoAdd(node + b, node + a, edge, ecnt);
  }
  bool achive[2005];
  int Ws[2005];
  int DFS(PNODE cur, PNODE par, int &accum) {
    PEDGE j;
    cur->W = cur->size;
    for (j = cur->head; j; j = j->next) {
      if (j->b != par) {
        cur->W += DFS(j->b, cur, accum);
      }
    }
    accum += cur->W * cur->size;
    return cur->W;
  }
  int CalcSub(PNODE root) {
    int ret = 0, i, j, basic = 0;
    int wpos = 0, out;
    memset(achive, 0, sizeof(achive));
    DFS(root, nullptr, basic);
    basic = basic - root->W * root->size + root->size * root->size;
    for (PEDGE pj = root->head; pj; pj = pj->next) {
      Ws[wpos++] = pj->b->W;
    }
    achive[0] = true;
    for (j = 0; j < wpos; j++) {
      for (i = root->W; i >= 0; i--) {
        if (achive[i]) {
          achive[i + Ws[j]] = true;
        }
      }
    }
    Ws[wpos] = -1;
    for (i = 0; i <= root->W; i++) {
      if (achive[i]) {
        out = root->W - root->size - i;
        ret = max(ret, (i + root->size) * (out + root->size) -
                           root->size * root->size);
      }
    }
    return ret + basic;
  }
  int Calc() {
    int i;
    int ret = 0;
    for (i = 1; i <= bcnt; i++) {
      ret = max(ret, CalcSub(node2 + i));
    }
    return ret;
  }
} tree;
int main() {
  int n, m, a, b;
  scanf("%d%d", &n, &m);
  tree.Init(n);
  while (m--) {
    scanf("%d%d", &a, &b);
    tree.AddEdge(a, b);
  }
  tree.Decompose();
  printf("%d\n", tree.Calc());
  return 0;
}
