Buggy python submission (verdict: Time Limit Exceeded):
class UnionFind():
    def __init__(self, size):
        # self.group holds a list of idx for parant node of i-th node
        # if self.group[i] = i, i-th node is a root.
        # if self.group[i] = j, j-th node is a paranet of i-th node. 
        self.group = [i for i in range(size)]
        
        # self.height holds a list of trees' heights
        self.height = [0] * (size)
        
    def find(self, i):
        """
        Search for i-th node's group.
        Args : 
            i : index of target node.
        Return :
            index of root of target node
        """ 
        
        if self.group[i] == i:
            # if root
            return i
        else:
            # if not root, search by the parent's node
            self.group[i] = self.find(self.group[i])
            return self.group[i]     
        
    def unite(self, i, j):
        """
        Unite two groups
        Args : 
            i, j : indices of target nodes.
        """ 
        # search roots
        i = self.find(i)
        j = self.find(j)
        
        if i == j:
            return 
        
        if self.height[i] < self.height[j]:
            self.group[i] = j
        else:
            self.group[j] = i
            if self.height[i] == self.height[j]:
                self.height[i] += 1
                
    def same(self, i, j):
        return self.find(i) == self.find(j)
       
    def size(self, i):
        """
        Get num of nodes in same group
        Args : 
            i : index of target node.
        """
        ans = 1
        root = self.find(i)
        for node_idx, par in enumerate(self.group):
            if root == par:
                ans += 1
            elif root == self.find(par):
                ans += 1
            else:
                pass
        ans -= 1
        return ans
        
        

import numpy as np
N, M = map(int, input().split())
ab_list = [list(map(int, input().split())) for _ in range(M)]

a_list = np.array(ab_list)[:, 0][-1::-1]
b_list = np.array(ab_list)[:, 1][-1::-1]

huben = [int((N) * (N-1) * 0.5)]
        
uni = UnionFind(size=N+1)

for a, b in zip(a_list, b_list):
    a_group = uni.find(a)
    b_group = uni.find(b)
    
    if a_group == b_group:
        huben.append(huben[-1])
    else:
        huben.append(huben[-1] - uni.size(a)*uni.size(b))
        uni.unite(a, b)
        
for ans in huben[-1::-1][1:]:
    print(ans)

Fixed submission:
class UnionFind():
    def __init__(self, size):
        # self.parent holds a list of idx for parant node of i-th node
        # if i-th node is a root, self.parent[i] holds the - (number of nodes) in the parent.
        # if self.parent[i] = j, j-th node is a paranet of i-th node. 
        self.parent = [-1 for _ in range(size)]
        
        # self.height holds a list of trees' heights
        self.height = [0] * (size)
        
    def find(self, i):
        """
        Search for i-th node's parent.
        Args : 
            i : index of target node.
        Return :
            index of root of target node
        """ 
        
        if self.parent[i] < 0:
            # root node
            return i
        else:
            # if not root, search by the parent's node
            self.parent[i] = self.find(self.parent[i])
            return self.parent[i]     
        
    def unite(self, i_, j_):
        """
        Unite two parents
        Args : 
            i, j : indices of target nodes.
        """ 
        # search roots
        i = self.find(i_)
        j = self.find(j_)
        
        if self.height[i] < self.height[j]:
            self.parent[j] += self.parent[i]
            self.parent[i] = j_
            
        else:
            self.parent[i] += self.parent[j]
            self.parent[j] = i_
            if self.height[i] == self.height[j]:
                self.height[i] += 1
       
    def size(self, i):
        """
        Get num of nodes in same parent
        Args : 
            i : index of target node.
        """
        return - self.parent[self.find(i)]
        
        

import numpy as np
N, M = map(int, input().split())
ab_list = [list(map(int, input().split())) for _ in range(M)]

a_list = np.array(ab_list)[:, 0][-1::-1]
b_list = np.array(ab_list)[:, 1][-1::-1]

huben = [int((N) * (N-1) * 0.5)]
        
uni = UnionFind(size=N+1)

for a, b in zip(a_list, b_list):
    a_group = uni.find(a)
    b_group = uni.find(b)
    
    if a_group == b_group:
        huben.append(huben[-1])
    else:
        huben.append(huben[-1] - uni.size(a)*uni.size(b))
        uni.unite(a, b)
        
