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:
n, m, k = map(int, input().split())

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 ''.join('{}: {}'.format(r, self.members(r)) for r in self.roots())

uf = UnionFind(n)

from collections import defaultdict
direct_f = defaultdict(int)
for i in range(m):
    a, b = map(int, input().split())
    a -= 1
    b -= 1
    direct_f[a] += 1
    direct_f[b] += 1
    uf.union(a, b)
ans = [uf.size(i) - direct_f[i] - 1 for i in range(n)]
for i in range(k):
    c, d = map(int, input().split())
    c -= 1
    d -= 1
    if uf.same(c,d):
        ans[c] -= 1
        ans[d] -= 1
print(*ans)

Submission status: Accepted

Solution code:
import sys
from collections import deque

def read():
    return sys.stdin.readline().rstrip()

def main():
    n, m, k = map(int, read().split())
    friend = [[] for _ in range(n)]
    block = [set() for _ in range(n)]
    potential = [set() for _ in range(n)]
    for _ in range(m):
        a, b = [int(i) - 1 for i in read().split()]
        friend[a].append(b)
        friend[b].append(a)
    for _ in range(k):
        c, d = [int(i) - 1 for i in read().split()]
        block[c].add(d)
        block[d].add(c)
    sd = set()
    for u in range(n):
        if u in sd:
            continue
        sn = deque([u])
        pf = set()
        while sn:
            p = sn.pop()
            if p in sd:
                continue
            sd.add(p)
            pf.add(p)
            for f in friend[p]:
                sn.append(f)
        for pfi in pf:
            potential[pfi] = pf
    print(*[len(potential[i]) - len(block[i] & potential[i]) - len(friend[i]) - 1 for i in range(n)])

if __name__ == '__main__':
    main()

Submission status: Accepted

Solution code:
N, M, K = map(int, input().split())
F = [[] for _ in range(N)]
B = [[] for _ in range(N)]

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

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


D = {}
parent = [-1] * N
visited = [False] * N
for root in range(N):
    if visited[root]:
        continue

    D[root] = set([root])
    stack = [root]
    while stack:
        n = stack.pop()
        visited[n] = True
        parent[n] = root

        for to in F[n]:
            if visited[to]:
                continue
            D[root].add(to)
            stack.append(to)

ans = [0] * N
for iam in range(N):
    group = D[parent[iam]]
    tmp_ans = len(group) - len(F[iam]) - 1
    for block in B[iam]:
        if block in group:
            tmp_ans -= 1
    ans[iam] = tmp_ans

print(*ans, sep=' ')

Submission status: Accepted

Solution code:
from sys import stdin
import sys
import copy
sys.setrecursionlimit(200000)
N,M,K=list(map(int,input().split()))
counter=[[None,None] for i in range(N+1)]
friend_list=[set() for _ in range(N+1)]
block_list=[set() for _ in range(N+1)]
def friend_tansaku(i,j):
    color.add(j)
    cnt[0]+=1
    for friend in friend_list[j]:
        if friend not in color :
            friend_tansaku(i,friend)





for _ in range(M):
   a,b= list(map(int, input().split()))
   friend_list[a].add(b)
   friend_list[b].add(a)
for _ in range(K):
    a, b = list(map(int, input().split()))
    block_list[a].add(b)
    block_list[b].add(a)
for i in range(1,N+1):
    cnt=[0]
    color =set()
    if counter[i][0] is None:
        friend_tansaku(i,i)
        cnt=cnt[0]
        for aa in color:
            counter[aa]=[color,cnt]
    color,cnt =counter[i][0],counter[i][1]
    for k in block_list[i]:
        if k not in color:
            cnt+=1

    count=cnt-(len(friend_list[i])+len(block_list[i]))-1
    if i==N:print(count)
    else:print(count,end=" ")

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


def main():

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

    uf = UnionFind(N)
    friends = [0 for _ in range(N)]

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

    blocks = [0 for _ in range(N)]
    for _ in range(K):
        c, d = map(int, input().split())
        c, d = c - 1, d - 1
        if uf.same(c, d):
            blocks[c] += 1
            blocks[d] += 1

    for i in range(N - 1):
        ans = uf.size(i) - 1 - friends[i] - blocks[i]
        print(str(ans) + " ", end="")

    ans = uf.size(N - 1) - 1 - friends[N - 1] - blocks[N - 1]
    print(ans)


if __name__ == '__main__':
    main()

Submission status: Accepted

Solution code:
import sys
sys.setrecursionlimit(10**6)

def dfs(GF,group,gn,i):
    size = 1
    group[i]=gn
    for node in GF[i]:
        if group[node]==-1:
            group[node]=gn
            size+=dfs(GF,group,gn,node)
    return size

def main():
    from sys import stdin
    n,m,k = map(int,stdin.readline().rstrip().split())
    F=[]
    for _ in range(m):
        F.append(list(map(int,stdin.readline().rstrip().split())))
    GF = [[] for _ in range(n+1)]
    for a,b in F:
        GF[a].append(b)
        GF[b].append(a)
    
    B=[]
    for _ in range(k):
        B.append(list(map(int,stdin.readline().rstrip().split())))
    GB = [[] for _ in range(n+1)]
    for a,b in B:
        GB[a].append(b)
        GB[b].append(a)    

    U = []
    group= [-1]*(n+1)
    gn = 0

    for i in range(1,n+1):
        if group[i] == -1:
            sz = dfs(GF,group,gn,i)
            gn+=1
            U.append(sz)
    
    for i in range(1,n+1):
        g = group[i]
        ans = U[g]-1-len(GF[i])

        for b in GB[i]:
            if group[b]==g:
                ans-=1
        print(ans,end=" ")
main()

Submission status: Accepted

Solution code:
import sys, re
from math import ceil, sqrt, hypot, factorial, pi, sin, cos, tan, asin, acos, atan, radians, degrees#, log2
from collections import deque, defaultdict, Counter
from itertools import accumulate, permutations, combinations, combinations_with_replacement, product, groupby
from operator import itemgetter, mul
from copy import deepcopy
from string import ascii_lowercase, ascii_uppercase, digits
from bisect import bisect, bisect_left
from fractions import gcd
from heapq import heappush, heappop, heapify
from functools import reduce
def input(): return sys.stdin.readline().strip()
def INT(): return int(input())
def MAP(): return map(int, input().split())
def LIST(): return list(map(int, input().split()))
def ZIP(n): return zip(*(MAP() for _ in range(n)))
sys.setrecursionlimit(10 ** 9)
INF = float('inf')
mod = 10 ** 9 + 7

class UnionFind():
    def __init__(self, n):
        self.n = n
        # parents[i]: 要素iの親要素の番号
        # 要素iが根の場合、parents[i] = -(そのグループの要素数)
        self.parents = [-1] * n
    def find(self, x):
        if 0 > self.parents[x]:
            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
    # 要素xが属するグループの要素数を返す
    def size(self, x):
        return -self.parents[self.find(x)]
    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 0 > x]
    # グループの数を返す
    def group_count(self):
        return len(self.roots())
    # 辞書{根の要素: [そのグループに含まれる要素のリスト], ...}を返す
    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}
    # print()での表示用
    # all_group_members()をprintする
    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())

N, M, K = MAP()

tree = UnionFind(N)
friends = [[] for _ in range(N)]

for _ in range(M):
	A, B = MAP()
	tree.union(A-1, B-1)
	friends[A-1].append(B-1)
	friends[B-1].append(A-1)

blocks = [[] for _ in range(N)]

for _ in range(K):
	C, D = MAP()
	blocks[C-1].append(D-1)
	blocks[D-1].append(C-1)

for i in range(N):
	blocks_cnt = sum([tree.same(i, j) for j in blocks[i]])
	print(tree.size(i) - len(friends[i]) - 1 - blocks_cnt, end=" ")
