#!/usr/bin/env python3

from pprint import pprint
import sys

sys.setrecursionlimit(10 ** 6)


# 辺を取り除くのではなく、辺が無い状態から始めて辺を順にグラフに追加していくことを考える
# 最初は辺が無いので不便さは N * (N-1) / 2
# 辺 u <-> v を追加したとき、頂点 u, v が既に到達可能であるなら、不便さは変わらない
# そうでなければ、不便さは直前の値より size[u] * size[v] だけ小さくなる

N, M = map(int, input().split())
edges = []
for _ in range(M):
    u, v = map(int, input().split())
    # 0-index
    edges.append([u-1, v-1])


def root(v):
    if parents[v] < 0:
        return v
    parents[v] = root(parents[v])
    return parents[v]


def has_same_root(u, v):
    return root(u) == root(v)


# unite by size
def unite(u, v):
    u_root = root(u)
    v_root = root(v)
    if size(u_root) > size(v_root):
        u_root, v_root = v_root, u_root
    parents[u_root] -= size(v_root)
    parents[v_root] = u_root


def size(v):
    return -parents[root(v)]


# the parent node of a root node has the size of tree (negative value)
parents = [-1 for v in range(N)]

ans = []
current = N * (N-1) // 2
for i in range(M):
    u, v = edges[M-1-i]
    # print(f'current = {current}')
    # print(f'u = {u}, v = {v}')
    # print(f'parents = {parents}')
    ans.append(current)
    if has_same_root(u, v):
        # print('skip')
        continue
    # print(f'size(u) = {size(u)}, size(v) = {size(v)}')
    current -= size(u) * size(v)
    unite(u, v)
    # print(f'parents = {parents}\n')

for i in reversed(range(M)):
    print(ans[i]) from pprint import pprint import sys sys sys.setrecursionlimit(10 ** 6) sys.setrecursionlimit sys setrecursionlimit 10 ** 6 10 6 N, M = map(int, input().split()) N map(int, input().split()) map int input().split() ().split () input split M edges = [] edges [] for _ in range(M):
    u, v = map(int, input().split())
    # 0-index
    edges.append([u-1, v-1]) _ range(M) range M u, v = map(int, input().split()) u map(int, input().split()) map int input().split() ().split () input split v edges.append([u-1, v-1]) edges.append edges append [u-1, v-1] u-1 u 1 v-1 v 1 def root(v):
    if parents[v] < 0:
        return v
    parents[v] = root(parents[v])
    return parents[v] root if parents[v] < 0:
        return v
     parents[v] < 0 parents[v] parents v 0 return v v parents[v] = root(parents[v]) parents[v] parents v root(parents[v]) root parents[v] parents v return parents[v] parents[v] parents v v v def has_same_root(u, v):
    return root(u) == root(v)


# unite by size has_same_root return root(u) == root(v) root(u) == root(v) root(u) root u root(v) root v u u v v def unite(u, v):
    u_root = root(u)
    v_root = root(v)
    if size(u_root) > size(v_root):
        u_root, v_root = v_root, u_root
    parents[u_root] -= size(v_root)
    parents[v_root] = u_root unite u_root = root(u) u_root root(u) root u v_root = root(v) v_root root(v) root v if size(u_root) > size(v_root):
        u_root, v_root = v_root, u_root
     size(u_root) > size(v_root) size(u_root) size u_root size(v_root) size v_root u_root, v_root = v_root, u_root u_root v_root v_root u_root parents[u_root] -= size(v_root) parents[u_root] parents u_root size(v_root) size v_root parents[v_root] = u_root parents[v_root] parents v_root u_root u u v v def size(v):
    return -parents[root(v)]


