#include<iostream>
#include<string>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<math.h>
#include<iomanip>
#include<set>
#include<numeric>
#include<cstring>
#include<cstdio>
#include<functional>

#define REP(i, n) for(int i = 0;i < n;i++)
#define REPR(i, n) for(int i = n;i >= 0;i--)
#define FOR(i, m, n) for(int i = m;i < n;i++)
#define FORR(i, m, n) for(int i = m;i >= n;i--)
#define SORT(v, n) sort(v, v+n);
#define VSORT(v) sort(v.begin(), v.end());
#define REVERSE(v,n) reverse(v,v+n);
#define VREVERSE(v) reverse(v.begin(), v.end());
#define ll long long
#define pb(a) push_back(a)
#define INF 9999999999
#define m0(x) memset(x,0,sizeof(x))
//#define fill(x,y) memset(x,y,sizeof(x))
#define print(x) cout<<x<<endl;
#define pe(x) cout<<x<<" ";
#define lb(v,n) lower_bound(v.begin(), v.end(), n);
#define ub(v,n) upper_bound(v.begin(), v.end(), n);
#define int long long


using namespace std;

template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return true; } return false; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return true; } return false; }


int dy[4] = { 0,0,1,-1 };
int dx[4] = { 1,-1,0,0 };
int dxx[9] = { 0, 0,0,1,1,1,-1,-1,-1 };
int dyy[9] = { 0, 1,-1,0,1,-1,0,1,-1 };




ll gcd(ll x, ll y) {
	ll m = max(x, y), n = min(x, y);
	if (m%n == 0)return n;
	else return gcd(m%n, n);
}
ll lcm(ll x, ll y) {
	return x / gcd(x, y)*y;
}

long long power_mod(long long x, long long n, long long m) {
	if (n == 0)
		return 1;
	if (n % 2 == 0)
		return power_mod(x * x % m, n / 2, m);
	else
		return x * power_mod(x, n - 1, m) % m;
}

long long power(long long a, long long n) {//aのn乗を計算します。
	long long x = 1;
	while (n > 0) {//全てのbitが捨てられるまで。
		if (n & 1) {//1番右のbitが1のとき。
			x = x * a;
		}
		a = a * a;
		n >>= 1;//bit全体を右に1つシフトして一番右を捨てる。
	}
	return x;
}



long long nCr(long long n, long long r) {
	if (r > n / 2) r = n - r; // because C(n, r) == C(n, n - r)
	long long ans = 1;
	long long i;

	for (i = 1; i <= r; i++) {
		ans *= n - r + i;
		ans /= i;
	}

	return ans;
}


const int MAX = 100010;
const int MOD = 998244353;

long long fac[MAX], finv[MAX], inv[MAX];

// テーブルを作る前処理
void COMinit() {
	fac[0] = fac[1] = 1;
	finv[0] = finv[1] = 1;
	inv[1] = 1;
	for (int i = 2; i < MAX; i++) {
		fac[i] = fac[i - 1] * i % MOD;
		inv[i] = MOD - inv[MOD%i] * (MOD / i) % MOD;
		finv[i] = finv[i - 1] * inv[i] % MOD;
	}
}

// 二項係数計算
long long COM(int n, int k) {
	if (n < k) return 0;
	if (n < 0 || k < 0) return 0;
	return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;
}

bool arr[100000100];
vector<ll>sosuu;
void Eratosthenes() {
	ll N = 10000010;
	int c = 0;
	for (int i = 0; i < N; i++) {
		arr[i] = 1;
	}
	for (ll i = 2; i < sqrt(N); i++) {
		if (arr[i]) {
			for (ll j = 0; i * (j + 2) < N; j++) {
				arr[i *(j + 2)] = 0;
			}
		}
	}

	for (ll i = 2; i < N; i++) {
		if (arr[i]) {
			sosuu.pb(i);
			//cout << sosuu[c] << " ";
			c++;
		}
	}
	//cout << endl;
	//cout << c << endl;
}

ll stoL(string s) {
	ll n = s.length();
	ll ans = 0;
	for (int i = 0; i < n; i++) {
		ans += power(10, n - i - 1)*(ll)(s[i] - '0');
	}
	return ans;
}

typedef pair<int, int> P;


