Problem:


Score : 400 points

Problem Statement

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?

Constraints

All values in input are integers.

2 ≤ N ≤ 10^5

0 \leq M \leq 10^5

0 \leq K \leq 10^5

1 \leq A_i, B_i \leq N

A_i \neq B_i

1 \leq C_i, D_i \leq N

C_i \neq D_i

(A_i, B_i) \neq (A_j, B_j) (i \neq j)

(A_i, B_i) \neq (B_j, A_j)

(C_i, D_i) \neq (C_j, D_j) (i \neq j)

(C_i, D_i) \neq (D_j, C_j)

(A_i, B_i) \neq (C_j, D_j)

(A_i, B_i) \neq (D_j, C_j)

Input

Input is given from Standard Input in the following format:

N M K
A_1 B_1
\vdots
A_M B_M
C_1 D_1
\vdots
C_K D_K

Output

Print the answers in order, with space in between.

Sample Input 1

4 4 1
2 1
1 3
3 2
3 4
4 1

Sample Output 1

0 1 0 1

There is a friendship between User 2 and 3, and between 3 and 4. Also, there is no friendship or blockship between User 2 and 4. Thus, User 4 is a friend candidate for User 2.

However, neither User 1 or 3 is a friend candidate for User 2, so User 2 has one friend candidate.

Sample Input 2

5 10 0
1 2
1 3
1 4
1 5
3 2
2 4
2 5
4 3
5 3
4 5

Sample Output 2

0 0 0 0 0

Everyone is a friend of everyone else and has no friend candidate.

Sample Input 3

10 9 3
10 1
6 7
8 2
2 5
8 4
7 3
10 9
6 4
5 8
2 6
7 5
3 1

Sample Output 3

1 3 5 4 3 3 3 3 1 0



Sample input:
4 4 1
2 1
1 3
3 2
3 4
4 1


Sample output:
0 1 0 1

Submission status: Accepted

Solution code:
def main():
    import sys
    from collections import defaultdict
    N, M, K = map(int, sys.stdin.readline().split())

    F = [set() for _ in range(N)]
    B = [set() for _ in range(N)]
    for m in range(M):
        a, b = map(int, sys.stdin.readline().split())
        a, b = a - 1, b - 1
        F[a].add(b)
        F[b].add(a)

    for k in range(K):
        c, d = map(int, sys.stdin.readline().split())
        c, d = c - 1, d - 1
        B[c].add(d)
        B[d].add(c)

    D = defaultdict(set)
    parents = [-1] * N
    visited = set()
    for s in range(N):
        if s in visited:
            continue

        stack = [s]
        D[s].add(s)
        while stack:
            n = stack.pop()
            visited.add(n)
            parents[n] = s
            for to in F[n]:
                if to in visited:
                    continue
                D[s].add(to)
                stack.append(to)

    ans = [0] * N
    for i in range(N):
        X = D[parents[i]]
        tmp_ans = 0
        tmp_ans += len(X)
        tmp_ans -= len(F[i])
        tmp_ans -= 1
        for b in B[i]:
            if b in X:
                tmp_ans -= 1
        ans[i] = tmp_ans

    print(*ans, sep=' ')


if __name__ == '__main__':
    main()

Submission status: Accepted

Solution code:
#!/usr/bin/env python3
import sys
from collections import defaultdict

class UnionFind():
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n
        self.ranks = [0] * 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.ranks[x] < self.ranks[y]:
            self.parents[x] = y
        else:
            self.parents[y] = x
            if self.ranks[x] == self.ranks[y]:
                self.ranks[x]+=1

        # 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)

    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]

    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

    def group_count(self):
        return len(self.roots())

    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}

    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())

def tup(a,b):
    return (min(a,b),max(a,b))

def solve(N: int, M: int, K: int, A: "List[int]", B: "List[int]", C: "List[int]", D: "List[int]"):
    friends = set()
    fc = [0 for i in range(N)]
    group = UnionFind(N)
    for i in range(M):
        friends.add(tup(A[i]-1,B[i]-1))
        group.union(A[i]-1,B[i]-1)
        fc[A[i]-1]+=1
        fc[B[i]-1]+=1
    for i in range(K):
        friends.add(tup(C[i]-1,D[i]-1))
        if group.find(C[i]-1) == group.find(D[i]-1):
            fc[C[i]-1]+=1
            fc[D[i]-1]+=1
    result = ""
    isFirst = True
    roots = group.roots()
    rootSets = {r: [] for r in roots }
    for i in range(N):
        r = group.find(i)
        rootSets[r].append(i)
    for i in range(N):
        r = group.find(i)
        c = len(rootSets[r]) - fc[i] - 1
        if not isFirst:
            result+=" "
        else:
            isFirst = False
        result+=str(c)
    print(result)
    return


