#Union Find

#xの根を求める
def find(x):
    if par[x] < 0:
        return x
    else:
        par[x] = find(par[x])
        return par[x]

#xとyの属する集合の併合
def unite(x,y):
    x = find(x)
    y = find(y)
    
    if x == y:
        return False
    else:
        #sizeの大きいほうがx
        if par[x] > par[y]:
            x,y = y,x
        par[x] += par[y]
        par[y] = x
        return True

#xとyが同じ集合に属するかの判定
def same(x,y):
    return find(x) == find(y)

#xが属する集合の個数
def size(x):
    return -par[find(x)]

N, M = map(int, input().split())
bridges = []

for _ in range(M):
    a, b = map(int, input().split())
    a -= 1
    b -= 1
    bridges.append((a, b))

#初期化
#根なら-size,子なら親の頂点
par = [-1]*N
tot = N*(N-1)//2
ans = [tot]

for a, b in bridges[::-1]:
    if not same(a, b): 
        tot -= size(a)*size(b)
    unite(a, b)
    ans.append(tot)

print('\n'.join(map(str, ans[:-1][::-1]))) def find(x):
    if par[x] < 0:
        return x
    else:
        par[x] = find(par[x])
        return par[x]

#xとyの属する集合の併合 find if par[x] < 0:
        return x
    else:
        par[x] = find(par[x])
        return par[x]

#xとyの属する集合の併合 par[x] < 0 par[x] par x 0 return x x par[x] = find(par[x]) par[x] par x find(par[x]) find par[x] par x return par[x] par[x] par x x x def unite(x,y):
    x = find(x)
    y = find(y)
    
    if x == y:
        return False
    else:
        #sizeの大きいほうがx
        if par[x] > par[y]:
            x,y = y,x
        par[x] += par[y]
        par[y] = x
        return True

#xとyが同じ集合に属するかの判定 unite x = find(x) x find(x) find x y = find(y) y find(y) find y if x == y:
        return False
    else:
        #sizeの大きいほうがx
        if par[x] > par[y]:
            x,y = y,x
        par[x] += par[y]
        par[y] = x
        return True

#xとyが同じ集合に属するかの判定 x == y x y return False False if par[x] > par[y]:
            x,y = y,x
         par[x] > par[y] par[x] par x par[y] par y x,y = y,x x y y x par[x] += par[y] par[x] par x par[y] par y par[y] = x par[y] par y x return True True x x y y def same(x,y):
    return find(x) == find(y)

#xが属する集合の個数 same return find(x) == find(y) find(x) == find(y) find(x) find x find(y) find y x x y y def size(x):
    return -par[find(x)] size return -par[find(x)] -par[find(x)] par[find(x)] par find(x) find x x x N, M = map(int, input().split()) N map(int, input().split()) map int input().split() ().split () input split M bridges = [] bridges [] for _ in range(M):
    a, b = map(int, input().split())
    a -= 1
    b -= 1
    bridges.append((a, b))

#初期化
#根なら-size,子なら親の頂点 _ range(M) range M a, b = map(int, input().split()) a map(int, input().split()) map int input().split() ().split () input split b a -= 1 a 1 b -= 1 b 1 bridges.append((a, b)) bridges.append bridges append (a, b) a b par = [-1]*N par [-1]*N [-1] -1 N tot = N*(N-1)//2 tot N*(N-1)//2 N*(N-1) N N-1 N 1 2 ans = [tot] ans [tot] tot for a, b in bridges[::-1]:
    if not same(a, b): 
        tot -= size(a)*size(b)
    unite(a, b)
    ans.append(tot) a b bridges[::-1] bridges ::-1 -1 if not same(a, b): 
        tot -= size(a)*size(b)
     not same(a, b) same(a, b) same a b tot -= size(a)*size(b) tot size(a)*size(b) size(a) size a size(b) size b unite(a, b) unite a b ans.append(tot) ans.append ans append tot print('\n'.join(map(str, ans[:-1][::-1]))) print '\n'.join(map(str, ans[:-1][::-1])) '\n'.join '\n' join map(str, ans[:-1][::-1]) map str ans[:-1][::-1] [:-1] ans :-1 -1 ::-1 -1 par = [-1]*N [-1]*N par b -= 1 1 b ans = [tot] [tot] ans N, M = map(int, input().split()) map(int, input().split()) N tot -= size(a)*size(b) size(a)*size(b) tot tot = N*(N-1)//2 N*(N-1)//2 tot def unite(x,y):
    x = find(x)
    y = find(y)
    
    if x == y:
        return False
    else:
        #sizeの大きいほうがx
        if par[x] > par[y]:
            x,y = y,x
        par[x] += par[y]
        par[y] = x
        return True

#xとyが同じ集合に属するかの判定 def unite(x,y):
    x = find(x)
    y = find(y)
    
    if x == y:
        return False
    else:
        #sizeの大きいほうがx
        if par[x] > par[y]:
            x,y = y,x
        par[x] += par[y]
        par[y] = x
        return True

#xとyが同じ集合に属するかの判定 unite def same(x,y):
    return find(x) == find(y)

#xが属する集合の個数 def same(x,y):
    return find(x) == find(y)

#xが属する集合の個数 same M = map(int, input().split()) map(int, input().split()) M b = map(int, input().split()) map(int, input().split()) b def size(x):
    return -par[find(x)] def size(x):
    return -par[find(x)] size a, b = map(int, input().split()) map(int, input().split()) a a -= 1 1 a def find(x):
    if par[x] < 0:
        return x
    else:
        par[x] = find(par[x])
        return par[x]

#xとyの属する集合の併合 def find(x):
    if par[x] < 0:
        return x
    else:
        par[x] = find(par[x])
        return par[x]

#xとyの属する集合の併合 find bridges = [] [] bridges
#Union Find

#xの根を求める
def find(x):
    if par[x] < 0:
        return x
    else:
        par[x] = find(par[x])
        return par[x]

#xとyの属する集合の併合
def unite(x,y):
    x = find(x)
    y = find(y)
    
    if x == y:
        return False
    else:
        #sizeの大きいほうがx
        if par[x] > par[y]:
            x,y = y,x
        par[x] += par[y]
        par[y] = x
        return True

#xとyが同じ集合に属するかの判定
def same(x,y):
    return find(x) == find(y)

#xが属する集合の個数
def size(x):
    return -par[find(x)]

N, M = map(int, input().split())
bridges = []

for _ in range(M):
    a, b = map(int, input().split())
    a -= 1
    b -= 1
    bridges.append((a, b))

#初期化
#根なら-size,子なら親の頂点
par = [-1]*N
tot = N*(N-1)//2
ans = [tot]

for a, b in bridges[::-1]:
    if not same(a, b): 
        tot -= size(a)*size(b)
    unite(a, b)
    ans.append(tot)

print('\n'.join(map(str, ans[:-1][::-1])))