#include <bits/stdc++.h>

using namespace std;
using ll = long long;
using ull = unsigned long long;

#ifndef __MACRO_H__
#define __MACRO_H__

#define all(collection)  (collection).begin(), (collection).end()		// begin to end
#define rep(i, begin, end) for (ll i = begin; i < end; i++)				// repeat
#define repr(i, begin, end) for (ll i = begin; end < i; i--)			// repeat reverse

#endif

namespace NyaGadgetUnionFind
{
	struct Vertex
	{	// 頂点を表現する構造体
		ll root;
		ll size;
	};

	template <class V> struct Graph
	{	// グラフを表現する構造体
		vector<V> vertex;
		/**
		@brief コンストラクタ
		@param v_size 頂点の数
		@note
		 v_sizeのunion-findを作成する
		**/
		Graph(ll v_size)
		{	// グラフ構造を構造体に格納する
			vertex.resize(v_size);
			rep(i, 0, (ll)vertex.size())
			{	// 各頂点の根を自分自身で初期化、各頂点の木サイズは１で初期化
				vertex[i].root = i;
				vertex[i].size = 1;
			}
		}
		/**
		@brief 根を検索する関数(vertex)
		@param v_index 根を検索する頂点インデックス
		@note
		 引数で指定された頂点が接続されている根を検索した結果をVertex構造体で返す。
		 RootVertex(10).size // 頂点インデックス10の根のサイズ(根に接続されている点の数)
		 のような使い方ができる。
		**/
		Vertex& RootVertex(ll v_index)
		{
			// 自分自身が根のとき
			if (v_index == vertex[v_index].root)
				return vertex[vertex[v_index].root];
			// 根の探索をすると同時に次からO(1)で根を参照できるようにする(経路圧縮)
			vertex[v_index].root = FindRoot(vertex[v_index].root);
			return vertex[vertex[v_index].root];
		}
		/**
		@brief 根を検索する関数(index)
		@param v_index 根を検索する頂点インデックス
		@note
		 引数で指定された頂点が接続されている根を検索した結果をindexで返す。
		 long long型で結果を返すので、根の頂点インデックスの情報だけ欲しいときに使う。
		 根の頂点インデックスのサイズなどの情報が欲しいときはRootVertex()のほうを使う。
		**/
		ll FindRoot(ll v_index)
		{
			// 自分自身が根のとき
			if (v_index == vertex[v_index].root)
				return vertex[v_index].root;
			// 根の探索をすると同時に次からO(1)で根を参照できるようにする(経路圧縮)
			vertex[v_index].root = FindRoot(vertex[v_index].root);
			return vertex[v_index].root;
		}
		/**
		@brief 2つの木を結合する関数
		@param v1_index 頂点インデックス
		@param v2_index 頂点インデックス
		@note
		 頂点インデックスv1_indexを含む木と頂点インデックスv2_indexを含む木を結合する。
		 ただし、v1_indexとv2_indexが既に同じ木に属しているときは何もしない。
		**/
		void UnionTree(ll v1_index, ll v2_index)
		{
			ll tree1_root = FindRoot(v1_index);
			ll tree2_root = FindRoot(v2_index);

			// 既に同じ木に属しているときは何もしない
			if (tree1_root == tree2_root)
				return;

			// サイズの小さい木の根をサイズの大きい木の根に繋いで結合する
			if (vertex[tree1_root].size < vertex[tree2_root].size)
			{
				vertex[tree1_root].root = tree2_root;
				vertex[tree2_root].size += vertex[tree1_root].size;
			}
			else
			{
				vertex[tree2_root].root = tree1_root;
				vertex[tree1_root].size += vertex[tree2_root].size;
			}
		}
	};
}

using namespace NyaGadgetUnionFind;

class ABC120D
{
public:
	ABC120D()
	{
		cin >> n >> m;
		a.resize(m);
		b.resize(m);
		rep(i, 0, m)
		{
			cin >> a[i] >> b[i];
			a[i]--; b[i]--;				// ゼロインデックスにする
		}
	}
	void Run(void)
	{
		Graph<Vertex> g(n);

		vector<ll> ans(m);				// 各状態の不便さ
		ans[m-1] = n * (n - 1) / 2;		// 全ての橋が崩壊した状態の不便さ
		repr(i, m-1, 0)
		{	
			// 既に全ての頂点が接続されているならループを抜ける
			if (g.RootVertex(a[i]).size == n)
				break;

			// 頂点を接続したときに変化する不便さを計算し、実際に結合する。
			if (g.FindRoot(a[i]) == g.FindRoot(b[i]))
				ans[i - 1] = ans[i];
			else
				ans[i - 1] = ans[i] - g.RootVertex(a[i]).size * g.RootVertex(b[i]).size;

			g.UnionTree(a[i], b[i]);
		}

		for (const auto& e : ans)
			cout << e << endl;
	}
private:
	ll n;
	ll m;
	vector<ll> a;
	vector<ll> b;
};

int main(void)
{
	ABC120D abc120d;
	abc120d.Run();

	return 0;
}


Measured memory_bytes: 5248