print()

Submission status: Accepted

Solution code:
import sys, re
from math import ceil, sqrt, hypot, factorial, pi, sin, cos, tan, asin, acos, atan, radians, degrees#, log2
from collections import deque, defaultdict, Counter
from itertools import accumulate, permutations, combinations, combinations_with_replacement, product, groupby
from operator import itemgetter, mul
from copy import deepcopy
from string import ascii_lowercase, ascii_uppercase, digits
from bisect import bisect, bisect_left
from fractions import gcd
from heapq import heappush, heappop, heapify
from functools import reduce
def input(): return sys.stdin.readline().strip()
def INT(): return int(input())
def MAP(): return map(int, input().split())
def LIST(): return list(map(int, input().split()))
def ZIP(n): return zip(*(MAP() for _ in range(n)))
sys.setrecursionlimit(10 ** 9)
INF = float('inf')
mod = 10 ** 9 + 7

class UnionFind():
    def __init__(self, n):
        self.n = n
        # parents[i]: 要素iの親要素の番号
        # 要素iが根の場合、parents[i] = -(そのグループの要素数)
        self.parents = [-1] * n
    def find(self, x):
        if 0 > self.parents[x]:
            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
    # 要素xが属するグループの要素数を返す
    def size(self, x):
        return -self.parents[self.find(x)]
    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 0 > x]
    # グループの数を返す
    def group_count(self):
        return len(self.roots())
    # 辞書{根の要素: [そのグループに含まれる要素のリスト], ...}を返す
    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}
    # print()での表示用
    # all_group_members()をprintする
    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())

N, M, K = MAP()

tree = UnionFind(N)
friends = [[] for _ in range(N)]

for _ in range(M):
	A, B = MAP()
	tree.union(A-1, B-1)
	friends[A-1].append(B-1)
	friends[B-1].append(A-1)

blocks = [[] for _ in range(N)]

for _ in range(K):
	C, D = MAP()
	blocks[C-1].append(D-1)
	blocks[D-1].append(C-1)

for i in range(N):
	blocks_cnt = 0
	for j in blocks[i]:
		if tree.same(i, j):
			blocks_cnt += 1
	print(tree.size(i) - len(friends[i]) - 1 - blocks_cnt, end=" ")
print()

Submission status: Accepted

Solution code:
import sys, re
from math import ceil, sqrt, hypot, factorial, pi, sin, cos, tan, asin, acos, atan, radians, degrees#, log2
from collections import deque, defaultdict, Counter
from itertools import accumulate, permutations, combinations, combinations_with_replacement, product, groupby
from operator import itemgetter, mul
from copy import deepcopy
from string import ascii_lowercase, ascii_uppercase, digits
from bisect import bisect, bisect_left
from fractions import gcd
from heapq import heappush, heappop, heapify
from functools import reduce
def input(): return sys.stdin.readline().strip()
def INT(): return int(input())
def MAP(): return map(int, input().split())
def LIST(): return list(map(int, input().split()))
def ZIP(n): return zip(*(MAP() for _ in range(n)))
sys.setrecursionlimit(10 ** 9)
INF = float('inf')
mod = 10 ** 9 + 7

class UnionFind():
    def __init__(self, n):
        self.n = n
        # parents[i]: 要素iの親要素の番号
        # 要素iが根の場合、parents[i] = -(そのグループの要素数)
        self.parents = [-1] * n
    def find(self, x):
        if 0 > self.parents[x]:
            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
    # 要素xが属するグループの要素数を返す
    def size(self, x):
        return -self.parents[self.find(x)]
    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 0 > x]
    # グループの数を返す
    def group_count(self):
        return len(self.roots())
    # 辞書{根の要素: [そのグループに含まれる要素のリスト], ...}を返す
    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}
    # print()での表示用
    # all_group_members()をprintする
    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())

N, M, K = MAP()

tree = UnionFind(N)
friends = [[] for _ in range(N)]