# Generated by 1.1.6 https://github.com/kyuridenamida/atcoder-tools  (tips: You use the default template now. You can remove this line by using your custom template)
def main():
    def iterate_tokens():
        for line in sys.stdin:
            for word in line.split():
                yield word
    tokens = iterate_tokens()
    N = int(next(tokens))  # type: int
    M = int(next(tokens))  # type: int
    K = int(next(tokens))  # type: int
    A = [int()] * (M)  # type: "List[int]"
    B = [int()] * (M)  # type: "List[int]"
    for i in range(M):
        A[i] = int(next(tokens))
        B[i] = int(next(tokens))
    C = [int()] * (K)  # type: "List[int]"
    D = [int()] * (K)  # type: "List[int]"
    for i in range(K):
        C[i] = int(next(tokens))
        D[i] = int(next(tokens))
    solve(N, M, K, A, B, C, D)

if __name__ == '__main__':
    main()

Submission status: Accepted

Solution code:
from collections import defaultdict


# 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, k = map(int, input().split())
ab = [list(map(int, input().split())) for i in range(m)]
cd = [list(map(int, input().split())) for i in range(k)]

# 初期化
# 根なら-size,子なら親の頂点
par = [-1] * n

not_see = defaultdict(set)

for a, b in ab:
    a -= 1
    b -= 1
    unite(a, b)
    if same(a, b):
        not_see[a].add(b)
        not_see[b].add(a)

for c, d in cd:
    c -= 1
    d -= 1
    if same(c, d):
        not_see[c].add(d)
        not_see[d].add(c)

for i in range(n):
    print(size(i) - len(not_see[i]) - 1)

Submission status: Accepted

Solution code:
class 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)

    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]

    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

    def group_count(self):
        return len(self.roots())

    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}

    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())

      
n,m,k=map(int,input().split())
A=UnionFind(n)
B=[[] for i in range(n)]
for i in range(m):
  a,b=map(int,input().split())
  a=a-1
  b=b-1
  A.union(a,b)
  B[a].append(b)
  B[b].append(a)
C=[[] for i in range(n)]
for i in range(k):
  a,b=map(int,input().split())
  a=a-1
  b=b-1
  C[a].append(b)
  C[b].append(a)
ans=[0]*n
for i in range(n):
  ans[i]=A.size(i)
  a=0
  for j in range(len(B[i])):
    if A.same(i,B[i][j]):
      a=a+1
  b=0
  for j in range(len(C[i])):
    if A.same(i,C[i][j]):
      b=b+1
  ans[i]=ans[i]-a-b
for i in range(n):
  print(ans[i]-1,end=" ")
print()

Submission status: Accepted

Solution code:
# https://note.nkmk.me/python-union-find/
class 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)

    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]

    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

    def group_count(self):
        return len(self.roots())

    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}

    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())

# print('input >>')
N, M, K = map(int,(input().split()))
friend_numbers = [0] * N
block_numbers = [0] * N # ただし同じUnionFind木内のみ
unionFind = UnionFind(N)
for _ in range(M):
    friend = list(map(int,(input().split())))
    i = friend[0]-1
    j = friend[1]-1
    unionFind.union(i, j)
    friend_numbers[i] += 1
    friend_numbers[j] += 1
for _ in range(K):
    block = list(map(int,(input().split())))
    i = block[0]-1
    j = block[1]-1
    if unionFind.same(i, j):
        block_numbers[i] += 1
        block_numbers[j] += 1

# print(friend_numbers)
# print(block_numbers)
# print(unionFind)

for i in range(N):
    print(unionFind.size(i) - friend_numbers[i] - block_numbers[i] - 1, end=' ')    

# print('-----output-----')

Submission status: Accepted

Solution code:
from collections import defaultdict


