Problem:


Score : 400 points

Problem Statement

There are N persons called Person 1 through Person N.

You are given M facts that "Person A_i and Person B_i are friends." The same fact may be given multiple times.

If X and Y are friends, and Y and Z are friends, then X and Z are also friends. There is no friendship that cannot be derived from the M given facts.

Takahashi the evil wants to divide the N persons into some number of groups so that every person has no friend in his/her group.

At least how many groups does he need to make?

Constraints

2 \leq N \leq 2\times 10^5

0 \leq M \leq 2\times 10^5

1\leq A_i,B_i\leq N

A_i \neq B_i

Input

Input is given from Standard Input in the following format:

N M
A_1 B_1
\vdots
A_M B_M

Output

Print the answer.

Sample Input 1

5 3
1 2
3 4
5 1

Sample Output 1

3

Dividing them into three groups such as \{1,3\}, \{2,4\}, and \{5\} achieves the goal.

Sample Input 2

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

Sample Output 2

4

Sample Input 3

10 4
3 1
4 1
5 9
2 6

Sample Output 3

3



Sample input:
5 3
1 2
3 4
5 1


Sample output:
3

Submission status: Accepted

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

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

    def find(self, x): #要素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が属するグループと要素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


n, m = map(int, input().split())
uf = UnionFind(n)
for i in range(m):
    a, b = map(int, input().split())
    a -= 1
    b -= 1
    uf.union(a, b)

print(abs(min(uf.parents)))

Submission status: Accepted

Solution code:
#Union-Find木の実装
from collections import Counter
N,M=map(int,input().split())

#初期化
par=[i for i in range(N)]#親の要素(par[x]=xのときxは木の根)
rank=[0]*N#木の深さ

#木の根を求める
def find(x):
  #xが根だった場合xをそのまま返す
  if par[x] == x:
    return x
  else:
    #根が出るまで再帰する
    par[x] = find(par[x])
    return par[x]

#xとyの属する集合を併合
def unite(x,y):
  x=find(x)#xの根
  y=find(y)#yの根
  #根が同じなら何もしない
  if x == y:
    return
  #もし根の深さがyの方が深いなら
  if rank[x] < rank[y]:
    par[x] = y#yを根にする
  else:
    par[y] = x#xを根にする
    if rank[x] == rank[y]:
      rank[x]+=1

#xとyが同じ集合に属するか否か
#def same(x,y):
  #return find(x)==find(y)

for _ in range(M):
  a,b = map(int,input().split())
  a,b = a-1, b-1
  unite(a,b)

for i in range(N):
  find(i)
c=Counter(par)
c=c.most_common()[0][1]
print(c)

Submission status: Accepted

Solution code:
# 参考URL https://note.nkmk.me/python-union-find/
class UnionFind():
    # 各要素の親要素の番号を格納するリスト
    # 要素が根（ルート）の場合は-(そのグループの要素数)を格納する
    def __init__(self, n):
        self.n = n
        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)]

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

from sys import stdin
def input():
    return stdin.readline().strip()

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

uf = UnionFind(n)

for _ in range(m):
    i, j = map(int, input().split())
    uf.union(i-1, j-1)

ans = 0
for i in uf.roots():
    j = uf.size(i)
    if ans < j:
        ans = j

print(ans)

Submission status: Accepted