for ans in huben[-1::-1][1:]:
    print(ans)

Buggy python submission (verdict: Time Limit Exceeded):
class UnionFind():
    def __init__(self, size):
        # self.group holds a list of idx for parant node of i-th node
        # if self.group[i] = i, i-th node is a root.
        # if self.group[i] = j, j-th node is a paranet of i-th node. 
        self.group = [i for i in range(size)]
        
        # self.height holds a list of trees' heights
        self.height = [0] * (size)
        
    def find(self, i):
        """
        Search for i-th node's group.
        Args : 
            i : index of target node.
        Return :
            index of root of target node
        """ 
        
        if self.group[i] == i:
            # if root
            return i
        else:
            # if not root, search by the parent's node
            self.group[i] = self.find(self.group[i])
            return self.group[i]     
        
    def unite(self, i, j):
        """
        Unite two groups
        Args : 
            i, j : indices of target nodes.
        """ 
        # search roots
        i = self.find(i)
        j = self.find(j)
        
        if i == j:
            return 
        
        if self.height[i] < self.height[j]:
            self.group[i] = j
        else:
            self.group[j] = i
            if self.height[i] == self.height[j]:
                self.height[i] += 1
                
    def same(self, i, j):
        return self.find(i) == self.find(j)
       
    def size(self, i):
        """
        Get num of nodes in same group
        Args : 
            i : index of target node.
        """
        ans = 1
        root = self.find(i)
        for node_idx, par in enumerate(self.group):
            if root == par:
                ans += 1
            elif root == self.find(par):
                ans += 1
            else:
                pass
        ans -= 1
        return ans
        
        

import numpy as np
N, M = map(int, input().split())
ab_list = [list(map(int, input().split())) for _ in range(M)]

a_list = np.array(ab_list)[:, 0][-1::-1]
b_list = np.array(ab_list)[:, 1][-1::-1]

huben = [int((N) * (N-1) * 0.5)]
        
uni = UnionFind(size=N+1)

for a, b in zip(a_list, b_list):
    a_group = uni.find(a)
    b_group = uni.find(b)
    
    if a_group == b_group:
        huben.append(huben[-1])
    else:
        huben.append(huben[-1] - uni.size(a)*uni.size(b))
        uni.unite(a, b)
        
for ans in huben[-1::-1][1:]:
    print(ans)

Fixed submission:
class UnionFind():
    def __init__(self, size):
        # self.parent holds a list of idx for parant node of i-th node
        # if i-th node is a root, self.parent[i] holds the - (number of nodes) in the parent.
        # if self.parent[i] = j, j-th node is a paranet of i-th node. 
        self.parent = [-1 for _ in range(size)]
        
        # self.height holds a list of trees' heights
        self.height = [0] * (size)
        
    def find(self, i):
        """
        Search for i-th node's parent.
        Args : 
            i : index of target node.
        Return :
            index of root of target node
        """ 
        
        if self.parent[i] < 0:
            # root node
            return i
        else:
            # if not root, search by the parent's node
            self.parent[i] = self.find(self.parent[i])
            return self.parent[i]     
        
    def unite(self, i_, j_):
        """
        Unite two parents
        Args : 
            i, j : indices of target nodes.
        """ 
        # search roots
        i = self.find(i_)
        j = self.find(j_)
        
        if self.height[i] < self.height[j]:
            self.parent[j] += self.parent[i]
            self.parent[i] = j_
            
        else:
            self.parent[i] += self.parent[j]
            self.parent[j] = i_
            if self.height[i] == self.height[j]:
                self.height[i] += 1
       
    def size(self, i):
        """
        Get num of nodes in same parent
        Args : 
            i : index of target node.
        """
        return - self.parent[self.find(i)]
        
        

import numpy as np
N, M = map(int, input().split())
ab_list = [list(map(int, input().split())) for _ in range(M)]

a_list = np.array(ab_list)[:, 0][-1::-1]
b_list = np.array(ab_list)[:, 1][-1::-1]

huben = [int((N) * (N-1) * 0.5)]
        
uni = UnionFind(size=N+1)

for a, b in zip(a_list, b_list):
    a_group = uni.find(a)
    b_group = uni.find(b)
    
    if a_group == b_group:
        huben.append(huben[-1])
    else:
        huben.append(huben[-1] - uni.size(a)*uni.size(b))
        uni.unite(a, b)
        
