Problem:
Score : 500 points

Problem Statement

Rng has a connected undirected graph with N vertices.
Currently, there are M edges in the graph, and the i-th edge connects Vertices A_i and B_i.

Rng will add new edges to the graph by repeating the following operation:

Operation: Choose u and v (u \neq v) such that Vertex v can be reached by traversing exactly three edges from Vertex u, and add an edge connecting Vertices u and v. It is not allowed to add an edge if there is already an edge connecting Vertices u and v.

Find the maximum possible number of edges that can be added.

Constraints

2 \leq N \leq 10^5

1 \leq M \leq 10^5

1 \leq A_i,B_i \leq N

The graph has no self-loops or multiple edges.

The graph is connected.

Input

Input is given from Standard Input in the following format:

N M
A_1 B_1
A_2 B_2
:
A_M B_M

Output

Find the maximum possible number of edges that can be added.

Sample Input 1

6 5
1 2
2 3
3 4
4 5
5 6

Sample Output 1

4

If we add edges as shown below, four edges can be added, and no more.

Sample Input 2

5 5
1 2
2 3
3 1
5 4
5 1

Sample Output 2

5

Five edges can be added, for example, as follows:

Add an edge connecting Vertex 5 and Vertex 3.

Add an edge connecting Vertex 5 and Vertex 2.

Add an edge connecting Vertex 4 and Vertex 1.

Add an edge connecting Vertex 4 and Vertex 2.

Add an edge connecting Vertex 4 and Vertex 3.

Solution in C# (Mono 4.6.2.0) (judge verdict: Time Limit Exceeded)

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using static System.Console;
using static System.Math;
using static CS_Contest.Utils;
using System.Numerics;
using System.Linq.Expressions;

//using static CS_Contest.Library;

namespace CS_Contest {
	using Li = List<int>;
	using LLi = List<List<int>>;
	using Ll = List<long>;

	internal class Program {
		private static void Main(string[] args) {
			var sw = new StreamWriter(OpenStandardOutput()) { AutoFlush = false };
			SetOut(sw);
			new Calc().Solve();
			Out.Flush();
		}
		

		public class Calc {

			public void Solve() {
				int N, M;
				ReadMulti(out N,out M);
				Library.CostGraph graph=new Library.CostGraph(N);
				REP(M, _ =>
				{
					int Ai, Bi;
					ReadMulti(out Ai,out Bi);
					Ai--;
					Bi--;
					graph.Add(Ai,Bi,0);
				});

				Func<int, int> bfs = null;
				bfs = (start) =>
				{
					var Q = graph[start].ToIndexEnumerable().Where(x=>x.Value==0).Select(x=>x.Index).Where(x=>x!=start).ToQueue();
					REP(2, _ =>
					{
						var tmp = new Queue<int>();
						while (Q.Any()) {
							var item = Q.Dequeue();
							//(_ + ": ======" + item + "=====").WL();
							for (int i = 0; i < N; i++) {
								if (item == i) continue;
								if (graph[item, i] == 0) {
									//(item + " " + i).WL();
									tmp.Enqueue(i);
								}
							}
						}
						Q = tmp;
					});
					foreach (var item in Q.Distinct()) {
						if (graph[start, item] != 0) {
							//item.WL();
							graph.Add(start, item, 0);
							return item;
						}
					}
					return -1;
				};



				int idx = 0, cnt = 0;
				while (idx<N) {
					var result = bfs(idx);
					if (result == -1) {
						idx++;
					}
					else {
						cnt++;
					}
				}
				cnt.WL();

				//Func<int, int, int, int> dfs=null;
				//int start = 0;
				//dfs = (fr, cr, step) =>
				//{
				//	if (step == 3) return graph[start, cr] == 0 || start == cr ? -1 : cr;

				//	for (int i = 0; i < graph[cr].Count; i++) {
				//		if(i==fr||i==cr||graph[cr][i]!=0) continue;
				//		var res = dfs(cr, i, step + 1);
				//		if (res != -1) return res;
				//	}

				//	return -1;
				//};
				//int cnt = 0;
				//while (start<N) {
				//	var result = dfs(start, start, 0);
				//	if (result == -1) {
				//		start++;
				//	}
				//	else {
				//		graph.Add(start,result,0);
				//		cnt++;
				//	}
				//}
				//cnt.WL();
				return;
			}

		}
	}

