// Original C++ solution (slower):
#include <iostream>

using namespace std;



#ifdef DEBUG

    #define IFD if(true)

#else

    #define IFD if(false)

#endif



#include <vector>



// 要素個数カウント付き Union Find



// 要素の型。int か long あたりを想定

template<typename T_uf_data>



class UnionFind

{

private:

    std::vector<T_uf_data> par; // 親 (parent) を指す

    std::vector<T_uf_data> rnk;

    std::vector<T_uf_data> cnt; // 引数の値が含まれるグループの要素数（ルートノードのみが意味を持つ）



    // その値を持つルートノードを返す

    T_uf_data find_root(int x)

    {

        if(par[x] == x) {

            return x;

        } else {

            return par[x] = find_root(par[x]);

        }

    }



public:



    // コンストラクタの引数で要素数を指定

    UnionFind(int n) : par(n), rnk(n), cnt(n)

    {

        for(int i = 0; i < n; i++) {

            par[i] = i; // 親を持たないノードは自分自身を親としておく

            rnk[i] = 0;

            cnt[i] = 1; // 初期状態ではすべてのノードの要素数は 1

        }

    }



    // 二つの要素をグループ化

    void Unite(int x, int y)

    {

        x = find_root(x);

        y = find_root(y);

        if(x == y) return;



        if(rnk[x] < rnk[y]) {

            // y が親になる

            par[x] = y;

            cnt[y] += cnt[x];

        } else {

            // x が親になる

            par[y] = x;

            cnt[x] += cnt[y];

            if(rnk[x] == rnk[y]) rnk[x]++;

        }

    }



    // x と y が同じグループかを返す

    bool isSameGroup(int x, int y)

    {

        return find_root(x) == find_root(y);

    }



    // x を含むグループの要素数を返す

    int Size(int x)

    {

        return cnt[find_root(x)];

    }

};





int main()

{

    int N, M, A[100001], B[100001];

    long long ans[100001];



    cin >> N >> M;

    UnionFind<int> uf(100001);



    for(int i = 1; i <= M; i++) {

        cin >> A[i] >> B[i];

    }

    ans[M] = (long long)N * (N - 1) / 2;



    for(int i = M - 1; i >= 1; i--) {

        ans[i] = ans[i + 1];

        if(!uf.isSameGroup(A[i + 1], B[i + 1])) {

            ans[i] -= (long long)uf.Size(A[i + 1]) * uf.Size(B[i + 1]);

            uf.Unite(A[i + 1], B[i + 1]);

        }

    }



    for(int i = 1; i <= M; i++) {

        cout << ans[i] << endl;

    }

    

    return 0;

}


// Optimized solution to the same problem (faster):
#include <iostream>

using namespace std;



#ifdef DEBUG

    #define IFD if(true)

#else

    #define IFD if(false)

#endif



//////////////////////////////////////////////////

//

// 要素個数カウント付き Union Find

//   -テンプレートで要素の型を指定。int か long あたりを想定

//   -コンストラクタで要素数 n を指定。0 ～ n - 1 までの要素が利用可能



#include <vector>

template<typename T_uf_data>



class UnionFind

{

private:



    std::vector<T_uf_data> par; // 親 (parent) 親がいない場合は -要素の個数

    std::vector<T_uf_data> rnk; // 要素を偏らせないためのもの



    // その値を持つグループのルートノードを返す

    T_uf_data find_root(int x)

    {

        if(par[x] < 0) {

            return x;

        } else {

            // 検索時に一番上の要素を指すように付け替える

            return par[x] = find_root(par[x]);

        }

    }



public:



    // コンストラクタの引数で要素数を指定

    UnionFind(int n) : par(n), rnk(n)

    {

        for(int i = 0; i < n; i++) {

            par[i] = -1; // 始めは -要素の個数 = -1 となる

            rnk[i] = 0;

        }

    }



    // 二つの要素をグループ化

    void Unite(int x, int y)

    {

        x = find_root(x);

        y = find_root(y);

        if(x == y) return;



        if(rnk[x] < rnk[y]) {

            // y が親になる

            par[y] += par[x]; // 要素の個数を足し合わせる

            par[x] = y;

        } else {

            // x が親になる

            par[x] += par[y]; // 要素の個数を足し合わせる

            par[y] = x;

            // 深さに差が無かった場合だけ長さが１増える

            if(rnk[x] == rnk[y]) rnk[x]++;

        }

    }



    // x と y が同じグループかを返す

    bool isSameGroup(int x, int y)

    {

        return find_root(x) == find_root(y);

    }



    // x を含むグループの要素数を返す

    int Size(int x)

    {

        return -par[find_root(x)];

    }

};

//////////////////////////////////////////////////







int main()

{

    int N, M, A[100001], B[100001];

    long long ans[100001];



    cin >> N >> M;

    UnionFind<int> uf(100001);



    for(int i = 1; i <= M; i++) {

        cin >> A[i] >> B[i];

    }

    ans[M] = (long long)N * (N - 1) / 2;



    for(int i = M - 1; i >= 1; i--) {

        ans[i] = ans[i + 1];

        if(!uf.isSameGroup(A[i + 1], B[i + 1])) {

            ans[i] -= (long long)uf.Size(A[i + 1]) * uf.Size(B[i + 1]);

            uf.Unite(A[i + 1], B[i + 1]);

        }

    }



    for(int i = 1; i <= M; i++) {

        cout << ans[i] << endl;

    }

    

    return 0;

}


// Fastest known solution for this problem: