CodeEff/ECCO huggingface dataset:
# Original solution
import sys
read = sys.stdin.readline


def readln():
    return list(map(int, read().split()))


N, M = readln()
AB = [readln() for _ in range(M)]
A = [ab[0]-1 for ab in AB[::-1]]
B = [ab[1]-1 for ab in AB[::-1]]


class UnionFind:
    def __init__(self, N):
        self.N = N  # ノード数
        # 親ノードをしめす。負は自身が親ということ。
        self.parent = [-1] * N  # idxが各ノードに対応。

    def root(self, A):
        # print(A)
        # ノード番号を受け取って一番上の親ノードの番号を帰す
        if (self.parent[A] < 0):
            return A
        self.parent[A] = self.root(self.parent[A])  # 経由したノードすべての親を上書き
        return self.parent[A]

    def size(self, A):
        # ノード番号を受け取って、そのノードが含まれている集合のサイズを返す。
        return -self.parent[self.root(A)]

    def concat(self, A, B):
        # ノード番号を2つ受け取って、そのノード同士をつなげる処理を行う。
        # 引数のノードを直接つなぐ代わりに、親同士を連結する処理にする。
        A = self.root(A)
        B = self.root(B)

        # すでにくっついている場合
        if (A == B):
            return False

        # 大きい方に小さい方をくっつけたほうが処理が軽いので大小比較
        if (self.size(A) < self.size(B)):
            A, B = B, A

        # くっつける
        self.parent[A] += self.parent[B]  # sizeの更新
        self.parent[B] = A  # self.rootが呼び出されればBにくっついてるノードもすべて親がAだと上書きされる

        return True


