#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())
A=[]
B=[]
for i in range(0,M,1):
    a,b=map(int,input().split())
    A.append(a)
    B.append(b)
#初期化
#根なら-size,子なら親の頂点
par = [-1]*(N+1)

ans = []
tmpans = N*(N-1)//2
for i in range(M-1,-1,-1):
    ans.append(tmpans)
    if same(A[i],B[i]):
        tmpans = tmpans
    else:
        tmpans -= size(A[i])*size(B[i])
        unite(A[i],B[i])

for i in range(M-1,-1,-1):
    print(ans[i]) 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 A=[] A [] B=[] B [] for i in range(0,M,1):
    a,b=map(int,input().split())
    A.append(a)
    B.append(b)
#初期化
#根なら-size,子なら親の頂点 i range(0,M,1) range 0 M 1 a,b=map(int,input().split()) a map(int,input().split()) map int input().split() ().split () input split b A.append(a) A.append A append a B.append(b) B.append B append b par = [-1]*(N+1) par [-1]*(N+1) [-1] -1 N+1 N 1 ans = [] ans [] tmpans = N*(N-1)//2 tmpans N*(N-1)//2 N*(N-1) N N-1 N 1 2 for i in range(M-1,-1,-1):
    ans.append(tmpans)
    if same(A[i],B[i]):
        tmpans = tmpans
    else:
        tmpans -= size(A[i])*size(B[i])
        unite(A[i],B[i]) i range(M-1,-1,-1) range M-1 M 1 -1 -1 ans.append(tmpans) ans.append ans append tmpans if same(A[i],B[i]):
        tmpans = tmpans
    else:
        tmpans -= size(A[i])*size(B[i])
        unite(A[i],B[i]) same(A[i],B[i]) same A[i] A i B[i] B i tmpans = tmpans tmpans tmpans tmpans -= size(A[i])*size(B[i]) tmpans size(A[i])*size(B[i]) size(A[i]) size A[i] A i size(B[i]) size B[i] B i unite(A[i],B[i]) unite A[i] A i B[i] B i for i in range(M-1,-1,-1):
    print(ans[i]) i range(M-1,-1,-1) range M-1 M 1 -1 -1 print(ans[i]) print ans[i] ans i M = map(int,input().split()) map(int,input().split()) M tmpans = tmpans tmpans tmpans N,M = map(int,input().split()) map(int,input().split()) N A=[] [] A B=[] [] B b=map(int,input().split()) map(int,input().split()) b ans = [] [] ans a,b=map(int,input().split()) map(int,input().split()) 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 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 size(x):
    return -par[find(x)] def size(x):
    return -par[find(x)] size par = [-1]*(N+1) [-1]*(N+1) par def same(x,y):
    return find(x) == find(y)

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

#xが属する集合の個数 same tmpans -= size(A[i])*size(B[i]) size(A[i])*size(B[i]) tmpans tmpans = N*(N-1)//2 N*(N-1)//2 tmpans
#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())
A=[]
B=[]
for i in range(0,M,1):
    a,b=map(int,input().split())
    A.append(a)
    B.append(b)
#初期化
#根なら-size,子なら親の頂点
par = [-1]*(N+1)

ans = []
tmpans = N*(N-1)//2
for i in range(M-1,-1,-1):
    ans.append(tmpans)
    if same(A[i],B[i]):
        tmpans = tmpans
    else:
        tmpans -= size(A[i])*size(B[i])
        unite(A[i],B[i])

for i in range(M-1,-1,-1):
    print(ans[i])