class UnionFindTree:
    def __init__(self):
        self.p = {}
        self.rank = {}

    def make(self, x):
        self.p[x] = x
        self.rank[x] = 0

    def find(self, x):
        if x in self.p:
            if self.p[x] != x:
                # 経路圧縮
                self.p[x] = self.find(self.p[x])
            return self.p[x]
        return None

    def same(self, x, y):
        return self.find(x) == self.find(y)

    def unite(self, x, y):
        return self._unite(self.find(x), self.find(y))

    def _unite(self, x, y):
        if self.rank[x] < self.rank[y]:
            self.p[x] = y
            return y
        else:
            self.p[y] = x
            if self.rank[x] == self.rank[y]:
                self.rank[x] += 1
            return x


utf = UnionFindTree()
unions = defaultdict(int)
friends = defaultdict(int)
blocks = defaultdict(int)
finds = {}

N, M, K = map(int, input().split())
for i in range(N):
    utf.make(i+1)

for i in range(M):
    a, b = map(int, input().split())
    utf.unite(a, b)
    friends[a] += 1
    friends[b] += 1

for i in range(N):
    f = utf.find(i+1)
    finds[i+1] = f
    unions[f] += 1

for i in range(K):
    c, d = map(int, input().split())
    fc, fd = utf.find(c), utf.find(d)
    if fc == fd:
        blocks[c] += 1
        blocks[d] += 1

ans = [str(unions[finds[i+1]] - friends[i+1] - blocks[i+1] - 1) for i in range(N)]
print(" ".join(ans))

Submission status: Accepted

Solution code:
"""
友達でも嫌いでもない人
友達の友達(の友達の...)
-> ok
"""
class UnionFind():
    # コンストラクタ
    def __init__(self, n):
        # 要素数
        self.n = n
        # parents[i]: 要素iの親要素の番号
        # 要素iが根の場合、parents[i] = -(そのグループの要素数)
        self.parents = [-1] * n

    # 要素xが属するグループの根を返す
    # 経路圧縮
    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    # 要素xが属するグループと要素yが属するグループとを併合する
    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

    # 要素xが属するグループの要素数を返す
    def size(self, x):
        return -self.parents[self.find(x)]

    # 要素x,yが同じグループに属するかどうかを返す
    def same(self, x, y):
        return self.find(x) == self.find(y)

    # 要素xが属するグループに属する要素をリストで返す
    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]

    # 全ての根の要素をリストで返す
    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

    # グループの数を返す
    def group_count(self):
        return len(self.roots())


N,M,K = map(int,input().split())

best = [0] * N

friend = UnionFind(N)
for _ in range(M):
    A,B = map(int,input().split())
    best[A-1] += 1
    best[B-1] += 1
    friend.union(A-1, B-1)

bad = [[] for _ in range(N)]
for _ in range(K):
    C,D = map(int,input().split())
    bad[C-1].append(D-1)
    bad[D-1].append(C-1)


ans = [0] * N
for i in range(N):
    ans[i] = friend.size(i) - best[i] - 1
    for kirai in bad[i]:
        if friend.same(i, kirai):
            ans[i] -= 1

print(*ans, sep=" ")

Submission status: Accepted

Solution code:
import sys
input=sys.stdin.readline

class UnionFind(object):
    def __init__(self, n=1):
        self.par = [i for i in range(n)]
        self.rank = [0 for _ in range(n)]
        self.size = [1 for _ in range(n)]

    def find(self, x):
        """
        x が属するグループを探索
        """
        if self.par[x] == x:
            return x
        else:
            self.par[x] = self.find(self.par[x])
            return self.par[x]

    def union(self, x, y):
        """
        x と y のグループを結合
        """
        x = self.find(x)
        y = self.find(y)
        if x != y:
            if self.rank[x] < self.rank[y]:
                x, y = y, x
            if self.rank[x] == self.rank[y]:
                self.rank[x] += 1
            self.par[y] = x
            self.size[x] += self.size[y]

    def is_same(self, x, y):
        """
        x と y が同じグループか否か
        """
        return self.find(x) == self.find(y)

    def get_size(self, x):
        """
        x が属するグループの要素数
        """
        x = self.find(x)
        return self.size[x]

n,m,k=map(int, input().split())

tk=UnionFind(n)

stk=[0 for _ in range(n)]
blk=[[] for _ in range(n)]

for _ in range(m):
    a,b=map(int, input().split())
    stk[a-1]+=1
    stk[b-1]+=1
    tk.union(a-1, b-1)