	public static class Utils {
		public static int ModValue = (int)(1000000007);
		public static long INF = long.MaxValue;

		public static long Mod(long x) => x % ModValue;

		public static long ModPow(long x, long n) {
			long tmp = 1; while (n != 0) { if (n % 2 == 1) { tmp = Mod(tmp * x); } x = Mod(x * x); n /= 2; }
			return tmp;
		}

		public static long DivMod(long x, long y) => Mod(x * ModPow(y, (long)(1e9 + 5)));

		public static void WL(this object obj) => WriteLine(obj);

		public static void WL(this string obj) => WriteLine(obj);

		public static void WL<T>(this IEnumerable<T> list) => list.ToList().ForEach(x => x.WL());

		public static int ReadInt() => int.Parse(ReadLine());

		public static List<int> ReadInts(char s = ' ') => ReadLine().Split(s).Where(x => x != "").Select(int.Parse).ToList();

		public static long ReadLong() => long.Parse(ReadLine());

		public static List<long> ReadLongs(char s = ' ') => ReadLine().Split(s).Select(long.Parse).ToList();

		public static void ReadMulti(out int x, out int y) {
			var i = ReadInts(' ');
			x = i[0]; y = i[1];
		}

		public static void ReadMulti(out long x, out long y) {
			var i = ReadLongs(' ');
			x = i[0]; y = i[1];
		}

		public static void ReadMulti(out int x, out int y, out int z) {
			var i = ReadInts(' ');
			x = i[0]; y = i[1]; z = i[2];
		}

		public static void ReadMulti(out int x, out int y, out int z, out int v) {
			var i = ReadInts(' ');
			x = i[0]; y = i[1]; z = i[2]; v = i[3];
		}

		public static string StringJoin<T>(this IEnumerable<T> l, string separator = "") => string.Join(separator, l);

		public static long GCD(long m, long n) {
			long tmp;
			if (m < n) { tmp = n; n = m; m = tmp; }
			while (m % n != 0) {
				tmp = n;
				n = m % n;
				m = tmp;
			}
			return n;
		}

		public static long LCM(long m, long n) => m * (n / GCD(m, n));

		public static void REP(int n, Action<int> act) {
			for (var i = 0; i < n; i++) {
				act(i);
			}
		}

		public static void RREP(int n, Action<int> act) {
			for (var i = n - 1; i >= 0; i--) {
				act(i);
			}
		}

		public static List<T> OrderByToList<T>(this IEnumerable<T> l) => l.OrderBy(x => x).ToList();

		public static int ManhattanDistance(int x1, int y1, int x2, int y2) => Abs(x2 - x1) + Abs(y2 - y1);

		public struct IndexT<T> {
			public T Value { get; set; }
			public int Index { get; set; }

			public IndexT(T v, int i) {
				Value = v; Index = i;
			}
			public override string ToString() {
				return Value + " " + Index;
			}
		}

		public static IEnumerable<IndexT<T>> ToIndexEnumerable<T>(this IEnumerable<T> list) => list.Select((x, i) => new IndexT<T>(x, i));

		public static Queue<T> ToQueue<T>(this IEnumerable<T> iEnumerable) {
			var rt = new Queue<T>();
			foreach (var item in iEnumerable) {
				rt.Enqueue(item);
			}
			return rt;
		}

		public static IndexT<T> IndexOf<T>(this IEnumerable<T> ie, Func<IndexT<T>, IndexT<T>, IndexT<T>> func) =>
			ie.ToIndexEnumerable().Aggregate(func);