ans = [N * (N - 1) // 2]
uni = UnionFind(N)
for a, b in zip(A, B):
    if uni.root(a) == uni.root(b):
        ans.append(ans[-1])
    else:
        ans.append(ans[-1] - uni.size(a) * uni.size(b))
        uni.concat(a, b)

for a in ans[-2::-1]:
    print(a)


# Optimized solution
import sys
read = sys.stdin.readline


def readln():
    return list(map(int, read().split()))


N, M = readln()
A = []
B = []
for _ in range(M):
    a, b = readln()
    A.append(a-1)
    B.append(b-1)
# AB = [readln() for _ in range(M)]
# A = [ab[0]-1 for ab in AB[::-1]]
# B = [ab[1]-1 for ab in AB[::-1]]
A.reverse()
B.reverse()


class UnionFind:
    def __init__(self, N):
        self.N = N  # ノード数
        # 親ノードをしめす。負は自身が親ということ。
        self.parent = [-1] * N  # idxが各ノードに対応。

    def root(self, A):
        # print(A)
        # ノード番号を受け取って一番上の親ノードの番号を帰す
        if (self.parent[A] < 0):
            return A
        self.parent[A] = self.root(self.parent[A])  # 経由したノードすべての親を上書き
        return self.parent[A]

    def size(self, A):
        # ノード番号を受け取って、そのノードが含まれている集合のサイズを返す。
        return -self.parent[self.root(A)]

    def concat(self, A, B):
        # ノード番号を2つ受け取って、そのノード同士をつなげる処理を行う。
        # 引数のノードを直接つなぐ代わりに、親同士を連結する処理にする。
        A = self.root(A)
        B = self.root(B)

        # すでにくっついている場合
        if (A == B):
            return False

        # 大きい方に小さい方をくっつけたほうが処理が軽いので大小比較
        if (self.size(A) < self.size(B)):
            A, B = B, A

        # くっつける
        self.parent[A] += self.parent[B]  # sizeの更新
        self.parent[B] = A  # self.rootが呼び出されればBにくっついてるノードもすべて親がAだと上書きされる

        return True


ans = [N * (N - 1) // 2]
uni = UnionFind(N)
for a, b in zip(A, B):
    if uni.root(a) == uni.root(b):
        ans.append(ans[-1])
    else:
        ans.append(ans[-1] - uni.size(a) * uni.size(b))
        uni.concat(a, b)

for a in ans[-2::-1]:
    print(a)
# Original solution
import sys
input = sys.stdin.readline

def Find(x, par):
  if par[x] < 0:
    return x
  else:
    # 経路圧縮
    par[x] = Find(par[x], par)
    return par[x]

def Unite(x, y, par, rank):
  x = Find(x, par)
  y = Find(y, par)

  if x != y:
    # rankの低い方を高い方につなげる
    if rank[x] < rank[y]:
      par[y] += par[x]
      par[x] = y
    else:
      par[x] += par[y]
      par[y] = x
      if rank[x] == rank[y]:
        rank[x] += 1

def Same(x, y, par):
  return Find(x, par) == Find(y, par)

def Size(x, par):
  return -par[Find(x, par)]

n, m = list(map(int, input().split()))
L = [[0, 0] for _ in range(m)]
for i in range(m):
    a, b = list(map(int, input().split()))
    a, b = a-1, b-1
    L[i][0] = a
    L[i][1] = b

par = [-1]* n
rank = [0]*n

ans = n*(n-1)//2
anss = [0]*m
for i in reversed(list(range(m))):
    anss[i] = ans
    a = L[i][0]
    b = L[i][1]
    if not Same(a, b, par):
        ans = max(0, ans-Size(a, par)*Size(b, par))
        Unite(a, b, par, rank)
    #print(par)

for i in range(m):
    print((anss[i]))


# Optimized solution
import sys
input = sys.stdin.buffer.readline

n, m = list(map(int, input().split()))
X = []
for i in range(m):
    a, b = list(map(int, input().split()))
    a, b = a-1, b-1
    X.append((a, b))

X.reverse()

def Find(x, par):
    if par[x] < 0:
        return x
    else:
        par[x] = Find(par[x], par)
        return par[x]

def Unite(x, y, par, rank):
    x = Find(x, par)
    y = Find(y, par)

    if x != y:
        if rank[x] < rank[y]:
            par[y] += par[x]
            par[x] = y
        else:
            par[x] += par[y]
            par[y] = x
            if rank[x] == rank[y]:
                rank[x] += 1

def Same(x, y, par):
    return Find(x, par) == Find(y, par)

def Size(x, par):
    return -par[Find(x, par)]

temp = n*(n-1)//2
ans = [0]*m

par = [-1]* n
rank = [0]*n

for i in range(m):
    a, b = X[i]
    ans[i] = temp
    if Same(a, b, par):
        continue
    else:
        pre_a = Size(a, par)
        pre_b = Size(b, par)
        Unite(a, b, par, rank)
        temp -= pre_a*pre_b
        #if temp <= 0:
        #temp = 0

ans.reverse()
#print(ans)
for i in range(len(ans)):
    print((ans[i]))
# Original solution
N, M = list(map(int, input().split()))

AB = []
for i in range(M):
    A, B = list(map(int, input().split()))
    AB.append([A, B, i])

AB_ = AB[::-1]

#print(AB)
#print(AB_)

ma = N * (N-1) // 2

path = []
subs = [0]
for i in range(len(AB_)):
    f0 = -1
    f1 = -1
    sub = 0
    for p in range(len(path)):
        if AB_[i][0] in path[p]:
            path[p] += [AB_[i][1]]
            f0 = p
        elif AB_[i][1] in path[p]:
            path[p] += [AB_[i][0]]
            f1 = p
            
    if  (f0 > -1) and (f1 > -1):
        #print("@", path[f0] + path[f1])
        s = list(set(path[f0] + path[f1]))
        if f0 > f1:
            path.pop(f0)
            path.pop(f1)
            path.append(s)
        elif f1 > f0:
            path.pop(f1)
            path.pop(f0)
            path.append(s)

    if  (f0 == -1) and (f1 == -1):
        path.append([AB_[i][0], AB_[i][1]])
        
    for p in range(len(path)):
        sub += len(list(set(path[p]))) * (len(list(set(path[p])))-1) // 2
    subs.append(sub)

#print(subs)

for i in range(2, len(subs)+1):
    print((ma-subs[-i]))

# Optimized solution

class UnionFind:
    def __init__(self, N):
        self.parents = [i for i in range(N)]
        self.sizes = [1 for _ in range(N)]
        
    # 木の根をまとめる, 頂点 v が属するグループ番号を得る (O(α(n)))
    def root(self, x):
        if self.parents[x] == x:
            return x # 根
        else:
            self.parents[x] = self.root(self.parents[x]) # 経路圧縮
            return self.parents[x]
            
    # xとyが同じ集合に属するか否か
    def is_same(self, x, y):
        return self.root(x) == self.root(y)
        
    # xとyの属する集合を併合, 頂点 u が属するグループと頂点 v が属するグループを併合し、同じグループにする (O(α(n)))
    def unite(self, x, y):
        x = self.root(x)
        y = self.root(y)
        if x == y:
            return False
        if self.sizes[x] < self.sizes[y]:
            x, y = y, x
        self.sizes[x] += self.sizes[y]
        self.parents[y] = x
        return True
    
    # 頂点 v が属するグループと同じグループに属する頂点数を得る (O(1))
    def size(self, x):
        return self.sizes[self.root(x)]
        
        
        
N, M = list(map(int, input().split()))

tree = UnionFind(N)

AB = []
for _ in range(M):
    a, b = list(map(int, input().split()))
    AB.append([a, b])

AB = AB[::-1]

tree = UnionFind(N)
ans = [N*(N-1)//2]
for i in range(M):
    a, b = AB[i]
    a, b = tree.root(a-1), tree.root(b-1)
    if a != b:
        ans.append(ans[-1] - tree.size(a)*tree.size(b))
    else:
        ans.append(ans[-1])
    tree.unite(a, b)

ans = ans[:M][::-1]
for i in range(M):
    print((ans[i]))
# Original solution
import sys
sys.setrecursionlimit(100000)
input = sys.stdin.readline
n,m=list(map(int,input().split()))
z=n*(n-1)//2
l=[-1]*n
a=[1]*n
b=[input().split() for _ in range(m)]
c=[0]*m+[z]
def r(s):
  t=l[s]
  return s if t<0 else r(t)
def f(s):
  return r(int(s)-1)
for i in range(m-1,-1,-1):
  x,y=list(map(f,b[i]))
  if x!=y:
    l[x]=y
    l=list([y if w==x else w for w in l])
    z-=a[x]*a[y]
    a[y]+=a[x]
  c[i]=z
for x in c[1:]:
  print(x)

# Optimized solution
import sys
sys.setrecursionlimit(100000)
input = sys.stdin.readline
n,m=list(map(int,input().split()))
z=n*(n-1)//2
l=[-1]*n
a=[1]*n
b=[input().split() for _ in range(m)]
c=[0]*m+[z]
d=[i for i in range(n)]
def r(s):
  t=l[s]
  if t<0:
    return s
  else:
    l[s]=r(t)
    return l[s]
def f(s):
  return r(int(s)-1)
for i in range(m-1,-1,-1):
  x,y=list(map(f,b[i]))
  if x!=y:
    l[x]=d[y]
    d[y]=d[x]
    z-=a[x]*a[y]
    a[y]+=a[x]
  c[i]=z
for x in c[1:]:
  print(x)
# Original solution
import sys
sys.setrecursionlimit(100000)
input = sys.stdin.readline
n,m=list(map(int,input().split()))
z=n*(n-1)//2
l=[-1]*n
a=[1]*n
b=[input().split() for _ in range(m)]
c=[0]*m+[z]
d=[i for i in range(n)]
def r(s):
  t=l[s]
  if t<0:
    return s
  else:
    l[s]=r(t)
    return l[s]
def f(s):
  return r(int(s)-1)
for i in range(m-1,-1,-1):
  x,y=list(map(f,b[i]))
  if x!=y:
    l[x]=y
    d[y]=d[x]
    z-=a[x]*a[y]
    a[y]+=a[x]
  c[i]=z
for x in c[1:]:
  print(x)

# Optimized solution
import sys
sys.setrecursionlimit(100000)
input = sys.stdin.readline
n,m=list(map(int,input().split()))
z=n*(n-1)//2
l=[-1]*n
a=[1]*n
b=[input().split() for _ in range(m)]
c=[0]*m+[z]
def r(s):
  t=l[s]
  if t<0:
    return s
  else:
    l[s]=r(t)
    return l[s]
def f(s):
  return r(int(s)-1)
for i in range(m-1,-1,-1):
  x,y=list(map(f,b[i]))
  if x!=y:
    s,t=a[x],a[y]
    z-=s*t
    if s<t:
      l[x]=y
      a[y]+=s
    else:
      l[y]=x
      a[x]+=t
  c[i]=z
for x in c[1:]:
  print(x)
# Original solution
import sys
sys.setrecursionlimit(100000)
input = sys.stdin.readline
n,m=list(map(int,input().split()))
z=n*(n-1)//2
l=[-1]*n
a=[1]*n
b=[input().split() for _ in range(m)]
c=[0]*m+[z]
def r(s):
  t=l[s]
  if t<0:
    return s
  else:
    l[s]=r(t)
    return l[s]
for i in range(m-1,-1,-1):
  x,y=[r(int(w)-1) for w in b[i]]
  if x!=y:
    z-=a[x]*a[y]
    l[x]=y
    a[y]+=a[x]
  c[i]=z
for x in c[1:]:
  print(x)

# Optimized solution
import sys
sys.setrecursionlimit(100000)
input=sys.stdin.readline
n,m=list(map(int,input().split()))
z=n*(n-1)//2
l=[-1]*n
a=[1]*n
b=[input().split() for _ in range(m)]
c=[0]*m+[z]
def r(s):
  t=l[s]
  if t<0:
    return s
  else:
    l[s]=r(t)
    return l[s]
def f(s):
  return r(int(s)-1)
for i in range(m-1,-1,-1):
  x,y=list(map(f,b[i]))
  if x!=y:
    s,t=a[x],a[y]
    z-=s*t
    if s<t:
      l[x]=y
      a[y]+=s
    else:
      l[y]=x
      a[x]+=t
  c[i]=z
for x in c[1:]:
  print(x)
# Original solution
n,m=list(map(int,input().split()))
l=[-1]*n
b=[input().split() for _ in range(m)]
c=[0]*m+[n*(n-1)//2]
def r(s):
  t=l[s]
  if t<0:
    return s
  else:
    l[s]=r(t)
    return l[s]
def f(s):
  return r(int(s)-1)
for i in range(m-1,-1,-1):
  x,y=list(map(f,b[i]))
  s,t=0,0
  if x!=y:
    s,t=l[x],l[y]
    if s>t:
      l[x]=y
      l[y]+=s
    else:
      l[y]=x
      l[x]+=t
  c[i]=c[i+1]-s*t
for x in c[1:]:
  print(x)

# Optimized solution
import sys
n,m=list(map(int,input().split()))
l=[-1]*n
b=[sys.stdin.readline().split() for _ in range(m)]
c=[0]*m+[n*(n-1)//2]
def r(s):
  t=l[s]
  if t<0:
    return s
  else:
    l[s]=r(t)
    return l[s]
def f(s):
  return r(int(s)-1)
for i in range(m-1,-1,-1):
  x,y=list(map(f,b[i]))
  s,t=0,0
  if x!=y:
    s,t=l[x],l[y]
    if s>t:
      l[x]=y
      l[y]+=s
    else:
      l[y]=x
      l[x]+=t
  c[i]=c[i+1]-s*t
for x in c[1:]:
  print(x)
# Original solution
import sys
n,m=list(map(int,input().split()))
l=[-1]*n
b=[sys.stdin.readline().split() for _ in range(m)]
c=[0]*m+[n*(n-1)//2]
def r(s):
  t=l[s]
  if t<0:
    return s
  else:
    l[s]=r(t)
    return l[s]
def f(s):
  return r(int(s)-1)
for i in range(m-1,-1,-1):
  x,y=list(map(f,b[i]))
  s,t=0,0
  if x!=y:
    s,t=l[x],l[y]
    if s>t:
      l[x]=y
      l[y]+=s
    else:
      l[y]=x
      l[x]+=t
  c[i]=c[i+1]-s*t
for x in c[1:]:
  print(x)

# Optimized solution
import sys
input=sys.stdin.readline
n,m=list(map(int,input().split()))
l=[-1]*n
z=n*(n-1)//2
b=[input().split() for _ in range(m)]
c=[0]*m+[z]
def r(s):
  t=l[s]
  if t<0:
    return s
  else:
    l[s]=r(t)
    return l[s]
def f(s):
  return r(int(s)-1)
for i in range(m)[::-1]:
  x,y=list(map(f,b[i]))
  if x!=y:
    s,t=l[x],l[y]
    z-=s*t
    if s>t:
      l[x]=y
      l[y]+=s
    else:
      l[y]=x
      l[x]+=t
  c[i]=z
for x in c[1:]:
  print(x)
# Original solution
import sys
input=sys.stdin.readline
n,m=list(map(int,input().split()))
l=[-1]*n
z=n*(n-1)//2
b=[input().split() for _ in range(m)]
c=[0]*(m-1)+[z]
def r(s):
  t=l[s]
  if t<0:
    return s
  else:
    l[s]=r(t)
    return l[s]
def f(s):
  return r(int(s)-1)
for i in range(m-1,0,-1):
  x,y=list(map(f,b[i]))
  if x!=y:
    s,t=l[x],l[y]
    z-=s*t
    if s<t:
      l[y]=x
      l[x]+=t
    else:
      l[x]=y
      l[y]+=s
  c[i-1]=z
for x in c:
  print(x)

# Optimized solution
import sys
input=sys.stdin.readline
n,m=list(map(int,input().split()))
l=[-1]*n
z=n*(n-1)//2
b=[input().split() for _ in range(m)]
c=[0]*(m-1)+[z]
def r(s):
  t=l[s]
  if t<0:
    return s
  else:
    l[s]=r(t)
    return l[s]
def f(s):
  return r(int(s)-1)
for i in range(m-1,0,-1):
  x,y=list(map(f,b[i]))
  if x!=y:
    s,t=l[x],l[y]
    z-=s*t
    if s>t:
      l[x]=y
      l[y]+=s
    else:
      l[y]=x
      l[x]+=t
  c[i-1]=z
for x in c:
  print(x)
# Original solution
#!/usr/bin/python3
# -*- coding:utf-8 -*-

class UnionFindTree:
  def __init__(self, n):
    self.nodes = [-1]*n
    
  def find(self, x):
    parents = []
    while True:
      parent = self.nodes[x]
      if parent < 0:
        for p in parents:
          self.nodes[p] = x
        return x
      else:
        x = parent
  
  def unite(self, x, y):
    xp = self.find(x)
    yp = self.find(y)
    self.nodes[xp] += self.nodes[yp]
    self.nodes[yp] = xp  
  
  def size(self, x):
    return -self.nodes[self.find(x)]


def main():
  n, m = list(map(int, input().split()))
  edges = []
  
  for _ in range(m):
    a, b = [int(x)-1 for x in input().split()]
    edges.append((a, b))
  uftree = UnionFindTree(n)
  scores = []
  
  for a, b in edges[::-1]:
    ap = uftree.find(a)
    bp = uftree.find(b)
    if  ap != bp:
      scores.append(uftree.size(ap) * uftree.size(bp))
      uftree.unite(a, b)    
    else:
      scores.append(0)
      
  sum = 0
  for score in scores[::-1]:
    sum += score
    print(sum)

if __name__=='__main__':
  main()



# Optimized solution
#!/usr/bin/python3
# -*- coding:utf-8 -*-

class UnionFindTree:
  def __init__(self, n):
    self.nodes = [-1]*n
    
  def find(self, x):
      parent = self.nodes[x]
      if parent < 0:
        return x
      else:
        self.nodes[x] = self.find(self.nodes[x])
        return self.nodes[x]
  
  def unite(self, x, y):
    xp = self.find(x)
    yp = self.find(y)
    if self.nodes[xp] > self.nodes[yp]:
      xp, yp = yp, xp
    self.nodes[xp] += self.nodes[yp]
    self.nodes[yp] = xp  
  
  def size(self, x):
    return -self.nodes[self.find(x)]


def main():
  n, m = list(map(int, input().split()))
  edges = []
  
  for _ in range(m):
    a, b = [int(x)-1 for x in input().split()]
    edges.append((a, b))
  uftree = UnionFindTree(n)
  scores = []
  
  for a, b in edges[::-1]:
    ap = uftree.find(a)
    bp = uftree.find(b)
    if  ap != bp:
      scores.append(uftree.size(ap) * uftree.size(bp))
      uftree.unite(a, b)    
    else:
      scores.append(0)
      
  sum = 0
  for score in scores[::-1]:
    sum += score
    print(sum)

if __name__=='__main__':
  main()
# Original solution
n,m=list(map(int,input().split()))
par=[-1]*n
def find(n):
    if par[n]<0:
        return n
    else:
        par[n]=find(par[n])
        return par[n]
def union(x,y):
    x,y=find(x),find(y) 
    if x!=y:
        if x>y:
            x,y=y,x
        par[x]+=par[y]
        par[y]=x
M=[]
for i in range(m):
    a,b=list(map(int,input().split()))
    M.append([a,b])
ANS=[n*(n-1)//2]
for i in reversed(list(range(1,m))):
    s=n*(n-1)//2
    a,b=M[i][0],M[i][1]
    union(a-1,b-1)
    for i in range(n):
        if par[i]<-1:
            s-=par[i]*(par[i]+1)//2
    ANS.append(s)
for ans in ANS[::-1]:
    print(ans)

# Optimized solution
n,m=list(map(int,input().split()))
par=[-1]*n
def find(n):
    if par[n]<0:
        return n
    else:
        par[n]=find(par[n])
        return par[n]
def union(x,y,s):
    x,y=find(x),find(y) 
    if x!=y:
        if x>y:
            x,y=y,x
        s-=par[x]*par[y]
        par[x]+=par[y]
        par[y]=x
    return s
        
M=[]
for i in range(m):
    a,b=list(map(int,input().split()))
    M.append([a,b])
ANS=[n*(n-1)//2]
s=n*(n-1)//2
for i in reversed(list(range(1,m))):
    a,b=M[i][0],M[i][1]
    s=union(a-1,b-1,s)
    ANS.append(s)
for ans in ANS[::-1]:
    print(ans)
# Original solution
class Unionfind():  # Unionfind
    def __init__(self, N):
        self.N = N
        self.parents = [-1] * N

    def find(self, x):  # グループの根
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    def union(self, x, y):  # グループの併合
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return
        if self.parents[x] > self.parents[y]:
            x, y = y, x
        self.parents[x] += self.parents[y]
        self.parents[y] = x

    def size(self, x):  # グループのサイズ
        return - self.parents[self.find(x)]

    def same(self, x, y):  # 同じグループか否か
        return self.find(x) == self.find(y)


n, m = map(int, input().split())
ab = [list(map(int, input().split())) for _ in range(m)]

uf = Unionfind(n)
ans, cnt = [], n * (n - 1) // 2
for a, b in ab[::-1]:
    ans.append(max(cnt, 0))
    if not uf.same(a - 1, b - 1):
        cnt -= uf.size(a - 1) * uf.size(b - 1)
        uf.union(a - 1, b - 1)
print(*ans[::-1], sep='\n')


# Optimized solution
class Unionfind():  # Unionfind
    def __init__(self, N):
        self.N = N
        self.parents = [-1] * N

    def find(self, x):  # グループの根
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    def union(self, x, y):  # グループの併合
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return
        if self.parents[x] > self.parents[y]:
            x, y = y, x
        self.parents[x] += self.parents[y]
        self.parents[y] = x

    def size(self, x):  # グループのサイズ
        return - self.parents[self.find(x)]


n, m = map(int, input().split())
ab = [list(map(int, input().split())) for _ in range(m)]

uf = Unionfind(n)
ans, cnt = [], n * (n - 1) // 2
for a, b in ab[::-1]:
    ans.append(max(cnt, 0))
    if uf.find(a - 1) != uf.find(b - 1):
        cnt -= uf.size(a - 1) * uf.size(b - 1)
        uf.union(a - 1, b - 1)
print(*ans[::-1], sep='\n')
# Original solution
N,M=[int(x) for x in input().split()]
I=[[] for n in range(N)]
ans = int(N * (N-1) / 2)
E=[]
result=[]

def visit(i,V):
    if(V[i]==0):
        V[i]=1
        total=1;
        for n in I[i]:
            if(V[n]==0):
                total+=visit(n,V)
        return total
    else:
        return 0

for m in range(M):
    A,B=[int(x) for x in input().split()]
    E.append((A-1,B-1))

for m in range(M):
    result.append(ans)
    if(ans>0):
        A,B=E.pop()
        V=[0 for n in range(N)]
        Wa=visit(A,V)
        Wb=visit(B,V)
        ans=ans-(Wa*Wb)
        I[A].append(B)
        I[B].append(A)

for r in reversed(result):
    print(r)


# Optimized solution
N,M=[int(x) for x in input().split()]
G=[-1] * N
W=[0] * N
E=[]

result=[]
ans = int(N * (N-1) / 2)

def union(i,j):
    gi=find(i)
    gj=find(j)

    if(gi!=gj):
        if W[gi] > W[gj]:
            G[gi]+=G[gj]
            G[gj]=gi
        else:
            G[gj]+=G[gi]
            G[gi]=gj
            if W[gi]==W[gj]:
                W[gj]+=1

def find(i):
    if G[i]<0:
        return i;
    else:
        G[i]=find(G[i])
        return G[i]

for m in range(M):
    A,B=[int(x) for x in input().split()]
    E.append((A-1,B-1))

for m in range(M):
    result.append(ans)
    if(ans>0):
        A,B=E.pop()
        ga,gb=find(A),find(B)
        if (ga!=gb):
            ans=ans-(G[ga]*G[gb])
            union(A,B)

for r in reversed(result):
    print(r)
# Original solution
n, m = list(map(int, input().split()))
ab = [list(map(int, input().split())) for _ in range(m)]

ans = [n*(n-1)//2]
remains = set(range(1, n+1))
sets = []
for i in range(m-1):
    a, b = ab[-(i+1)]
    if a in remains and b in remains:
        sets.append(set([a, b]))
        remains.remove(a)
        remains.remove(b)
        ans.append(ans[i] - 1)
    elif a not in remains and b in remains:
        for i_set in range(len(sets)):
            if a in sets[i_set]:
                size_a = len(sets[i_set])
                sets[i_set].add(b)
                remains.remove(b)
                ans.append(ans[i] - size_a)
                break
    elif a in remains and b not in remains:
        for i_set in range(len(sets)):
            if b in sets[i_set]:
                size_b = len(sets[i_set])
                sets[i_set].add(a)
                remains.remove(a)
                ans.append(ans[i] - size_b)
                break
    else:
        i_set_a, i_set_b = None, None
        for i_set in range(len(sets)):
            if a in sets[i_set]:
                i_set_a = i_set
                size_a = len(sets[i_set])
            if b in sets[i_set]:
                i_set_b = i_set
                size_b = len(sets[i_set])
            if i_set_a is not None and i_set_b is not None:
                break
        if i_set_a == i_set_b:
            ans.append(ans[i])
        else:
            sets[i_set_a] = sets[i_set_a].union(sets[i_set_b])
            sets.pop(i_set_b)
            ans.append(ans[i] - size_a*size_b)
    # print(sets, remains)

for a in ans[::-1]:
    print(a)


# Optimized solution
import sys
sys.setrecursionlimit(100000)

n, m = list(map(int, input().split()))
ab = [list(map(int, input().split())) for _ in range(m)][::-1]

par, sizes = [-1]*(n+1), [1]*(n+1)
def find(i):
    if par[i] < 0:
        return i
    else:
        par[i] = find(par[i])
        return par[i]

ans = [n*(n-1)//2]
for i in range(m-1):
    a, b = ab[i]
    pa, pb = find(a), find(b)

    if pa != pb:
        ans.append(ans[i] - sizes[pa]*sizes[pb])
        par[pa] = pb
        sizes[pb] += sizes[pa]
    else:
        ans.append(ans[i])
    # print(par, sizes)

for ans_ in ans[::-1]:
    print(ans_)