for _ in range(k):
    c,d=map(int, input().split())
    blk[c-1].append(d-1)
    blk[d-1].append(c-1)

for i in range(n):
    ans=tk.get_size(i)-1-stk[i]
    for j in blk[i]:
        if tk.is_same(i, j):
            ans-=1
    print(ans)

Submission status: Accepted

Solution code:
import sys
sys.setrecursionlimit(1000000000)

N, M, K = map(int, input().split())

class Account:
    def __init__(self, val):
        self.val = val
        self.friends = []
        self.valid_blocks = 0
        self.graph = 0


def rec(index, past, graph):
    past.add(index)
    graph.add(index)
    account = accounts[index]
    account.graph = count
    for friend in account.friends:
        if friend in past:
            continue
        past, graph = rec(friend, past, graph)
    return past, graph


accounts = [Account(i - 1) for i in range(N)]

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

past = set()
graphs = []
count = 0
for i in range(N):
    if i in past:
        continue
    past, graph = rec(i, past, set())
    graphs.append(graph)
    count += 1

for _ in range(K):
    c, d = map(int, input().split())
    C = accounts[c-1]
    D = accounts[d-1]
    if C.graph == D.graph:
        C.valid_blocks += 1
        D.valid_blocks += 1

answers = [0]*N
for i, account in enumerate(accounts):
    answers[i] = len(graphs[account.graph]) - len(account.friends) - 1 - account.valid_blocks

print(*answers)

Submission status: Accepted

Solution code:
class UnionFind():
    def __init__(self, n):
        self.parents = [-1] * n

    def find(self, x):
        if self.parents[x] < 0:
            return x
        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 main():
    N, M, K = list(map(int, input().split()))
    U = UnionFind(N)
    FR = [0] * N
    for _ in range(M):
        a, b = map(int, input().split())
        U.union(a - 1, b - 1)
        FR[a - 1] += 1
        FR[b - 1] += 1
    r = [0] * N
    LS = {}
    for i in range(N):
        t = U.find(i)
        if t not in LS:
            LS[t] = set()
        LS[t].add(i)
        r[i] = -U.parents[t] - 1 - FR[i]
    for _ in range(K):
        c, d = map(int, input().split())
        c, d = c - 1, d - 1
        if d in LS[U.find(c)]:
            r[c] -= 1
            r[d] -= 1
    print(' '.join(str(i) for i in r))

main()

Submission status: Accepted

Solution code:
from collections import defaultdict
import sys
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
input = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines

class UnionFind :
    def __init__(self, size) :
        self.parent = list(range(size))
        self.height = [0] * size
        self.size = [1] * size
        self.component = size

    def root(self, index) :
        if self.parent[index] == index :  # 根の場合
            return index
        rootIndex = self.root(self.parent[index])  # 葉の場合親の根を取得
        self.parent[index] = rootIndex  # 親の付け直し
        return rootIndex

    def union(self, index1, index2) :  # 結合
        root1 = self.root(index1)
        root2 = self.root(index2)

        if root1 == root2 :  # 連結されている場合
            return

        self.component -= 1  # 連結成分を減らす

        if self.height[root1] < self.height[root2] :
            self.parent[root1] = root2  # root2に結合
            self.size[root2] += self.size[root1]
        else :
            self.parent[root2] = root1  # root1に結合
            self.size[root1] += self.size[root2]
            if self.height[root1] == self.height[root2] :
                self.height[root1] += 1
        return

    def isSameRoot(self, index1, index2) :
        return self.root(index1) == self.root(index2)

    def sizeOfSameRoot(self, index) :
        return self.size[self.root(index)]

    def getComponent(self) :
        return self.component

N, M, K = map(int, input().split())
tree = UnionFind(N)

friend = [[i] for i in range(N)]
for _ in range(M):
    fr, to = map(int, input().split())
    fr -= 1
    to -= 1
    tree.union(fr, to)
    friend[fr].append(to)
    friend[to].append(fr)

dis = [[] for _ in range(N)]
for _ in range(K):
    fr, to = map(int, input().split())
    fr -= 1
    to -= 1
    dis[fr].append(to)
    dis[to].append(fr)

grp = defaultdict(set)
for i in range(N):
    grp[tree.root(i)].add(i)

ans = []
for i in range(N):
    A = grp[tree.root(i)]
    cnt = len(A)
    for to in friend[i]:
        if to in A:
            cnt -= 1
    for to in dis[i]:
        if to in A:
            cnt -= 1
    ans.append(cnt)

