import std.stdio, std.string, std.conv, std.range;
import std.algorithm, std.array, std.typecons, std.container;
import std.math, std.numeric, std.random, core.bitop;

enum inf = 1_001_001_001;
enum infl = 1_001_001_001_001_001_001L;


struct UnionFind {
    int N;
    int[] parent; // 根は -(連結成分のサイズ) としておく
    int cc;

    this(int n)
    in {
        assert(n > 0);
    }
    body {
        N = n;
        parent = new int[](N);
        parent[] = -1;
        cc = n;
    }

    int root(int x)
    in {
        assert(0 <= x && x < N);
    }
    body {
        if (parent[x] < 0) return x;
        else return parent[x] = root(parent[x]);
    }

    int size(int x)
    in {
        assert(0 <= x && x < N);
    }
    body {
        return -parent[root(x)];
    }

    bool same(int x, int y)
    in {
        assert(0 <= x && x < N);
        assert(0 <= y && y < N);
    }
    body {
        return root(x) == root(y);
    }

    bool merge(int x, int y)
    in {
        assert(0 <= x && x < N);
        assert(0 <= y && y < N);
    }
    body {
        import std.algorithm : swap;

        x = root(x);
        y = root(y);

        if (x == y) return false;
        if (size(x) < size(y)) swap(x, y);

        // size(x) >= size(y)
        parent[x] += parent[y];
        parent[y] = x;
        cc--;

        return true;
    }
}


unittest {
    auto uf = UnionFind(10);

    uf.merge(0, 8);
    uf.merge(2, 7);
    uf.merge(3, 6);

    assert(!uf.same(0, 6));
    assert(!uf.same(4, 5));
    assert(uf.same(2, 7));
    assert(uf.size(8) == 2);
    assert(uf.size(2) == 2);
    assert(uf.size(3) == 2);
    assert(uf.size(4) == 1);

    uf.merge(2, 6);
    uf.merge(0, 5);
    uf.merge(0, 9);

    assert(uf.same(8, 9));
    assert(uf.same(9, 5));
    assert(uf.same(6, 7));
    assert(uf.same(7, 3));
    assert(uf.size(2) == 4);
    assert(uf.size(6) == 4);
    assert(uf.size(5) == 4);
    assert(uf.size(8) == 4);
    assert(uf.size(9) == 4);
    assert(uf.size(1) == 1);

    assert(!uf.same(1, 9));
    assert(!uf.same(5, 7));
    assert(!uf.same(0, 3));
    assert(!uf.same(8, 2));
}

void main() {
    int N, M;
    scan(N, M);
    auto a = new int[](M);
    auto b = new int[](M);
    foreach (i ; 0 .. M) {
        scan(a[i], b[i]);
    }
    a[] -= 1;
    b[] -= 1;

    auto uf = UnionFind(N);

    auto ans = new long[](M + 1);
    ans[M] = 1L * N * (N - 1) / 2;
    foreach_reverse (i ; 0 .. M) {
        if (uf.same(a[i], b[i])) continue;

        int l = uf.size(a[i]);
        int r = uf.size(b[i]);
        ans[i] = ans[i + 1] - 1L * l * r;
        uf.merge(a[i], b[i]);
    }

    writefln("%(%s\n%)", ans[1 .. $]);
}


void scan(T...)(ref T args) {
    auto line = readln.split;
    foreach (ref arg; args) {
        arg = line.front.to!(typeof(arg));
        line.popFront;
    }
    assert(line.empty);
}

void fillAll(R, T)(ref R arr, T value) {
    static if (is(typeof(arr[] = value))) {
        arr[] = value;
    }
    else {
        foreach (ref e; arr) {
            fillAll(e, value);
        }
    }
}

bool chmin(T, U...)(ref T x, U args) {
    bool isChanged;
    foreach (arg; args) if (x > arg) {
        x = arg;
        isChanged = true;
    }
    return isChanged;
}

bool chmax(T, U...)(ref T x, U args) {
    bool isChanged;
    foreach (arg; args) if (x < arg) {
        x = arg;
        isChanged = true;
    }
    return isChanged;
}

void yes(bool ok, string y = "Yes", string n = "No") {
    return writeln(ok ? y : n);
}