# the parent node of a root node has the size of tree (negative value) size return -parents[root(v)] -parents[root(v)] parents[root(v)] parents root(v) root v v v -1 for v in range(N) for v in range(N) v range(N) range N for v in range(N) -1 parents = [-1 for v in range(N)] parents [-1 for v in range(N)] ans = [] ans [] current = N * (N-1) // 2 current N * (N-1) // 2 N * (N-1) N N-1 N 1 2 for i in range(M):
    u, v = edges[M-1-i]
    # print(f'current = {current}')
    # print(f'u = {u}, v = {v}')
    # print(f'parents = {parents}')
    ans.append(current)
    if has_same_root(u, v):
        # print('skip')
        continue
    # print(f'size(u) = {size(u)}, size(v) = {size(v)}')
    current -= size(u) * size(v)
    unite(u, v)
    # print(f'parents = {parents}\n') i range(M) range M u, v = edges[M-1-i] u edges[M-1-i] edges M-1-i M-1 M 1 i v ans.append(current) ans.append ans append current if has_same_root(u, v):
        # print('skip')
        continue
    # print(f'size(u) = {size(u)}, size(v) = {size(v)}')
     has_same_root(u, v) has_same_root u v continue current -= size(u) * size(v) current size(u) * size(v) size(u) size u size(v) size v unite(u, v) unite u v for i in reversed(range(M)):
    print(ans[i]) i reversed(range(M)) reversed range(M) range M print(ans[i]) print ans[i] ans i ans = [] [] ans u, v = map(int, input().split()) map(int, input().split()) u v = edges[M-1-i] edges[M-1-i] v v = map(int, input().split()) map(int, input().split()) v edges = [] [] edges def size(v):
    return -parents[root(v)]


# the parent node of a root node has the size of tree (negative value) def size(v):
    return -parents[root(v)]


# the parent node of a root node has the size of tree (negative value) size current = N * (N-1) // 2 N * (N-1) // 2 current u, v = edges[M-1-i] edges[M-1-i] u def has_same_root(u, v):
    return root(u) == root(v)


# unite by size def has_same_root(u, v):
    return root(u) == root(v)


# unite by size has_same_root current -= size(u) * size(v) size(u) * size(v) current N, M = map(int, input().split()) map(int, input().split()) N def root(v):
    if parents[v] < 0:
        return v
    parents[v] = root(parents[v])
    return parents[v] def root(v):
    if parents[v] < 0:
        return v
    parents[v] = root(parents[v])
    return parents[v] root def unite(u, v):
    u_root = root(u)
    v_root = root(v)
    if size(u_root) > size(v_root):
        u_root, v_root = v_root, u_root
    parents[u_root] -= size(v_root)
    parents[v_root] = u_root def unite(u, v):
    u_root = root(u)
    v_root = root(v)
    if size(u_root) > size(v_root):
        u_root, v_root = v_root, u_root
    parents[u_root] -= size(v_root)
    parents[v_root] = u_root unite parents = [-1 for v in range(N)] [-1 for v in range(N)] parents M = map(int, input().split()) map(int, input().split()) M
#!/usr/bin/env python3

from pprint import pprint
import sys

sys.setrecursionlimit(10 ** 6)


# 辺を取り除くのではなく、辺が無い状態から始めて辺を順にグラフに追加していくことを考える
# 最初は辺が無いので不便さは N * (N-1) / 2
# 辺 u <-> v を追加したとき、頂点 u, v が既に到達可能であるなら、不便さは変わらない
# そうでなければ、不便さは直前の値より size[u] * size[v] だけ小さくなる

N, M = map(int, input().split())
edges = []
for _ in range(M):
    u, v = map(int, input().split())
    # 0-index
    edges.append([u-1, v-1])


def root(v):
    if parents[v] < 0:
        return v
    parents[v] = root(parents[v])
    return parents[v]


def has_same_root(u, v):
    return root(u) == root(v)


# unite by size
def unite(u, v):
    u_root = root(u)
    v_root = root(v)
    if size(u_root) > size(v_root):
        u_root, v_root = v_root, u_root
    parents[u_root] -= size(v_root)
    parents[v_root] = u_root


def size(v):
    return -parents[root(v)]


# the parent node of a root node has the size of tree (negative value)
parents = [-1 for v in range(N)]

ans = []
current = N * (N-1) // 2
for i in range(M):
    u, v = edges[M-1-i]
    # print(f'current = {current}')
    # print(f'u = {u}, v = {v}')
    # print(f'parents = {parents}')
    ans.append(current)
    if has_same_root(u, v):
        # print('skip')
        continue
    # print(f'size(u) = {size(u)}, size(v) = {size(v)}')
    current -= size(u) * size(v)
    unite(u, v)
    # print(f'parents = {parents}\n')

for i in reversed(range(M)):
    print(ans[i])
