Problem: An SNS has N users - User 1, User 2, \cdots, User N.  Between these N users, there are some relationships - M _friendships_ and K _blockships_.  For each i = 1, 2, \cdots, M, there is a bidirectional friendship between User A_i and User B_i.  For each i = 1, 2, \cdots, K, there is a bidirectional blockship between User C_i and User D_i.  We define User a to be a _friend candidate_ for User b when all of the following four conditions are satisfied:    * a \neq b.   * There is not a friendship between User a and User b.   * There is not a blockship between User a and User b.   * There exists a sequence c_0, c_1, c_2, \cdots, c_L consisting of integers between 1 and N (inclusive) such that c_0 = a, c_L = b, and there is a friendship between User c_i and c_{i+1} for each i = 0, 1, \cdots, L - 1.  For each user i = 1, 2, ... N, how many friend candidates does it have?

Submission attempts (in order):
import sys
input = sys.stdin.buffer.readline

def main():
    n, m, k = map(int, input().split())
    parent_f = list(range(n+1))
    rank_f = [0]*(n+1)
    parent_b = list(range(n+1))
    rank_b = [0]*(n+1)
    group_f = [set() for _ in range(n+1)]
    group_b = [set() for _ in range(n+1)]
    group_index_f = [None]*(n+1)
    group_index_b = [None]*(n+1)
    friends = [set() for i in range(n+1)]
    blocks = [set() for i in range(n+1)]
    for _ in range(m):
        a, b = map(int, input().split())
        friends[a] |= {b}
        friends[b] |= {a}
        unite(a, b, parent_f, rank_f)
    for _ in range(k):
        c, d = map(int, input().split())
        blocks[c] |= {d}
        blocks[d] |= {c}
        unite(c, d, parent_b, rank_b)
    for i in range(1, n+1):
        rf = root(i, parent_f)
        rb = root(i, parent_b)
        group_f[rf] |= {i}
        group_b[rb] |= {i}
        group_index_f[i] = rf
        group_index_b[i] = rb
    for i in range(1, n+1):
        print(len(group_f[group_index_f[i]]-friends[i]-blocks[i]-{i}))
    
    

def root(x, parent):
    if parent[x] == x:
        return x
    parent[x] = root(parent[x], parent)
    return parent[x]

def unite(x, y, parent, rank):
    x = root(x, parent)
    y = root(y, parent)
    if x != y:
        if rank[x] > rank[y]:
            parent[y] = x
        elif rank[x] < rank[y]:
            parent[x] = y
        else:
            parent[y] = x
            rank[x] += 1

if __name__ == "__main__":
    main()

def main():
    n, m, k = map(int, input().split())
    fb = [0]*(n+1)
    uf = UnionFind(n)
    for i in range(m):
        a, b = map(int, input().split())
        fb[a] += 1
        fb[b] += 1
        uf.unite(a, b)
    for i in range(k):
        c, d = map(int, input().split())
        
        if uf.same(c, d):
            fb[c] += 1
            fb[d] += 1
    ans = [uf.size(i)-1-fb[i] for i in range(1, n+1)]
    print(" ".join(list(map(str, ans))))


class UnionFind:
    __slots__ = ["data"]
    
    def __init__(self, n=0):
        self.data = [-1]*(n+1)
    
    def root(self, x):
        if self.data[x] < 0:
            return x
        self.data[x] = self.root(self.data[x])
        return self.data[x]
    
    def unite(self, x, y):
        x = self.root(x)
        y = self.root(y)
        if x != y:
            if self.data[x] < self.data[y]:
                self.data[x] += self.data[y]
                self.data[y] = x
            else:
                self.data[y] += self.data[x]
                self.data[x] = y
    
    def same(self, x, y):
        return self.root(x) == self.root(y)
    
    def size(self, x):
        return -self.data[self.root(x)]



if __name__ == "__main__":
    main()

Verdicts: Time Limit Exceeded

Accepted