for ans in huben[-1::-1][1:]:
    print(ans)

Buggy python submission (verdict: Time Limit Exceeded):
class UnionFind():
    def __init__(self, size):
        # self.group holds a list of idx for parant node of i-th node
        # if self.group[i] = i, i-th node is a root.
        # if self.group[i] = j, j-th node is a paranet of i-th node. 
        self.group = [i for i in range(size)]
        
        # self.height holds a list of trees' heights
        self.height = [0] * (size)
        
    def find(self, i):
        """
        Search for i-th node's group.
        Args : 
            i : index of target node.
        Return :
            index of root of target node
        """ 
        
        if self.group[i] == i:
            # if root
            return i
        else:
            # if not root, search by the parent's node
            self.group[i] = self.find(self.group[i])
            return self.group[i]     
        
    def unite(self, i, j):
        """
        Unite two groups
        Args : 
            i, j : indices of target nodes.
        """ 
        # search roots
        i = self.find(i)
        j = self.find(j)
        
        if self.height[i] < self.height[j]:
            self.group[i] = j
        else:
            self.group[j] = i
            if self.height[i] == self.height[j]:
                self.height[i] += 1
       
    def size(self, i):
        """
        Get num of nodes in same group
        Args : 
            i : index of target node.
        """
        ans = 1
        root = self.find(i)
        for node_idx, par in enumerate(self.group):
            if root == par:
                ans += 1
            elif self.find(par) == root:
                ans += 1
            else:
                pass
        ans -= 1
        return ans
        
        

import numpy as np
N, M = map(int, input().split())
ab_list = [list(map(int, input().split())) for _ in range(M)]

a_list = np.array(ab_list)[:, 0][-1::-1]
b_list = np.array(ab_list)[:, 1][-1::-1]

huben = [int((N) * (N-1) * 0.5)]
        
uni = UnionFind(size=N+1)

for a, b in zip(a_list, b_list):
    a_group = uni.find(a)
    b_group = uni.find(b)
    
    if a_group == b_group:
        huben.append(huben[-1])
    else:
        huben.append(huben[-1] - uni.size(a)*uni.size(b))
        uni.unite(a, b)
        
for ans in huben[-1::-1][1:]:
    print(ans)

Fixed submission:
class UnionFind():
    def __init__(self, size):
        # self.parent holds a list of idx for parant node of i-th node
        # if i-th node is a root, self.parent[i] holds the - (number of nodes) in the parent.
        # if self.parent[i] = j, j-th node is a paranet of i-th node. 
        self.parent = [-1 for _ in range(size)]
        
        # self.height holds a list of trees' heights
        self.height = [0] * (size)
        
    def find(self, i):
        """
        Search for i-th node's parent.
        Args : 
            i : index of target node.
        Return :
            index of root of target node
        """ 
        
        if self.parent[i] < 0:
            # root node
            return i
        else:
            # if not root, search by the parent's node
            self.parent[i] = self.find(self.parent[i])
            return self.parent[i]     
        
    def unite(self, i_, j_):
        """
        Unite two parents
        Args : 
            i, j : indices of target nodes.
        """ 
        # search roots
        i = self.find(i_)
        j = self.find(j_)
        
        if self.height[i] < self.height[j]:
            self.parent[j] += self.parent[i]
            self.parent[i] = j_
            
        else:
            self.parent[i] += self.parent[j]
            self.parent[j] = i_
            if self.height[i] == self.height[j]:
                self.height[i] += 1
       
    def size(self, i):
        """
        Get num of nodes in same parent
        Args : 
            i : index of target node.
        """
        return - self.parent[self.find(i)]
        
        

import numpy as np
N, M = map(int, input().split())
ab_list = [list(map(int, input().split())) for _ in range(M)]

a_list = np.array(ab_list)[:, 0][-1::-1]
b_list = np.array(ab_list)[:, 1][-1::-1]

huben = [int((N) * (N-1) * 0.5)]
        
uni = UnionFind(size=N+1)

for a, b in zip(a_list, b_list):
    a_group = uni.find(a)
    b_group = uni.find(b)
    
    if a_group == b_group:
        huben.append(huben[-1])
    else:
        huben.append(huben[-1] - uni.size(a)*uni.size(b))
        uni.unite(a, b)
        