print(*ans)

Submission status: Accepted

Solution code:
from sys import setrecursionlimit


def find(parent, i):
    t = parent[i]
    if t < 0:
        return i
    t = find(parent, t)
    parent[i] = t
    return t


def unite(parent, i, j):
    i = find(parent, i)
    j = find(parent, j)
    if i == j:
        return
    parent[j] += parent[i]
    parent[i] = j


setrecursionlimit(10 ** 5)


N, M, K = map(int, input().split())
AB = [list(map(int, input().split())) for _ in range(M)]
CD = [list(map(int, input().split())) for _ in range(K)]

parent = [-1] * N
friends = [[] for _ in range(N)]
for A, B in AB:
    unite(parent, A - 1, B - 1)
    friends[A-1].append(B-1)
    friends[B-1].append(A-1)
blocks = [[] for _ in range(N)]
for C, D in CD:
    blocks[C-1].append(D-1)
    blocks[D-1].append(C-1)

result = []
for i in range(N):
    p = find(parent, i)
    t = -parent[p] - 1
    t -= len(friends[i])
    for b in blocks[i]:
        if p == find(parent, b):
            t -= 1
    result.append(t)
print(*result)

Submission status: Accepted

Solution code:
n,m,k = map(int, input().split())

class UnionFindVerSize():
    def __init__(self, N):
        """ N個のノードのUnion-Find木を作成する """
        # 親の番号を格納する。自分が親だった場合は、自分の番号になり、それがそのグループの番号になる
        self._parent = [n for n in range(0, N)]
        # グループのサイズ（個数）
        self._size = [1] * N

    def find_root(self, x):
        """ xの木の根(xがどのグループか)を求める """
        if self._parent[x] == x: return x
        self._parent[x] = self.find_root(self._parent[x]) # 縮約
        return self._parent[x]

    def unite(self, x, y):
        """ xとyの属するグループを併合する """
        gx = self.find_root(x)
        gy = self.find_root(y)
        if gx == gy: return

        # 小さい方を大きい方に併合させる（木の偏りが減るので）
        if self._size[gx] < self._size[gy]:
            self._parent[gx] = gy
            self._size[gy] += self._size[gx]
        else:
            self._parent[gy] = gx
            self._size[gx] += self._size[gy]

    def get_size(self, x):
        """ xが属するグループのサイズ（個数）を返す """
        return self._size[self.find_root(x)]

    def is_same_group(self, x, y):
        """ xとyが同じ集合に属するか否か """
        return self.find_root(x) == self.find_root(y)

    def calc_group_num(self):
        """ グループ数を計算して返す """
        N = len(self._parent)
        ans = 0
        for i in range(N):
            if self.find_root(i) == i:
                ans += 1
        return ans

uf = UnionFindVerSize(n)

minus = [0] * n

for _ in range(m):
    a,b = map(int, input().split())
    uf.unite(a - 1,b - 1)
    minus[a - 1] += 1
    minus[b - 1] += 1

for _ in range(k):
    c,d = map(int, input().split())
    if uf.is_same_group(c - 1, d - 1):
        minus[c - 1] += 1
        minus[d - 1] += 1

ans = []
for i in range(n):
    ans.append(uf.get_size(i) - minus[i] - 1)

print(" ".join(map(str, ans)))

Submission status: Accepted

Solution code:
import math
import sys
MAX_INT = int(10e15)
MIN_INT = -MAX_INT
mod = 1000000007
sys.setrecursionlimit(1000000)
def IL(): return list(map(int,input().split()))
def SL(): return input().split()
def I(): return int(sys.stdin.readline())
def S(): return input()

def init(n):
  for i in range(1,N+1):
    par[i] = i
    rnk[i] = 0
    size[i] = 1
def find(x):
  if par[x] == x:
    return x
  else:
    par[x] = find(par[x])
    return par[x]
def numfind(x):
  if par[x] == x:
    return size[x]
  else:
    return numfind(par[x])
def unite(x, y):
  x = find(x)
  y = find(y)
  if x == y:
    return
  if (rnk[x] < rnk[y]):
    par[x] = y
    size[y] += size[x]
  else:
    par[y] = x
    size[x] += size[y]
    if(rnk[x] == rnk[y]):
      rnk[x] += 1
