#include <bits/stdc++.h>
using namespace std;


typedef long long ll;
// #define DEBUG

class UnionFind{
    private:
    vector<int> par; // 親
    vector<int> rank; // 木の深さ
    vector<long long> sizes_; 
    int num_of_conn;

    public:
    // n要素で初期化
    UnionFind(int n) {
        par = vector<int>(n);
        rank = vector<int>(n);
        sizes_ = vector<long long>(n);
        for (int i = 0; i < n; i++) {
            par[i] = i;
            rank[i] = 0;
            sizes_[i] = 1;
        }
        num_of_conn = n;
    }

    // 木の根を求める
    int find(int x) {
        if (par[x] == x) {
            return x;
        } else {
            return par[x] = find(par[x]);
        }
    }

    long long getSize(int x){
        return sizes_[par[x]];
    }

    // xとyの属する集合を併合
    void unite(int x, int y) {
        x = find(x);
        y = find(y);
        auto sizex = getSize(x);
        auto sizey = getSize(y);
        if (x == y) return;
        if (rank[x] < rank[y]) {
            par[x] = y;
        } else {
            par[y] = x;
            if (rank[x] == rank[y]) rank[x]++;
        }
        num_of_conn--;
        sizes_[find(x)] = sizex + sizey;
    }

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

    int numOfConnected(){
        return num_of_conn;
    }
};


void solve(long long N, long long M, std::vector<long long> A, std::vector<long long> B){
    for(int i=0; i < M; i++){
        A[i]--;
        B[i]--;
    }


    reverse(A.begin(), A.end());
    reverse(B.begin(), B.end());

    vector<ll> ress(M);
    ll doubled_res = N*(N-1);
    UnionFind uf(N);

    for(int i=0; i < M; i++){
        #ifdef DEBUG
        printf("---\n");
        #endif
        ress[i] = doubled_res/2;

        // 接続するノードを取得
        auto a = A[i];
        auto b = B[i];



        // それらがすでに連結されているならcontinue
        if(uf.same(a, b)){
            continue;
        }

        // その連結成分IDを取得
        auto connA = uf.find(a);
        auto connB = uf.find(b);
        auto sizeA = uf.getSize(connA);
        auto sizeB = uf.getSize(connB);

        // あたらしく連結するばあいはトータル点から(その連結成分の大きさ)*(N-(その連結成分のおおきさ))をひくのお両方についてやる
        doubled_res -= uf.getSize(connA)*(N - uf.getSize(connA));
        doubled_res -= uf.getSize(connB)*(N - uf.getSize(connB));
        // 連結
        uf.unite(a, b);
        // トータル点に(その連結成分の大きさ)*(N-(その連結成分のおおきさ))をたす
        auto connNew = uf.find(a);
        doubled_res += uf.getSize(connNew)*(N - uf.getSize(connNew));

        #ifdef DEBUG
        printf("%d %d %d\n", sizeA, sizeB, uf.getSize(connNew));
        #endif
    }

    reverse(ress.begin(), ress.end());
    for(auto iter: ress){
        cout << iter << endl;
    }

}

// Generated by 1.1.6 https://github.com/kyuridenamida/atcoder-tools  (tips: You use the default template now. You can remove this line by using your custom template)
int main(){
    long long N;
    scanf("%lld",&N);
    long long M;
    scanf("%lld",&M);
    std::vector<long long> A(M);
    std::vector<long long> B(M);
    for(int i = 0 ; i < M ; i++){
        scanf("%lld",&A[i]);
        scanf("%lld",&B[i]);
    }
    solve(N, M, std::move(A), std::move(B));
    return 0;
}


Measured memory_bytes: 5248