for _ in range(M):
	A, B = MAP()
	tree.union(A-1, B-1)
	friends[A-1].append(B-1)
	friends[B-1].append(A-1)

blocks = [[] for _ in range(N)]

for _ in range(K):
	C, D = MAP()
	blocks[C-1].append(D-1)
	blocks[D-1].append(C-1)

for i in range(N):
	ans = tree.size(i) - 1 - len(friends[i])
	blocks_cnt = 0
	for j in  blocks[i]:
		if tree.same(i, j):
			blocks_cnt += 1
	ans -= blocks_cnt
	print(ans, end=" ")
print()

Submission status: Accepted

Solution code:
import sys
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines

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

    def makeSet(self, n):
        self.parents = [i for i in range(n)]
        self.rank = [0 for _ in range(n)]
        self.length = [1 for _ in range(n)]

    def find(self, x):
        if self.parents[x] == x:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    def unite(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return
        if self.rank[x] < self.rank[y]:
            self.parents[x] = y
            self.length[y] += self.length[x]
        else:
            self.parents[y] = x
            self.length[x] += self.length[y]
            if self.rank[x] == self.rank[y]:
                self.rank[x] += 1

    def getLength(self, x):
        x = self.find(x)
        return self.length[x]        

    def isSameGroup(self, x, y):
        return self.find(x) == self.find(y)
 
def main():
    N, M, K = map(int, readline().split())
    friend = [set() for _ in range(N)]
    block = [set() for _ in range(N)]
    uf = UnionFind(N)
    for _ in range(M):
        a, b = map(int, readline().split())
        a-=1
        b-=1
        friend[a].add(b)
        friend[b].add(a)
        uf.unite(a, b)

    for _ in range(K):
        c, d = map(int, readline().split())
        c-=1
        d-=1
        block[c].add(d)
        block[d].add(c)

    for i in range(N):
        cnt = 0
        for blk in block[i]:
            if uf.isSameGroup(i, blk):
                cnt += 1    
        ans = uf.getLength(i)-cnt-len(friend[i])-1
        if i == N-1:
            print(ans)
        else:
            print(ans, end=" ")
if __name__ == '__main__': 
    main()

Submission status: Accepted

Solution code:
import sys
sys.setrecursionlimit(10 ** 5 + 10)
def input(): return sys.stdin.readline().strip()

def resolve():
    
    class UnionFind(object):
        def __init__(self, n=1):
            # 木の親要素を管理するリストparをつくります。
            # par[x] == xの場合には、そのノードが根であることを示します。
            # 初期状態では一切グループ化されていないので、すべてのノードが根になりますね。
            self.par = [i for i in range(n)]
            # 木の高さを持っておき、あとで低い方を高い方につなげる。初期状態は0
            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
                # 同じ長さの場合rankが1増える
                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())
    uf = UnionFind(N)  # ノード数Nでクラス継承
    friends_cnt=[0]*N
    for i in range(M):
        # A,Bはノード
        A, B = map(int, input().split())
        A-=1
        B-=1
        friends_cnt[A]+=1
        friends_cnt[B]+=1
    
        # 連結クエリ union
        uf.union(A, B)
    
    blocks=[[] * N for i in range(N)]
    for i in range(K):
        x, y = map(int, input().split())
        x, y = x - 1, y - 1
        blocks[x].append(y)
        blocks[y].append(x) # 有向ならコメントアウト
    
    for i in range(N):
        ans=uf.get_size(i)-friends_cnt[i]-1
        for j in blocks[i]:
            if uf.is_same(i,j):
                ans-=1
        print(ans,end=' ')
    print()

    
    

    

resolve()

Submission status: Accepted