		public static Tuple<TKey, TSource> ToTuple<TKey, TSource>(this KeyValuePair<TKey, TSource> kvp) => new Tuple<TKey, TSource>(kvp.Key, kvp.Value);

		public static IEnumerable<Tuple<TKey, TSource>> ToTupleList<TKey, TSource>(this Dictionary<TKey, TSource> d) => d.Select(_ => _.ToTuple());

		public static IEnumerable<T> When<T>(this IEnumerable<T> iEnumerable, Func<T, bool> condition, Func<T,T> filterFunc) {
			var rt = iEnumerable.ToArray();
			var index = 0;
			foreach (var item in iEnumerable) {
				rt[index] = condition(item) ? filterFunc(item) : item;
				index++;
			}
			return rt;
		}

		public static T[] Range<T>(int range,Func<int,T> func) {
			var rt = new T[range];
			for (var i = 0; i < range; i++) rt[i] = func(i);
			return rt;
		}
		public static void Swap<T>(ref T x,ref T y) {
			var tmp = x;
			x = y;
			y = tmp;
		}

		public static int Count<T>(this IEnumerable<T> l, T target) => l.Count(x => x.Equals(target));
	}
	public static class Library {

		public struct UnionFind {
			private int[] data;

			public UnionFind(int size) {
				data = new int[size];
				for (var i = 0; i < size; i++) data[i] = -1;
			}

			public bool Unite(int x, int y) {
				x = Root(x);
				y = Root(y);

				if (x != y) {
					if (data[y] < data[x]) {
						var tmp = y;
						y = x;
						x = tmp;
					}
					data[x] += data[y];
					data[y] = x;
				}
				return x != y;
			}

			public bool IsSameGroup(int x, int y) {
				return Root(x) == Root(y);
			}

			private int Root(int x) {
				return data[x] < 0 ? x : data[x] = Root(data[x]);
			}
		}

		public class CostGraph {
			private List<long>[] list;
			private int Size;
			private const long INF = long.MaxValue / 2;
			private List<List<Edge>> edge;

			public struct Edge :IComparable {
				public int From { get; set; }
				public int To { get; set; }
				public long Cost { get; set; }

				public Edge(int f, int t, long c) {
					From = f; To = t; Cost = c;
				}

				public static bool operator <(Edge e1, Edge e2) => e1.Cost < e2.Cost;

				public static bool operator >(Edge e1, Edge e2) => e1.Cost > e2.Cost;

				public int CompareTo(object obj) {
					return Cost.CompareTo(obj);
				}
			}

			public CostGraph(int size) {
				Size = size;
				list = Enumerable.Range(0, Size).Select(x => new List<long>()).ToArray();
				Utils.REP(Size, i => {
					Utils.REP(Size, k => {
						list[i].Add(i == k ? 0 : INF);
					});
				});
				edge = Enumerable.Range(0, Size).Select(x => new List<Edge>()).ToList();
			}

			public void Add(int A, int B, long C, bool direction = true) {
				this[A, B] = Min(this[A, B], C);
				edge[A].Add(new Edge(A, B, C));
				if (!direction) return;
				this[B, A] = this[A, B]; edge[B].Add(new Edge(B, A, C));
			}

			public long this[int A, int B] {
				get { return list[A][B]; }
				set { list[A][B] = value; }
			}

			public List<long> this[int index] {
				get { return list[index]; }
				set { list[index] = value; }
			}

			public void Clear() {
				for (var i = 0; i < Size; i++) {
					list[i].Clear();
				}
				edge.Clear();
			}

