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)}
import java.util.List;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.ArrayList;
import java.io.BufferedReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.StringTokenizer;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
	public static void main(String[] args) {
		InputStream inputStream = System.in;
		OutputStream outputStream = System.out;
		InputReader in = new InputReader(inputStream);
		PrintWriter out = new PrintWriter(outputStream);
		TaskE solver = new TaskE();
		solver.solve(1, in, out);
		out.close();
	}
}

class TaskE {
    private int n;
    private boolean[][] graph;
    private boolean[][] isBridge;
    private int[] inTime;
    private int[] lowLink;
    private int travelTime = 0;

    public void solve(int testNumber, InputReader in, PrintWriter out) {
        n = in.nextInt();
        graph = new boolean[n][n];
        int m = in.nextInt();
        for (int i = 0; i < m; ++i) {
            int u = in.nextInt() - 1;
            int v = in.nextInt() - 1;
            graph[u][v] = graph[v][u] = true;
        }
        isBridge = new boolean[n][n];
        inTime = new int[n];
        lowLink = new int[n];
        Arrays.fill(inTime, -1);
        dfs(0);
        DisjointSet sets = new DisjointSet(n);
        for (int u = 0; u < n; ++u)
            for (int v = 0; v < n; ++v)
                if (graph[u][v] && !isBridge[u][v])
                    sets.joinSet(u, v);
        int[] id = new int[n];
        for (int i = 0, j = 0; i < n; ++i)
            if (sets.getSet(i) == i)
                id[i] = j++;
        Vertex[] vertices = new Vertex[sets.countSets()];
        for (int i = 0; i < vertices.length; ++i)
            vertices[i] = new Vertex();
        for (int i = 0; i < n; ++i)
            ++vertices[id[sets.getSet(i)]].weight;
        for (int u = 0; u < n; ++u)
            for (int v = u + 1; v < n; ++v)
                if (isBridge[u][v]) {
                    Vertex foo = vertices[id[sets.getSet(u)]];
                    Vertex bar = vertices[id[sets.getSet(v)]];
                    foo.adj.add(bar);
                    bar.adj.add(foo);
                }
        int answer = 0;
        for (Vertex root : vertices) {
            for (Vertex vertex : vertices) vertex.parent = null;
            answer = Math.max(answer, root.dfs());
        }
        out.println(answer);
    }

    private void dfs(int u) {
        lowLink[u] = inTime[u] = travelTime++;
        for (int v = 0; v < n; ++v) if (graph[u][v]) {
            graph[v][u] = false;
            if (inTime[v] == -1) {
                dfs(v);
                lowLink[u] = Math.min(lowLink[u], lowLink[v]);
                if (lowLink[v] >= inTime[v])
                    isBridge[u][v] = isBridge[v][u] = true;
            } else {
                lowLink[u] = Math.min(lowLink[u], inTime[v]);
            }
        }
    }

    private class Vertex {
        public List<Vertex> adj = new ArrayList<>();
        public int weight = 0;
        public Vertex parent;
        public int subtreeSize;

        public int dfs() {
            int total = 0;
            subtreeSize = weight;
            for (Vertex child : adj) {
                if (child == parent) continue;
                child.parent = this;
                total += child.dfs();
                subtreeSize += child.subtreeSize;
            }
            total += subtreeSize * weight;
            if (parent == null) {
                boolean[] possible = new boolean[subtreeSize - weight + 1];
                possible[0] = true;
                int sum = 0;
                for (Vertex child : adj) {
                    sum += child.subtreeSize;
                    for (int i = sum; i >= child.subtreeSize; --i)
                        possible[i] |= possible[i - child.subtreeSize];
                }
                int delta = 0;
                for (int i = 0; i <= sum; ++i)
                    if (possible[i])
                        delta = Math.max(delta, i * (sum - i));
                total += delta;
            }
            return total;
        }
    }
}

class InputReader {
    private BufferedReader reader;
    private StringTokenizer tokenizer;

    public InputReader(InputStream inputStream) {
        reader = new BufferedReader(new InputStreamReader(inputStream));
        tokenizer = null;
    }

    public String next() {
        while (tokenizer == null || !tokenizer.hasMoreTokens())
            try {
                tokenizer = new StringTokenizer(reader.readLine());
            } catch (IOException e) {
                throw new RuntimeException();
            }
        return tokenizer.nextToken();
    }

    public int nextInt() {
        return Integer.parseInt(next());
    }

}

class DisjointSet {
    private final Listener listener;
    private final int[] label;
    private int numSets;

    public DisjointSet(int n, Listener listener) {
        label = new int[n];
        Arrays.fill(label, -1);
        numSets = n;
        this.listener = listener;
    }

    public DisjointSet(int n) {
        this(n, null);
    }

    public int getSet(int u) {
        if (label[u] < 0) return u;
        return label[u] = getSet(label[u]);
    }

    public boolean joinSet(int u, int v) {
        u = getSet(u);
        v = getSet(v);
        if (u == v) return false;
        if (label[u] < label[v]) {
            int tmp = u;
            u = v;
            v = tmp;
        }
        label[v] += label[u];
        label[u] = v;
        if (listener != null) listener.joined(u, v);
        --numSets;
        return true;
    }

    public int countSets() {
        return numSets;
    }

    public interface Listener {
        public void joined(int joinedRoot, int root);
    }
}

