package main
import (
"bufio"
"io"
"os"
"strconv"
)
type FastScanner struct {
data []byte
idx int
}
func (fs *FastScanner) nextInt() int {
n := len(fs.data)
for fs.idx < n {
c := fs.data[fs.idx]
if c >= '0' && c <= '9' {
break
}
fs.idx++
}
val := 0
for fs.idx < n {
c := fs.data[fs.idx]
if c < '0' || c > '9' {
break
}
val = val*10 + int(c-'0')
fs.idx++
}
return val
}
type Edge struct {
to int32
id int32
}
var (
tree [][]int
weights []int
)
func branchDP(u, p int) (int, int64) {
sum := weights[u]
var pairs int64
for _, v := range tree[u] {
if v == p {
continue
}
s, pr := branchDP(v, u)
sum += s
pairs += pr
}
pairs += int64(weights[u]) * int64(sum)
return sum, pairs
}
func shiftOr(bits []uint64, shift int) {
word := shift >> 6
bit := uint(shift & 63)
if bit == 0 {
for i := len(bits) - 1; i >= word; i-- {
bits[i] |= bits[i-word]
}
} else {
r := 64 - bit
for i := len(bits) - 1; i > word; i-- {
bits[i] |= (bits[i-word] << bit) | (bits[i-word-1] >> r)
}
bits[word] |= bits[0] << bit
}
}
func main() {
data, _ := io.ReadAll(os.Stdin)
fs := &FastScanner{data: data}
n := fs.nextInt()
m := fs.nextInt()
eu := make([]int32, m)
ev := make([]int32, m)
deg := make([]int, n)
for i := 0; i < m; i++ {
u := fs.nextInt() - 1
v := fs.nextInt() - 1
eu[i] = int32(u)
ev[i] = int32(v)
deg[u]++
deg[v]++
}
adj := make([][]Edge, n)
for i := 0; i < n; i++ {
adj[i] = make([]Edge, 0, deg[i])
}
for i := 0; i < m; i++ {
u := int(eu[i])
v := int(ev[i])
adj[u] = append(adj[u], Edge{to: int32(v), id: int32(i)})
adj[v] = append(adj[v], Edge{to: int32(u), id: int32(i)})
}
tin := make([]int, n)
low := make([]int, n)
vis := make([]bool, n)
isBridge := make([]bool, m)
timer := 0
var dfsBridge func(int, int)
dfsBridge = func(u, pe int) {
vis[u] = true
tin[u] = timer
low[u] = timer
timer++
for _, e := range adj[u] {
v := int(e.to)
id := int(e.id)
if id == pe {
continue
}
if vis[v] {
if tin[v] < low[u] {
low[u] = tin[v]
}
} else {
dfsBridge(v, id)
if low[v] < low[u] {
low[u] = low[v]
}
if low[v] > tin[u] {
isBridge[id] = true
}
}
}
}
dfsBridge(0, -1)
comp := make([]int, n)
for i := 0; i < n; i++ {
comp[i] = -1
}
var compWeights []int
stack := make([]int, 0, n)
for i := 0; i < n; i++ {
if comp[i] != -1 {
continue
}
id := len(compWeights)
comp[i] = id
stack = stack[:0]
stack = append(stack, i)
cnt := 0
for len(stack) > 0 {
u := stack[len(stack)-1]
stack = stack[:len(stack)-1]
cnt++
for _, e := range adj[u] {
if isBridge[e.id] {
continue
}
v := int(e.to)
if comp[v] == -1 {
comp[v] = id
stack = append(stack, v)
}
}
}
compWeights = append(compWeights, cnt)
}
k := len(compWeights)
tree = make([][]int, k)
weights = make([]int, k)
copy(weights, compWeights)
for i := 0; i < m; i++ {
if !isBridge[i] {
continue
}
a := comp[int(eu[i])]
b := comp[int(ev[i])]
tree[a] = append(tree[a], b)
tree[b] = append(tree[b], a)
}
totalW := n
bitsLen := (totalW >> 6) + 1
var ans int64
for r := 0; r < k; r++ {
bits := make([]uint64, bitsLen)
bits[0] = 1
var base int64
sideSum := 0
for _, nb := range tree[r] {
s, p := branchDP(nb, r)
sideSum += s
base += p
shiftOr(bits, s)
}
best := int64(0)
maxX := totalW - weights[r]
for x := 0; x <= maxX; x++ {
if ((bits[x>>6] >> uint(x&63)) & 1) == 0 {
continue
}
val := int64(weights[r]+x) * int64(totalW-x)
if val > best {
best = val
}
}
cur := base + best
if cur > ans {
ans = cur
}
}
out := bufio.NewWriterSize(os.Stdout, 1<<20)
out.WriteString(strconv.FormatInt(ans, 10))
out.WriteByte('\n')
out.Flush()
}