def same(x, y):
  return find(x) == find(y)

N,M,K = IL()
ab = [IL() for i in range(M)]
cd = [IL() for i in range(K)]

par = [0 for i in range(N+1)]
rnk = [0 for i in range(N+1)]
size = [0 for i in range(N+1)]
init(N)

fr = [[] for i in range(N+1)]
bl = [[] for i in range(N+1)]
for a,b in ab:
  fr[a].append(b)
  fr[b].append(a)

for a,b in ab:
  if same(a,b):
    continue
  else:
    unite(a,b)

ans = [-1]*N
for i in range(1,N+1):
  cnt = numfind(i) - len(fr[i]) -1
  ans[i-1] = cnt

for c,d in cd:
  if same(c,d):
    ans[c-1] -= 1
    ans[d-1] -= 1
print(*ans)

Submission status: Accepted

Solution code:
# ABC157d


def main():
    import sys
    input = sys.stdin.readline
    sys.setrecursionlimit(10**6)
    # 再帰関数を使わない限りPypyで出すこと

    class UnionFind:
        def __init__(self, n):
            self.tree = [i for i in range(n)]
            self.member = [1]*n

        def root(self, x):
            if(self.tree[x] == x):
                return x
            self.tree[x] = self.root(self.tree[x])
            return self.tree[x]  # 経路圧縮

        def same(self, x, y):  # xとyが同じ木に属するか
            return self.root(x) == self.root(y)

        def unite(self, x, y):
            x = self.root(x)
            y = self.root(y)
            if(x == y):
                return
            new = self.member[x]+self.member[y]
            self.member[x] = new
            self.member[y] = new
            self.tree[x] = y

    n, m, k = map(int, input().split())
    tree = UnionFind(n)

    friend = [set() for i in range(n)]
    for _ in range(m):
        a, b = map(int, input().split())
        friend[a - 1].add(b - 1)
        friend[b - 1].add(a - 1)
        tree.unite(a-1, b-1)
    block = [set() for i in range(n)]
    for _ in range(k):
        c, e = map(int, input().split())
        if tree.same(c - 1, e - 1):
            block[c - 1].add(e - 1)
            block[e - 1].add(c - 1)
    ans = []
    for i in range(n):
        #print(i, tree.member[tree.root(i)], len(friend[i]), len(block[i]))
        ans.append(tree.member[tree.root(i)]-len(friend[i])-len(block[i])-1)
    print(*ans)


if __name__ == '__main__':
    main()

Submission status: Accepted

Solution code:
import sys

sys.setrecursionlimit(10 ** 8)

input = sys.stdin.readline


class 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)

    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]

    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

    def group_count(self):
        return len(self.roots())

    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}

    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())


def main():
    N, M, K = [int(x) for x in input().split()]

    u = UnionFind(N)
    ans1 = [0] * N
    for _ in range(M):
        a, b = [int(x) for x in input().split()]
        ans1[a - 1] += 1
        ans1[b - 1] += 1
        u.union(a - 1, b - 1)

    ans2 = [0] * N
    for _ in range(K):
        a, b = [int(x) for x in input().split()]
        if u.same(a - 1, b - 1):
            ans2[a - 1] += 1
            ans2[b - 1] += 1

    for i in range(N):
        # friblo[i].add(i)
        # print(u.members(i))
        # print(friblo[i])
        # print(len(set(u.members(i)) - friblo[i]), end=" ")
        print(u.size(i) - ans1[i] - ans2[i] - 1, end=" ")


if __name__ == '__main__':
    main()

Submission status: Accepted

Solution code:
class 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)

    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]

    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

    def group_count(self):
        return len(self.roots())

    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}

    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())
    
  

n, m, k = map(int, input().split())

uf = UnionFind(n)

friends = [[] for i in range(n)]
blocks = [[] for i in range(n)]

for i in range(m):
    a, b = map(int, input().split())
    uf.union(a-1, b-1)
    friends[a-1].append(b-1)
    friends[b-1].append(a-1)    
    
for i in range(k):
    c, d = map(int, input().split())
    blocks[c-1].append(d-1)
    blocks[d-1].append(c-1)     
    
for i in range(n):
    tmp = uf.size(i) - len(friends[i]) -1

    for v in blocks[i]:
        if uf.same(i, v):
            tmp -= 1
        
    print(tmp, end=' ')