			/// <summary>
			/// ダイクストラ
			/// </summary>
			/// <param name="s"></param>
			/// <param name="t"></param>
			/// <returns></returns>
			public long Dijkstra(int s, int t) {
				var dist = Enumerable.Repeat(INF, Size).ToList();
				dist[s] = 0;
				var priorityQueue = new PriorityQueue<Tuple<long, int>>();
				priorityQueue.Enqueue(new Tuple<long, int>(0, s));
				while (priorityQueue.Count != 0) {
					var src = priorityQueue.Dequeue();
					if (dist[src.Item2] < src.Item1) continue;

					for (var dest = 0; dest < Size; dest++) {
						var cost = this[src.Item2, dest];
						if (cost == INF || dist[dest] <= dist[src.Item2] + cost) continue;
						dist[dest] = dist[src.Item2] + cost;
						priorityQueue.Enqueue(new Tuple<long, int>(dist[dest], dest));
					}
				}
				return dist[t];
			}

			public void WarshallFloyd() {
				Utils.REP(Size, k => {
					Utils.REP(Size, i => {
						Utils.REP(Size, j => this[i, j] = Min(this[i, j], this[i, k] + this[k, j]));
					});
				});
			}

			/// <summary>
			/// べルマンフォード
			/// </summary>
			/// <param name="s">start</param>
			/// <param name="n">node count</param>
			/// <returns></returns>
			public Tuple<List<long>, bool> BellmanFord(int s, int n) {
				var dist = Enumerable.Repeat(INF, Size).ToList();
				dist[s] = 0;
				for (var i = 0; i < n; i++) {
					for (var v = 0; v < n; v++) {
						foreach (var item in edge[v]) {
							if (dist[v] != INF && dist[item.To] > dist[v] + item.Cost) {
								dist[item.To] = dist[v] + item.Cost;
								if (i == n - 1) return new Tuple<List<long>, bool>(dist, true);
							}
						}
					}
				}
				return new Tuple<List<long>, bool>(dist, false);
			}

			public long Kruskal() {
				var sorted = new List<Edge>();
				foreach (var item in edge) {
					sorted.AddRange(item);
				}
				sorted = sorted.OrderBy(x => x.Cost).ToList();
				var uf = new UnionFind(sorted.Count);
				long min_cost = 0;

				foreach (var e in sorted) {
					if (!uf.IsSameGroup(e.From, e.To)) {
						min_cost += e.Cost;
						uf.Unite(e.From, e.To);
					}
				}
				return min_cost;
			}
		}

		/// <summary>
		/// 優先度付きキュー
		/// </summary>
		/// <typeparam name="T"></typeparam>
		public class PriorityQueue<T> {
			private readonly List<T> heap;
			private readonly Comparison<T> compare;
			private int size;

			public PriorityQueue() : this(Comparer<T>.Default) {
			}

			public PriorityQueue(IComparer<T> comparer) : this(16, comparer.Compare) {
			}

			public PriorityQueue(Comparison<T> comparison) : this(16, comparison) {
			}

			public PriorityQueue(int capacity, Comparison<T> comparison) {
				this.heap = new List<T>(capacity);
				this.compare = comparison;
			}

			public void Enqueue(T item) {
				this.heap.Add(item);
				var i = size++;
				while (i > 0) {
					var p = (i - 1) >> 1;
					if (compare(this.heap[p], item) <= 0)
						break;
					this.heap[i] = heap[p];
					i = p;
				}
				this.heap[i] = item;
			}

			public T Dequeue() {
				var ret = this.heap[0];
				var x = this.heap[--size];
				var i = 0;
				while ((i << 1) + 1 < size) {
					var a = (i << 1) + 1;
					var b = (i << 1) + 2;
					if (b < size && compare(heap[b], heap[a]) < 0) a = b;
					if (compare(heap[a], x) >= 0)
						break;
					heap[i] = heap[a];
					i = a;
				}
				heap[i] = x;
				heap.RemoveAt(size);
				return ret;
			}

			public T Peek() {
				return heap[0];
			}

			public int Count => size;

			public bool Any() {
				return size > 0;
			}
		}
	}

}