Solution code:
import sys, re
from math import ceil, sqrt, hypot, factorial, pi, sin, cos, tan, asin, acos, atan, radians, degrees#, log2
from collections import deque, defaultdict, Counter
from itertools import accumulate, permutations, combinations, combinations_with_replacement, product, groupby
from operator import itemgetter, mul
from copy import deepcopy
from string import ascii_lowercase, ascii_uppercase, digits
from bisect import bisect, bisect_left
from fractions import gcd
from heapq import heappush, heappop, heapify
from functools import reduce
def input(): return sys.stdin.readline().strip()
def INT(): return int(input())
def MAP(): return map(int, input().split())
def LIST(): return list(map(int, input().split()))
def ZIP(n): return zip(*(MAP() for _ in range(n)))
sys.setrecursionlimit(10 ** 9)
INF = float('inf')
mod = 10 ** 9 + 7

class UnionFind():
    def __init__(self, n):
        self.n = n
        # parents[i]: 要素iの親要素の番号
        # 要素iが根の場合、parents[i] = -(そのグループの要素数)
        self.parents = [-1] * n
    def find(self, x):
        if 0 > self.parents[x]:
            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
    # 要素xが属するグループの要素数を返す
    def size(self, x):
        return -self.parents[self.find(x)]
    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 0 > x]
    # グループの数を返す
    def group_count(self):
        return len(self.roots())
    # 辞書{根の要素: [そのグループに含まれる要素のリスト], ...}を返す
    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}
    # print()での表示用
    # all_group_members()をprintする
    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())


N, M, K = MAP()
friends = defaultdict(list)
tree = UnionFind(N)
for _ in range(M):
	A, B = MAP()
	tree.union(A-1, B-1)
	friends[A-1].append(B-1)
	friends[B-1].append(A-1)

blocks = defaultdict(list)
for _ in range(K):
	C, D = MAP()
	blocks[C-1].append(D-1)
	blocks[D-1].append(C-1)

for i in range(N):
	minus = 0
	for b in blocks[i]:
		if tree.same(i, b):
			minus += 1
	print(tree.size(i)-len(friends[i])-1-minus, end = " ")
print()

"""
print("friends")
print(friends)

print("blocks")
print(blocks)

i = 1
print("i={}".format(i))
print("tree.size(i)={}".format(tree.size(i)))
print("tree.find(i))={}".format(tree.find(i)))
print("tree.members(i)={}".format(tree.members(i)))
print("tree.roots={}".format(tree.roots()))
print("tree.group_count={}".format(tree.group_count()))
print("tree.all_group_members={}".format(tree.all_group_members()))
"""

Submission status: Accepted

Solution code:
import sys
sys.setrecursionlimit(10**5)

def DFS(i,g):
    if i not in done:
        done.add(i)
        circle.add(i)
        g_list[i]=g
        for f in F[i]:
            DFS(f,g)
    else:
        return

N,M,K=map(int,input().split())
F=[[] for _ in range(N)]
B=[[] for _ in range(N)]

for f in range(M):
    f1,f2=map(int,input().split())
    F[f1-1].append(f2-1)
    F[f2-1].append(f1-1)
for b in range(K):
    b1,b2=map(int,input().split())
    B[b1-1].append(b2-1)
    B[b2-1].append(b1-1)

Group=[]
circle=set()
done=set()
g_list=[0 for _ in range(N)]
g=0
for i in range(N):
    if i not in done:
        DFS(i,g)
        Group.append(circle)
        circle=set()
        g+=1

ans=[-1 for _ in range(N)]
for i in range(N):
    G=g_list[i]
    ans[i]+=len(Group[G])
    for fr in F[i]:
        if fr in Group[G]:
            ans[i]-=1
    for bl in B[i]:
        if bl in Group[G]:
            ans[i]-=1

print(*ans)

Submission status: Accepted

Solution code:
import sys
import collections
def input():
    return sys.stdin.readline()[:-1]
sys.setrecursionlimit(10000000)
n,m,k=map(int,input().split())
gf = [[]for i in range(n)]
gb = [[]for i in range(n)]
for i in range(m):
    a,b = map(int,input().split())
    gf[a-1].append(b-1)
    gf[b-1].append(a-1)