Solution code:
import math
ini = lambda : int(input())
inm = lambda : map(int,input().split())
inl = lambda : list(map(int,input().split()))
gcd = lambda x,y : gcd(y,x%y) if x%y else y
def factorization(n):
    arr = []
    temp = n
    for i in range(2, int(-(-n**0.5//1))+1):
        if temp%i==0:
            cnt=0
            while temp%i==0:
                cnt+=1
                temp //= i
            arr.append([i, cnt])
    if temp!=1:
        arr.append([temp, 1])
    if arr==[]:
        arr.append([n, 1])
    return arr
def make_divisors(n):
    divisors = []
    for i in range(1, int(n**0.5)+1):
        if n % i == 0:
            divisors.append(i)
            if i != n // i:
                divisors.append(n//i)
    divisors.sort()
    return divisors
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())
mod = 10**9 + 7

#maincode-------------------------------------------------

n,m = inm()
uf = UnionFind(n)
for i in range(m):
    a,b = inm()
    a -= 1
    b -= 1
    uf.union(a,b)

ans = 0
for i in range(n):
    ans = max(ans,uf.size(i))

print(ans)

Submission status: Accepted

Solution code:
import os

n,m = (int(x) for x in input().split())

#Union Find

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

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

for i in range(m):
    a,b = (int(x)-1 for x in input().split())
    unite(a,b)

ans = 0
for i in range(0,n):
    ans = max([ans,size(i)])

print(ans)

Submission status: Accepted

Solution code:
# 連結成分に分解、異なる連結成分から一人ずつ集めたグループが１セット。
# これを全ての連結成分が空になるまで繰り返す。
# 全ての連結成分が空になる <===> 連結成分の最大の要素数回この操作を繰り返せば良い。
# Union FInd が一番適してそう。
class UnionFind():
    
    def __init__(self,N):
        self.N = N
        self.par = [-1]*N
    
    def find(self,x):
        if self.par[x]<0: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.par[x]>self.par[y]:
            x,y = y,x
        
        self.par[x] += self.par[y]
        self.par[y] = x
    

N,M=map(int,input().split())
uf = UnionFind(N)
for _ in range(M):
    a,b = map(int,input().split())
    a -= 1;b -= 1
    uf.union(a,b)
print(-min(uf.par))

Submission status: Accepted

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

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

root = [-1] * n

def r(x):
    if root[x] < 0:
        return x
    
    else:
        root[x] = r(root[x])
        return root[x]

def unite(x,y):
    x = r(x)
    y = r(y)
    if x == y:
        return
    root[x] += root[y]
    root[y] = x

def size(x):
    x = r(x)
    return -root[x]

for i in range(m):
    x,y = map(int,input().split())
    x -= 1
    y -= 1
    unite(x,y)


print(-min(root))

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 = map(int,input().split()) 
uf = UnionFind(N)
for _ in range(M):
  a, b = map(int,input().split())
  uf.union(a-1,b-1)

ans = 0
for i in range(N):
  ans=max(ans, uf.size(i))
print(ans)

Submission status: Accepted

Solution code:
# D - Friends

from collections import Counter

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

# 答は最大連結成分の要素数

cc = [None for a in range(n + 1)] # 各頂点の連結成分

ccid = 0
for u in range(1, n + 1):
    if cc[u] != None:
        continue
    ccid += 1
    queue = [u]
    while len(queue) > 0:
        a = queue.pop()
        if cc[a] == None:
            cc[a] = ccid
            queue.extend(adj[a])

counter = Counter(cc)
print(max(counter.values()))

Submission status: Accepted

Solution code:
class UnionFind():
    # 作りたい要素数nで初期化
    # 使用するインスタンス変数の初期化
    def __init__(self, n):
        self.n = n
        # root[x]<0ならそのノードが根かつその値が木の要素数
        # rootノードでその木の要素数を記録する
        self.root = [-1]*(n+1)
        # 木をくっつける時にアンバランスにならないように調整する
        self.rnk = [0]*(n+1)

    # ノードxのrootノードを見つける
    def Find_Root(self, x):
        if(self.root[x] < 0):
            return x
        else:
            # ここで代入しておくことで、後の繰り返しを避ける
            self.root[x] = self.Find_Root(self.root[x])
            return self.root[x]
    # 木の併合、入力は併合したい各ノード
    def Unite(self, x, y):
        # 入力ノードのrootノードを見つける
        x = self.Find_Root(x)
        y = self.Find_Root(y)
        # すでに同じ木に属していた場合
        if(x == y):
            return 
        # 違う木に属していた場合rnkを見てくっつける方を決める
        elif(self.rnk[x] > self.rnk[y]):
            self.root[x] += self.root[y]
            self.root[y] = x

        else:
            self.root[y] += self.root[x]
            self.root[x] = y
            # rnkが同じ（深さに差がない場合）は1増やす
            if(self.rnk[x] == self.rnk[y]):
                self.rnk[y] += 1
    # xとyが同じグループに属するか判断
    def isSameGroup(self, x, y):
        return self.Find_Root(x) == self.Find_Root(y)

    # ノードxが属する木のサイズを返す
    def Count(self, x):
        return -self.root[self.Find_Root(x)]
    
N, M = map(int,input().split())
A = [None] * M
B = [None] * M
for i in range(M):
    A[i], B[i] = map(int,input().split())
uf = UnionFind(N)
for j,h in zip(A,B):
    uf.Unite(j,h)
print(min(uf.root)*(-1))

Submission status: Accepted

Solution code:
def main():
    N, M = map(int, input().split())

    friends = [set() for _ in range(N)]
    for _ in range(M):
        a, b = map(lambda x: int(x)-1, input().split())
        friends[a].add(b)
        friends[b].add(a)
    # print(friends)

    visited = [0]*N #グループを作って合ったら
    ans = 0
    for i in range(N):
        if visited[i]:
            continue
        tmp = list(friends[i])
        ans_tmp = 1
        visited[i] = 1
        while tmp:
            t = tmp.pop()
            if not visited[t]:
                visited[t] = 1
                ans_tmp += 1
                for j in friends[t]:
                    tmp.append(j)

        ans = max(ans, ans_tmp)
    print(ans)

if __name__ == '__main__':
    main()

Submission status: Accepted

Solution code:
def dfs(target, graph, visited):
    stack = []
    stack.append(target)
    visited[target] = True
    ans = 0
    while len(stack) > 0: 
        root = stack.pop()
        ans += 1
        for dst in graph[root]:
            if visited[dst] is False:
                visited[dst] = True
                stack.append(dst)
                pass 
    return ans 

n, m = map(int, input().split())
graph = {i:set() for i in range(n)}
for _ in range(m):
    a, b = map(int, input().split())
    a -= 1
    b -= 1
    graph[a].add(b)
    graph[b].add(a)
visited = [False]*n
ans = 1
for target in graph:
    if visited[target] is False:
        score = dfs(target, graph, visited)
        ans = max(ans, score)

print(ans)

Submission status: Accepted

Solution code:
N, M, *AB = [int(_) for _ in open(0).read().split()]


class UnionFind():
    def __init__(self, n):
        self.n = n
        self.root = [-1] * (n + 1)
        self.rank = [0] * (n + 1)

    def find(self, x):
        if self.root[x] < 0:
            return x
        else:
            self.root[x] = self.find(self.root[x])
            return self.root[x]

    def unite(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return 0
        elif self.rank[x] > self.rank[y]:
            self.root[x] += self.root[y]
            self.root[y] = x
        else:
            self.root[y] += self.root[x]
            self.root[x] = y
            if self.rank[x] == self.rank[y]:
                self.rank[y] += 1

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

    def size(self, x):
        return -self.root[self.find(x)]


uf = UnionFind(N)
for a, b in zip(AB[::2], AB[1::2]):
    uf.unite(a, b)
ans = max(uf.size(i) for i in range(1, N + 1))
print(ans)

Submission status: Accepted

Solution code:
'''
自宅用PCでの解答
'''
import math
#import numpy as np
import itertools
import queue
import bisect
from collections import deque,defaultdict
import heapq as hpq
from sys import stdin,setrecursionlimit
#from scipy.sparse.csgraph import dijkstra
#from scipy.sparse import csr_matrix
ipt = stdin.readline
setrecursionlimit(10**7)
mod = 10**9+7 #998244353
dir = [(-1,0),(0,-1),(1,0),(0,1)]
alp = "abcdefghijklmnopqrstuvwxyz"

#UnionFindのクラス,0-indexed
class UnionFind():
    def __init__(self, n):
        self.n = n
        # parents = [-1,0,-4,1,1,1]のように、親の添字かマイナス要素数を表す
        self.parents = [-1] * n
    # find: xの親がすべてrootになる。これにより計算量削減(O(N) for all (not each))
    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 = map(int,ipt().split())
    uf = UnionFind(n+1)
    for i in range(m):
        a,b = map(int,ipt().split())
        uf.union(a,b)

    print(-min(uf.parents))

    return None

if __name__ == '__main__':
    main()

Submission status: Accepted

Solution code:
'''
自宅用PCでの解答
'''
import math
#import numpy as np
import itertools
import queue
import bisect
from collections import deque,defaultdict
import heapq as hpq
from sys import stdin,setrecursionlimit
#from scipy.sparse.csgraph import dijkstra
#from scipy.sparse import csr_matrix
ipt = stdin.readline
setrecursionlimit(10**7)
mod = 10**9+7 #998244353
dir = [(-1,0),(0,-1),(1,0),(0,1)]
alp = "abcdefghijklmnopqrstuvwxyz"

#UnionFindのクラス,0-indexed
class UnionFind():
    def __init__(self, n):
        self.n = n
        # parents = [-1,0,-4,1,1,1]のように、親の添字かマイナス要素数を表す
        self.parents = [-1] * n
    # find: xの親がすべてrootになる。これにより計算量削減(O(N) for all (not each))
    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 = map(int,ipt().split())
    uf = UnionFind(n)
    for i in range(m):
        a,b = map(int,ipt().split())
        uf.union(a-1,b-1)

    print(-min(uf.parents))

    return None

if __name__ == '__main__':
    main()

Submission status: Accepted

Solution code:
from collections import deque

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

ad_sum_array = [0] * n
ad_array = [set() for _ in range(n)]

for ab in ab_array:
    a, b = ab
    ad_array[a - 1].add(b - 1)
    ad_array[b - 1].add(a - 1)

check_array = [False] * n

def bfs(node_num):
    queue = deque([node_num])
    check_array[node_num] = True
    num = 1

    while queue:
        node = queue.popleft()
        for ad in ad_array[node]:
            if not check_array[ad]:
                check_array[ad] = True
                queue.append(ad)
                num += 1
    return num

ans = 0
for i in range(n):
    if not check_array[i]:
        ans = max(ans, bfs(i))

print(ans)

Submission status: Accepted

Solution code:
N, M = map(int, input().split())

par = list(range(N))
rank = [1]*N
size = [1]*N

def find(x):
  if par[x] == x:
    return x
  else:
    return find(par[x])
  
def unite(x,y):
  x = find(x)
  y = find(y)
  
  if x == y:
    return
  if rank[x]<rank[y]:
    x,y = y,x
  par[y] = x
  size[x] += size[y]
  if rank[x]==rank[y]:
    rank[x]+=1
    
for i in range(M):
  a,b = [int(i)-1 for i in input().split()]
  unite(a,b)
  
print(max(size))

Submission status: Accepted

Solution code:
N, M = map(int, input().split())

par = list(range(N))
rank = [1]*N
size = [1]*N

def find(x):
  if par[x] == x:
    return x
  else:
    return find(par[x])
  
def unite(x,y):
  x = find(x)
  y = find(y)
  
  if x == y:
    return
  if rank[x]<rank[y]:
    par[x]=y
    size[y]+= size[x]
  else:
    par[y] = x
    size[x] += size[y]
    if rank[x]==rank[y]:
      rank[x]+=1
    
for i in range(M):
  a,b = [int(i)-1 for i in input().split()]
  unite(a,b)
  
print(max(size))

Submission status: Accepted

Solution code:
import sys
import heapq

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 all_group_memberss(self):
        return [self.size(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 = [int(x) for x in input().split()]
    AB = [[int(x) for x in input().split()] for _ in range(M)]

    uf = UnionFind(N)

    for a, b in AB:
        uf.union(a - 1, b - 1)

    hq = []
    for k in uf.all_group_memberss():
        heapq.heappush(hq, k)

    ans = 0
    prev = 0
    while hq:
        c = heapq.heappop(hq)
        if prev != c:
            ans += (c - prev)
            prev = c

    print(ans)


if __name__ == '__main__':
    main()

Submission status: Accepted

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


class UnionFind:

    def __init__(self, N):
        self.parents = list(range(N))
        self.depth = [0] * N

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

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

        if self.depth[x] == self.depth[y]:
            self.depth[x] += 1
            self.parents[y] = x
        elif self.depth[x] > self.depth[y]:
            self.parents[y] = x
        else:
            self.parents[x] = y


def main():
    N, M = map(int, input().split())
    uf = UnionFind(N)
    for i in range(M):
        a, b = map(int, input().split())
        uf.union(a - 1, b - 1)
    num = [0] * N
    for i in range(N):
        p = uf.find(i)
        num[p] += 1
    ans = max(num)
    print(ans)


if __name__ == '__main__':
    main()

Submission status: Accepted

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


class UnionFind:
    def __init__(self, size):
        self.parent = [-1] * size
        self.rank = [1] * size
        self.groups = size

    def get_root(self, node):
        parent = self.parent[node]
        if parent == -1:
            root = node
        else:
            root = self.get_root(parent)
            self.parent[node] = root  # 同じnodeへの2回目以降のget_rootを高速にするために、直接rootに繋いでおく
        return root

    def in_same_group(self, node1, node2):
        root1 = self.get_root(node1)
        root2 = self.get_root(node2)
        return root1 == root2

    def unite(self, node1, node2):
        if self.in_same_group(node1, node2):
            return
        main_root = self.get_root(node1)
        sub_root = self.get_root(node2)
        if self.rank[main_root] < self.rank[sub_root]:  # rankの大きい方をmain_rootにする
            main_root, sub_root = sub_root, main_root

        self.parent[sub_root] = main_root
        self.rank[main_root] += self.rank[sub_root]
        self.groups -= 1


def main():
    n, m = map(int, input().split())
    uf = UnionFind(n)
    for _ in range(m):
        a, b = map(int, input().split())
        a -= 1
        b -= 1
        uf.unite(a, b)

    ans = max(uf.rank)
    print(ans)


if __name__ == "__main__":
    main()

Submission status: Accepted

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

N,Q = map(int,input().split())
par = [i for i in range(N)]
rank = [0]*(N+1)
def find(x):
    if par[x] == x:
        return x
    else:
        par[x] = find(par[x]) #経路圧縮
        return par[x]
def same(x,y):
    return find(x) == find(y)
def unite(x,y):
    x = find(x)
    y = find(y)
    if x == y:
        return 0
    if rank[x] < rank[y]:
        par[x] = y
    else:
        par[y] = x
        if rank[x]==rank[y]:rank[x]+=1

for _ in range(Q):
  a,b=map(int,input().split())
  a,b=a-1,b-1
  unite(a,b)
from collections import Counter
a=[-1]*N
for i in range(N):
  a[i]=find(i)
ca=Counter(a)
ans=0
for c in ca.values():
  ans=max(ans,c)
print(ans)

Submission status: Accepted

Solution code:
import math
import sys
import os
from operator import mul

sys.setrecursionlimit(10**7)

def _S(): return sys.stdin.readline().rstrip()
def I(): return int(_S())
def LS(): return list(_S().split())
def LI(): return list(map(int,LS()))

if os.getenv("LOCAL"):
    inputFile = basename_without_ext = os.path.splitext(os.path.basename(__file__))[0]+'.txt'
    sys.stdin = open(inputFile, "r")
INF = float("inf")

N,M = LI()
AB = [LI() for _ in range(M)]

ans = 0

par = [0]*N
# rank = [0]*N

def init(n):
    for i in range(n):
        # 親のID or 属する頂点の数
        par[i]=-1
        # rank[i] = 0

# rootを返す
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
    if (par[x] > par[y]):
        x,y = y,x
    # rootの頂点数を結合
    par[x] += par[y]
    # yの親をxに
    par[y] = x
    return

    # if (rank[x]<rank[y]):
    #     par[x]=y
    # else:
    #     par[y]=x
    #     if rank[x] == rank[y]:
    #         rank[x] += 1

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

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

init(N)

for r in AB:
    f = r[0]-1
    t = r[1]-1
    unite(f,t)
    # print(par)

for i in range(N):
    # print(size(i))
    ans = max(ans,size(i))

print(ans)

Submission status: Accepted

Solution code:
class UnionFind:
    def __init__(self,N):
        self.parent = [i for i in range(N)]
        self.rank = [0] * N
        self.count = 0
        self._size = [1]*N
    def root(self,a):
        if self.parent[a] == a:
            return a
        else:
            self.parent[a] = self.root(self.parent[a])
            return self.parent[a]
    def is_sama(self,a,b):
        return self.root(a) == self.root(b)
    def unite(self,a,b):
        ra = self.root(a)
        rb = self.root(b)
        if ra == rb:
            return
        if self.rank[ra] < self.rank[rb]:
            self.parent[ra] = rb
            self._size[rb] += self._size[ra]
        else:
            self.parent[rb] = ra
            if self.rank[ra] == self.rank[rb]:
                self.rank[ra] += 1
            self._size[ra] += self._size[rb]
        self.count += 1
    def print_info(self):
        print("parent", self.parent)
        print("rank", self.rank)
        print("count", self.count)
        print("size", self._size)
    def size(self,a):
        return self._size[self.root(a)]

N, M = map(int,input().split())
uf = UnionFind(N)
for i in range(M):
    a,b = map(int,input().split())
    a -= 1
    b -= 1
    uf.unite(a,b)
ans = 0
for i in range(N):
    ans = max(ans,uf.size(i))
print(ans)

Submission status: Accepted

Solution code:
class UnionFind:
  N=0
  parent=None
  size=None
  def __init__(self,N):
    self.N=N
    self.parent=[i for i in range(self.N)]
    self.size=[1]*self.N
    
  def root(self,x):
    while x!=self.parent[x]:
      self.parent[x]=self.parent[self.parent[x]]
      x=self.parent[x]
    return x
  
  def same(self,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
    if self.size[x]>self.size[y]:
      # 大きい方にくっつける
      self.parent[y]=x
      self.size[x]+=self.size[y]
    else:
      self.parent[x]=y
      self.size[y]+=self.size[x]
      
  def get_group_size(self,x):
    return self.size[self.root(x)]
  
  def get_roots(self):
    r=set()
    for i in range(self.N):
      r.add(self.root(i))
    return r
  
  def show_parent(self):
    print(self.parent)
    
  def show_size(self):
    print(self.size)
    
import sys
readline = sys.stdin.readline

N,M = map(int,readline().split())
UF = UnionFind(N)

for i in range(M):
  a,b = map(int,readline().split())
  UF.unite(a - 1, b - 1)
  
roots = UF.get_roots()
ans = 0
for r in roots:
  s = UF.get_group_size(r)
  if ans < s:
    ans = s
    
print(ans)

Submission status: Accepted

Solution code:
#import array
#import random
#import sys

#N, M = 200000, 200000
N, M = list(map(int, input().split()))
R = [[] for _ in range(N+1)]
G = [0] * (N+1)
Z = [0] * (N+1)

def grp(R, grpid, i, G, Z):
    stack = [i]
    while len(stack) > 0:
        k = stack.pop()
        if G[k] > 0: continue
        G[k] = grpid
        Z[grpid] += 1
        for l in range(len(R[k])):
            stack.append(R[k][l])
        
for i in range(M):
    a, b = list(map(int, input().split()))
#    a, b = random.choice(range(N)), random.choice(range(N))
    R[a].append(b)
    R[b].append(a)

grpid = 0
for i in range(1, N+1):
    if G[i] > 0: continue
    grpid += 1
    grp(R, grpid, i, G, Z)
    
Z.sort(reverse=True)
print(Z[0])

Submission status: Accepted

Solution code:
#https://at274.hatenablog.com/entry/2018/02/02/173000
class UnionFind:
    def __init__(self, n):
        self.par = [i for i in range(n+1)]
        self.rank = [0] * (n+1)

    # 検索
    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 self.rank[x] < self.rank[y]:
            self.par[x] = y
        else:
            self.par[y] = x
            if self.rank[x] == self.rank[y]:
                self.rank[x] += 1

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

n,m=map(int, input().split())
uf=UnionFind(n)
for _ in range(m):
    ai,bi=map(int, input().split())
    uf.union(ai,bi)

cnt=[0]*(n+1)

for i in range(n+1):
    cnt[uf.find(i)]+=1
print(max(cnt))