for ans in huben[-1::-1][1:]:
    print(ans)

Buggy python submission (verdict: Time Limit Exceeded):
import numpy as np
N, M = map(int, input().split())
ab_list = [list(map(int, input().split())) for _ in range(M)]

a_list = np.array(ab_list)[:, 0][-1::-1]
b_list = np.array(ab_list)[:, 1][-1::-1]

huben = [int((N) * (N-1) * 0.5)]

class UnionFind():
    def __init__(self, size):
        # self.group holds a list of idx for parant node of i-th node
        # if self.group[i] = i, i-th node is a root.
        # if self.group[i] = j, j-th node is a paranet of i-th node. 
        self.group = [i for i in range(size)]
        
        # self.height holds a list of trees' heights
        self.height = [0] * (size)
        
    def find(self, i):
        """
        Search for i-th node's group.
        Args : 
            i : index of target node.
        Return :
            index of root of target node
        """ 
        
        if self.group[i] == i:
            # if root
            return i
        else:
            # if not root, search by the parent's node
            self.group[i] = self.find(self.group[i])
            return self.group[i]     
        
    def unite(self, i, j):
        """
        Unite two groups
        Args : 
            i, j : indices of target nodes.
        """ 
        # search roots
        i = self.find(i)
        j = self.find(j)
        
        if self.height[i] < self.height[j]:
            self.group[i] = j
        else:
            self.group[j] = i
            if self.height[i] == self.height[j]:
                self.height[i] += 1
       
    def size(self, i):
        """
        Get num of nodes in same group
        Args : 
            i : index of target node.
        """
        ans = 1
        root = self.find(i)
        for par in self.group:
            if self.find(par) == root:
                ans += 1
        ans -= 1
        return ans
        

uni = UnionFind(size=N+1)

for a, b in zip(a_list, b_list):
    a_group = uni.find(a)
    b_group = uni.find(b)
    
    if a_group == b_group:
        huben.append(huben[-1])
    else:
        huben.append(huben[-1] - uni.size(a)*uni.size(b))
        uni.unite(a, b)
        
for ans in huben[-1::-1][1:]:
    print(ans)

Fixed submission:
class UnionFind():
    def __init__(self, size):
        # self.parent holds a list of idx for parant node of i-th node
        # if i-th node is a root, self.parent[i] holds the - (number of nodes) in the parent.
        # if self.parent[i] = j, j-th node is a paranet of i-th node. 
        self.parent = [-1 for _ in range(size)]
        
        # self.height holds a list of trees' heights
        self.height = [0] * (size)
        
    def find(self, i):
        """
        Search for i-th node's parent.
        Args : 
            i : index of target node.
        Return :
            index of root of target node
        """ 
        
        if self.parent[i] < 0:
            # root node
            return i
        else:
            # if not root, search by the parent's node
            self.parent[i] = self.find(self.parent[i])
            return self.parent[i]     
        
    def unite(self, i_, j_):
        """
        Unite two parents
        Args : 
            i, j : indices of target nodes.
        """ 
        # search roots
        i = self.find(i_)
        j = self.find(j_)
        
        if self.height[i] < self.height[j]:
            self.parent[j] += self.parent[i]
            self.parent[i] = j_
            
        else:
            self.parent[i] += self.parent[j]
            self.parent[j] = i_
            if self.height[i] == self.height[j]:
                self.height[i] += 1
       
    def size(self, i):
        """
        Get num of nodes in same parent
        Args : 
            i : index of target node.
        """
        return - self.parent[self.find(i)]
        
        

import numpy as np
N, M = map(int, input().split())
ab_list = [list(map(int, input().split())) for _ in range(M)]

a_list = np.array(ab_list)[:, 0][-1::-1]
b_list = np.array(ab_list)[:, 1][-1::-1]

huben = [int((N) * (N-1) * 0.5)]
        
uni = UnionFind(size=N+1)

for a, b in zip(a_list, b_list):
    a_group = uni.find(a)
    b_group = uni.find(b)
    
    if a_group == b_group:
        huben.append(huben[-1])
    else:
        huben.append(huben[-1] - uni.size(a)*uni.size(b))
        uni.unite(a, b)
        
for ans in huben[-1::-1][1:]:
    print(ans)