for i in range(k):
    a,b = map(int,input().split())
    gb[a-1].append(b-1)
    gb[b-1].append(a-1)

seen = [0 for i in range(n)]

def dfs(i,k):
    for nec in gf[i]:
        if seen[nec]!=0:
            continue
        seen[nec]=k
        dfs(nec,k)
k=1

for i in range(n):
    if seen[i]==0:
        seen[i]=k
        dfs(i,k)
        k+=1
c = collections.Counter(seen)
lis = []
for i in range(n):
    dec = 0
    for k in gb[i]:
        if seen[i]==seen[k]:
            dec += 1
    lis.append(c[seen[i]]-len(gf[i])-dec-1)
print(*lis)

Submission status: Accepted

Solution code:
# UnionFind木
class UnionFind():
    def __init__(self, n):
        # その節の根、その節を含む木の高さ、その節が根の時の木のノード数
        self.par = [i for i in range(n)]
        self.rank = [0] * n
        self.size = [1] * n

    # 根を検索
    def find(self, 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 = self.find(x)
        y = self.find(y)
        if x == y:
            return
        if self.rank[x] < self.rank[y]:
            self.par[x] = y
            self.size[y] += self.size[x]
        else:
            self.par[y] = x
            self.size[x] += self.size[y]
            if self.rank[x] == self.rank[y]:
                self.rank[x] += 1

    # 同じ集合に属するか判定
    def same_check(self, x, y):
        return self.find(x) == self.find(y)

    # 木のノード数を得る
    def getSize(self, x):
        return self.size[self.find(x)]

def main():
    N,M,K = map(int, input().split())
    # 広義の友達 - 直接の友達 - ブロック
    # UnionFind木
    uftree = UnionFind(N)
    count = [0] * N
    for i in range(M):
        A,B = map(lambda x:x-1, map(int, input().split()))
        uftree.union(A,B)
        count[A] += 1
        count[B] += 1
    for i in range(K):
        C,D = map(lambda x:x-1, map(int, input().split()))
        if uftree.same_check(C,D):
            count[C] += 1
            count[D] += 1
    ans = [0] * N
    for i in range(N):
        ans[i] = uftree.getSize(i) - 1 - count[i] # 真ん中の-1は自分自身
    print(*ans)

main()

Submission status: Accepted

Solution code:
n,m,k=map(int,input().split())
 
def find(x):
    if par[x] < 0:
        return x
    else:
        par[x] = find(par[x])
        return par[x]
 
def unite(x,y):
    x = find(x)
    y = find(y)
    
    if x == y:
        return False
    else:
        if par[x] > par[y]:
            x,y = y,x
        par[x] += par[y]
        par[y] = x
        return True
 
def same(x,y):
    return find(x) == find(y)
 
def size(x):
    return -par[find(x)]
 
par = [-1]*n
 
ans=[0]*n
nxt=[0]*n
block=[[] for _ in range(n)]
 
for _ in range(m):
    a,b=map(int,input().split())
    unite(a-1,b-1)
    nxt[a-1]+=1
    nxt[b-1]+=1
 
for _ in range(k):
    c,d=map(int,input().split())
    block[c-1].append(d-1)
    block[d-1].append(c-1)
 
for i in range(n):
    ans[i]=size(i)-nxt[i]-1
    for j in block[i]:
        if same(j,i):
            ans[i]-=1
print(*ans)

Submission status: Accepted

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

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

def unite(x,y):
    x = find(x)
    y = find(y)
    
    if x == y:
        return False
    else:
        if par[x] > par[y]:
            x,y = y,x
        par[x] += par[y]
        par[y] = x
        return True

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

def size(x):
    return -par[find(x)]

par = [-1]*n

ans=[0]*n
nxt=[0]*n
block=[[] for _ in range(n)]

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

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

for i in range(n):
    ans[i]=size(i)-nxt[i]-1
    for j in block[i]:
        if same(j,i):
            ans[i]-=1
print(*ans)