#include <stdio.h>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <list>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <vector>
#include <string>
#include <bitset>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <utility>
#include <numeric>
#include <complex>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <cassert>
#include <iostream>
#include <iterator>
#include <algorithm>
using namespace std;
typedef long long ll;
const double EPS = 1e-9;
typedef vector<int> vint;
typedef vector<vector<int>> v2int;
typedef vector<ll> vll;
typedef vector<vector<ll>> v2ll;
typedef vector<bool> vbool;
typedef vector<vector<bool>> v2bool;
typedef deque<int> ideque;
typedef pair<int, int> pint;
typedef map<int, int> mint;
typedef vector<pint> vpair;
typedef unordered_map<int, int> umint;
typedef unordered_map<int, vint> graph;
typedef set<int> sint;
typedef unordered_set<int> smint;
const int INF = int(2e9);
const ll LINF = ll(2e20);
#define rep(i, n) REP(i, 0, n)
#define ALL(v) v.begin(), v.end()
#define MSG(a) cout << #a << " " << a << endl;
#define REP(i, x, n) for(int i = x; i < n; i++)
template<class T, class C> void chmax(T& a, C b) { a>b ? : a = b; }
template<class T, class C> void chmin(T& a, C b) { a<b ? : a = b; }

class union_find
{
private:
    std::vector<int> parent;
    std::vector<int> rank;
    std::vector<int> count;
    int node_num;
public:
    union_find(int node_num);
    void unite(int x, int y);
    int get_count(int x);
    int find(int x);
};

union_find::union_find(int node_num) :
    count(node_num + 1, 1),
    parent(node_num + 1, 0),
    rank(node_num + 1, 0)
{
    for (int i = 0; i <= node_num; i++) {
        parent[i] = i;
    }
}

int union_find::get_count(int x) {
    int parent = find(x);
    return count[parent];
}

void union_find::unite(int x, int y) {
    int x_root = find(x);
    int y_root = find(y);
    get_count(x);
    //既に同じ根なら、同じ所属なので何もしない
    if (x_root == y_root) return;
    //ランクが大きい方に小さい方をくっつける
    //結合後のランクは大きい方になる。
    if (rank[x_root] > rank[y_root]) {
        parent[y_root] = x_root;
    }
    else {
        parent[x_root] = y_root;
        if (rank[x_root] == rank[y_root]) {
            //ランクが等しい場合は、必ずランクが1上がる。
            rank[y_root]++;
        }
    }
    int next_count = count[x_root] + count[y_root];
    int parent = find(x);
    //count[y] = next_count;
    //count[x] = next_count;

    count[parent] = next_count;
}

int union_find::find(int x) {
    if (x != parent[x]) {
        // findの結果を各parentに入れることで経路を圧縮。
        //ただし、変更コストが大きいのでランクは変えてない。
        parent[x] = find(parent[x]);
    }
    return parent[x];
}

int main() {
    int N, M;
    cin >> N >> M;
    vpair G(M);
    rep(i, M) {
        int a, b;
        cin >> a >> b;
        G[i] = make_pair(a, b);
    }
    ll now_score = 0;
    union_find uf(N);
    vll vscore(M);
    vscore[M - 1] = 0;
    //vscore[0] = (ll(N) * ll(N - 1)) / 2;
    for (int i = M - 1; i >= 1; i--) {
        if (uf.find(G[i].first) == uf.find(G[i].second)) {
            vscore[i - 1] = now_score;
            continue;
        }

        ll pre_score1 = uf.get_count(G[i].first);
        ll pre_score2 = uf.get_count(G[i].second);
        
        uf.unite(G[i].first, G[i].second);
        ll next_score = uf.get_count(G[i].first);
        now_score = now_score - pre_score1 * (pre_score1 - 1)/2 - 
                    pre_score2 * (pre_score2 - 1) / 2 +
                    next_score * (next_score - 1) / 2;
        vscore[i - 1] = now_score;
    }
    for (int i = 0; i < M; i++) {
        cout << (ll(N) * ll(N - 1)) / 2 - vscore[i] << endl;
    }


    return 0;
}

Measured memory_bytes: 4096