#![allow(unused_imports, unused_variables, dead_code, non_snake_case, unused_macros)]
use std::io::{stdin, Read, StdinLock};
use std::str::FromStr;
use std::fmt::*;
use std::str::*;
use std::cmp::*;
use std::collections::*;

fn getline() -> String{
    let mut res = String::new();
    std::io::stdin().read_line(&mut res).ok();
    res
}

macro_rules! readl {
    ($t: ty) => {
        {
            let s = getline();
            s.trim().parse::<$t>().unwrap()
        }
    };
    ($( $t: ty),+ ) => {
        {
            let s = getline();
            let mut iter = s.trim().split(' ');
            ($(iter.next().unwrap().parse::<$t>().unwrap(),)*) 
        }
    };
}

macro_rules! readlvec {
    ($t: ty) => {
        {
            let s = getline();
            let iter = s.trim().split(' ');
            iter.map(|x| x.parse().unwrap()).collect::<Vec<$t>>()
        }
    }
}

macro_rules! mvec {
    ($v: expr, $s: expr) => {
        vec![$v; $s]
    };
    ($v: expr, $s: expr, $($t: expr),*) => {
        vec![mvec!($v, $($t),*); $s]
    };
}

macro_rules! debug {
    ($x: expr) => {
        println!("{}: {:?}", stringify!($x), $x)
    }
}

fn printiter<'a, T>(v: &'a T)
where
    &'a T: std::iter::IntoIterator, 
    <&'a T as std::iter::IntoIterator>::Item: std::fmt::Display {
    for (i,e) in v.into_iter().enumerate() {
        if i != 0 {
            print!(" ");
        }
        print!("{}", e);
    }
    println!("");
}

struct ContestPrinter {
    s: String,
}

impl ContestPrinter {
    fn new() -> ContestPrinter {
        ContestPrinter {
        s: String::new(),
        }
    }

    fn print<T>(&mut self, x: T)
        where T: std::fmt::Display {
        self.s.push_str(format!("{}", x).as_str());
    }

    fn println<T>(&mut self, x: T)
        where T: std::fmt::Display {
        self.s.push_str(format!("{}\n", x).as_str());
    }
}

impl std::ops::Drop for ContestPrinter {
    fn drop(&mut self) {
        print!("{}", self.s);
    }
}

// euclidの互除法
fn gcd(a: i64, b: i64) -> i64 {
    if b == 0 { a }
    else { gcd(b, a % b) }
}
// ab = lcm(a, b)gcd(a, b)
fn lcm(a: i64, b: i64) -> i64 {
    let g = gcd(a, b);
    (a / g) * b
}
// 約数列挙 昇順ではない
fn divisors(n: i64) -> Vec<i64> {
    let mut ret = Vec::new();
    if n == 1 { ret.push(1); return ret; }
    let mut i = 1;
    loop {
        if (n % i) == 0 {
            ret.push(i);
            if (i != 1) & ((i*i) != n) {
                ret.push(n / i);
            }
        }
        i += 1; if n < (i*i) { break; }
    }
    ret.push(n);
    ret
}

fn is_max_i64(num: i64) -> bool { if num == i64::max_value() { true } else { false } }

fn is_bipartite(graph: &Vec<Vec<usize>>) -> (bool, usize, usize) {
    let size = graph.len();
    let mut color: Vec<i32> = vec![0; size];
    fn dfs(g: &Vec<Vec<usize>>, color: &mut Vec<i32>, v: usize, c: i32) -> bool {
        color[v] = c;
        for i in 0..g[v].len() {
            let nb = g[v][i];
            let nbc = color[nb];
            if nbc == c { return false; }
            if nbc == 0 { if !dfs(g, color, nb, -c) { return false; } }
        }
        return true;
    }
    for i in 0..size {
        if color[i] == 0 { if !dfs(graph, &mut color, i, 1) { return (false, 0, 0); } }
    }
    
    let (mut c1, mut c2) = (0, 0);
    for c in color { match c {
        1 => c1 += 1,
        _ => c2 += 1,
    } }
    (true, c1, c2)
}


fn main() {
    let mut pr = ContestPrinter::new();
    
    let (N, M) = readl!(usize, usize);
    let N1 = N + 1;
    let mut mat: Vec<Vec<usize>> = vec![Vec::new(); N];
    for _ in 0..M {
        let (a, b) = readl!(usize, usize);
        mat[a-1].push(b-1);
        mat[b-1].push(a-1);
    }

    let (ib, b, w) = is_bipartite(&mat);
    pr.println(if ib { b * w - M } else { N * (N - 1) / 2 - M });
}

Measured memory_bytes: 10876