Buggy python submission (verdict: Time Limit Exceeded):
from sys import exit, stdin

input = stdin.readline
import copy
from collections import deque, Counter

# import numpy as np


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

if M == 0:
    print(1)
    exit()


D = [-1] * N
tmp = 0
for i in range(M):
    a, b = list(map(int, input().split()))
    a -= 1
    b -= 1
    if D[a] == -1 and D[b] == -1:
        D[a] = tmp
        D[b] = tmp
        tmp += 1
    elif D[a] == -1 and D[b] != -1:
        D[a] = D[b]
    elif D[a] != -1 and D[b] == -1:
        D[b] = D[a]
    elif D[a] != D[b]:
        for k in range(N):
            if D[k] == D[b]:
                D[k] = a


R = Counter(D)
ans = R.most_common(2)
if ans[0][0] == -1:
    print(ans[1][1])
else:
    print(ans[0][1])


Fixed submission:
from sys import exit, stdin

input = stdin.readline
import copy
from collections import deque, Counter

# import numpy as np


class BIT:
    def __init__(self, a=0):
        self.n = a
        self.d = [0] * (a + 1)

    def add(self, i, x=1):
        i += 1
        while i <= self.n:
            self.d[i] += x
            i += i & (-i)

    def sum(self, *i):
        if len(i) == 1:
            x = 0
            i += 1
            while i:
                x += self.d[i]
                i -= i & (-i)
            return x
        else:
            return sum(self, i[1] - 1) - sum(self, i[0] - 1)


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

    def find(self, x):
        # find x's root
        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):
        # unite x and y
        rx = self.find(x)
        ry = self.find(y)

        if rx == ry:
            return False
        if -(self.parents[rx]) < -(self.parents[ry]):
            rx, ry = ry, rx
        self.parents[rx] += self.parents[ry]
        self.parents[ry] = rx
        return True

    def size(self, x):
        # size of group of x's root
        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 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 = list(map(int, input().split()))

if M == 0:
    print(1)
    exit()


D = UnionFind(N)

for i in range(M):
    a, b = list(map(int, input().split()))
    a -= 1
    b -= 1
    D.union(a, b)

num = [D.size(r) for r in D.roots()]

print(max(num))

Buggy python submission (verdict: Runtime Error):
from sys import exit, stdin

input = stdin.readline
import copy

from collections import deque, Counter

# import numpy as np


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

D = [-1] * N

tmp = 0
for i in range(M):
    a, b = list(map(int, input().split()))
    a -= 1
    b -= 1
    if D[a] == -1 and D[b] == -1:
        D[a] = tmp
        D[b] = tmp
        tmp += 1
    elif D[a] == -1 and D[b] != -1:
        D[a] = D[b]
    elif D[a] != -1 and D[b] == -1:
        D[b] = D[a]
    elif D[a] != D[b]:
        for k in range(N):
            if D[k] == D[b]:
                D[k] = a


R = Counter(D)
ans = R.most_common(2)
if ans[0][0] == -1:
    print(ans[1][1])
else:
    print(ans[0][1])


Fixed submission:
from sys import exit, stdin

input = stdin.readline
import copy
from collections import deque, Counter

# import numpy as np


class BIT:
    def __init__(self, a=0):
        self.n = a
        self.d = [0] * (a + 1)

    def add(self, i, x=1):
        i += 1
        while i <= self.n:
            self.d[i] += x
            i += i & (-i)

    def sum(self, *i):
        if len(i) == 1:
            x = 0
            i += 1
            while i:
                x += self.d[i]
                i -= i & (-i)
            return x
        else:
            return sum(self, i[1] - 1) - sum(self, i[0] - 1)


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

    def find(self, x):
        # find x's root
        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):
        # unite x and y
        rx = self.find(x)
        ry = self.find(y)

        if rx == ry:
            return False
        if -(self.parents[rx]) < -(self.parents[ry]):
            rx, ry = ry, rx
        self.parents[rx] += self.parents[ry]
        self.parents[ry] = rx
        return True

    def size(self, x):
        # size of group of x's root
        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 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 = list(map(int, input().split()))

if M == 0:
    print(1)
    exit()


D = UnionFind(N)

for i in range(M):
    a, b = list(map(int, input().split()))
    a -= 1
    b -= 1
    D.union(a, b)

num = [D.size(r) for r in D.roots()]

print(max(num))