void getbit(ll x, int bits[]) {
	int cnt = 0;
	while (x > 0) {
		if (x % 2 == 0)bits[cnt] = 0;
		else bits[cnt] = 1;
		x /= 2;
		cnt++;
	}
}
void addbit(ll x, int bits[]) {
	int cnt = 0;
	while (x > 0) {
		if (x % 2 == 0)bits[cnt] += 0;
		else bits[cnt] += 1;
		x /= 2;
		cnt++;
	}
}

vector<int>A, B, num,num2, G[100010];
vector<int>ans;
map<int, int>mp;


int siz[MAX];
int par[MAX];//親
int Rank[MAX];//木の深さ

//n要素で初期化
void init(int n) {
	REP(i, n) {
		par[i] = i;
		Rank[i] = 0;
		siz[i]=1;
	}
}

//木の根を求める
int find(int x) {
	if (par[x] == x) {
		return x;
	}
	else {
		return par[x] = find(par[x]);//経路圧縮(根に直接つなぎなおす)もしつつ
	}
}

//xとyの属する集合を併合
void unite(int x, int y) {
	x = find(x);
	y = find(y);
	if (x == y)return;
	//低いほうを高いほうにつなげる(効率化)
	if (Rank[x] < Rank[y]) {
		par[x] = y;
		siz[x]+=siz[y];
		siz[y]=siz[x];
	}
	else {
		siz[y]+=siz[x];
		siz[x]=siz[y];
		par[y] = x;
		if (Rank[x] == Rank[y])Rank[x]++;
	}
}

//xとyが同じ集合に属するか否か
bool same(int x, int y) {
	return find(x) == find(y);
}

void uni(int n,int cnt) {
	for (auto x : G[n]) {
		if (num[x] != -1) {
			num[n] = num[x];
			mp[num[n]]++;
			return;
		}
	}
	num[n] = cnt;
	mp[num[n]]++;
	for (auto x:G[n]) {
		uni(x, cnt);
	}
}
void paint(int n, int cnt) {
	mp[num[n]]--;
	mp[cnt]++;
	num[n] = cnt;
	for (auto x : G[n]) {
		if (num[x] != cnt) {
			paint(x, cnt);
		}
	}
}
signed main() {

	int N, M; cin >> N >> M;
	num.resize(N);
	init(N);
	REP(i, N) num[i] = -1;
	A.resize(M); B.resize(M);
	REP(i, M) {
		cin >> A[i] >> B[i];
		A[i]--, B[i]--;
	}
	ll res = N * (N - 1) / 2;
	VREVERSE(A); VREVERSE(B);
	int cnt = 1;
	ans.pb(res);
	REP(i, M) {
		if (num[A[i]] == -1) {
			num[A[i]] = cnt;
			mp[cnt]++;
			//print(mp[num[A[i]]]);
			cnt++;
		}
		if (num[B[i]] == -1) {
			num[B[i]] = cnt;
			mp[cnt]++;
			cnt++;
		}
		G[A[i]].pb(B[i]);
		G[B[i]].pb(B[i]);
		if (!same(A[i], B[i])) {
			//cout<<"mp[num[A[i]]]:"<<mp[num[A[i]]]<<"mp[num[B[i]]]"<<mp[num[B[i]]]<<endl;
			//res -= max((ll)1,mp[num[A[i]]]) * max((ll)1,mp[num[B[i]]]);
			//res -= mp[num[A[i]]] * mp[num[B[i]]];
			res-=siz[find(A[i])]*siz[find(B[i])];
			unite(A[i], B[i]);
		}
		//res = max(res, (ll)0);
		//paint(B[i], num[A[i]]);
		ans.pb(res);
		/*if (num[A[i]] != -1 && num[B[i]] != -1) {
			if(num[A[i]!=num[B[i]]])res -= mp[num[A[i]]] * mp[num[B[i]]];
		}
		else if (num[A[i]] != -1) {
			res -= mp[num[A[i]]];
		}
		else if (num[B[i]] != -1) {
			res -= mp[num[B[i]]];
		}
		else res--;*/
	}
	VREVERSE(ans);
	FOR(i, 1, M + 1) {
		print(ans[i]);
	}
}




Measured memory_bytes: 20712