CodeEff/ECCO huggingface dataset:
# Original solution
import sys

read = sys.stdin.read
readline = sys.stdin.readline
readlines = sys.stdin.readlines
sys.setrecursionlimit(10 ** 9)
INF = 1 << 60
MOD = 1000000007


def main():
    N = int(readline())

    def rec(vec):
        if vec and int(''.join(vec)) > N:
            return 0
        ans = 0
        if all(c in vec for c in '357'):
            ans += 1
        for c in '357':
            vec.append(c)
            ans += rec(vec)
            vec.pop()
        return ans

    ans = rec([])
    print(ans)
    return


if __name__ == '__main__':
    main()


# Optimized solution
import sys

read = sys.stdin.read
readline = sys.stdin.readline
readlines = sys.stdin.readlines
sys.setrecursionlimit(10 ** 9)
INF = 1 << 60
MOD = 1000000007


def main():
    N = int(readline())

    def rec(n, used):
        ans = 0
        if all(used):
            ans += 1
        for i, d in enumerate((3, 7, 5)):
            if 10 * n + d <= N:
                cur = used[i]
                used[i] = True
                ans += rec(10 * n + d, used)
                used[i] = cur
        return ans

    print((rec(0, [False, False, False])))
    return


if __name__ == '__main__':
    main()
# Original solution
import sys
readline = sys.stdin.readline
from collections import deque

def main():
    N = int(readline())
    que = []
    for val in ['357', '375', '537', '573', '735', '753']:
        if int(val) <= N:
            que.append(val)
    res = set(que)
    que = deque(que)
    while que:
        pre = que.popleft()
        for p in ['3', '5', '7']:
            for i in range(len(pre)+1):
                next = pre[:i] + p + pre[i:]
                if int(next) <= N and next not in res:
                    que.append(next)
                    res.add(next)

    print((len(res)))

if __name__ == '__main__':
    main()

# Optimized solution
import sys
readline = sys.stdin.readline

N = int(readline())

def dfs(num):
    if int(num) > N:
        return 0
    if all(num.count(n) > 0 for n in '753'):
        res = 1
    else:
        res = 0
    for n in '753':
        res += dfs(num + n)
        
    return res


def main():
    print((dfs('0')))

if __name__ == '__main__':
    main()
# Original solution
# ABC114 C - 755
N = int(eval(input()))

def rep(s):
    if int(s) > N:
         return 0
    ret = 1 if all(s.count(c) > 0 for c in '753') else 0 
    for c in '753':
        ret += rep(s + c)
    return ret

print((rep('0')))

# Optimized solution
# C - 755

def dfs(n,s):
    if int(s)>n:
        return 0
    res=0
    if s.count('7')>0 and s.count('5')>0 and s.count('3')>0:
        res=1
    
    for i in '753':
        res+=dfs(n,s+i)
    return res

n=int(eval(input()))
print((dfs(n,'0')))
# Original solution
from itertools import product
N = int(eval(input()))
ans = 0
for l in range(1, 11):
    for p in product("357", repeat=l):
        v = "".join(p)
        if "3" in v and "5" in v and "7" in v and int("".join(p)) <= N:
            ans += 1
print(ans)

# Optimized solution
N = int(eval(input()))

cnt = 0
def dfs(s):
    global cnt
    if '3' in s and '5' in s and '7' in s and int(s) <= N:
        cnt += 1
    if len(s) >= 10:
        return cnt
    dfs(s + '3')
    dfs(s + '5')
    dfs(s + '7')
    return cnt

print((dfs('')))
# Original solution
N = int(eval(input()))

cnt = 0
def dfs(s):
    global cnt
    if '3' in s and '5' in s and '7' in s and int(s) <= N:
        cnt += 1
    if len(s) >= 10:
        return cnt
    dfs(s + '3')
    dfs(s + '5')
    dfs(s + '7')
    return cnt

print((dfs('')))

# Optimized solution
from itertools import product
N = int(eval(input()))

cnt = 0
for i in range(3,10):
    for v in product('357',repeat=i):
        val = ''.join(v)
        if int(val) <= N and '3' in val and '5' in val and '7' in val:
           cnt += 1

print(cnt)
# Original solution
N = int(eval(input()))
A = []

def f(s):
    if s != '' and eval(s) > N:
        return 0
    if all(s.count(i) >= 1 for i in '753'):
        A.append(eval(s))
    for i in '753':
        f(s + i)

f('')
print((len(A)))
# print(sorted(A))

# Optimized solution
N = int(eval(input()))
A = []

def f(s):
    if int(s) > N:
        return 0
    if all(s.count(i) >= 1 for i in '753'):
        A.append(int(s))
    for i in '753':
        f(s + i)

f('0')
print((len(A)))
# print(sorted(A))
# Original solution
from collections import deque

N = int(eval(input()))
ans = 0
option = ["7","5","3"]
dq = deque()
for s in option:
    dq.append(s)

def judge(string):
    bit = [0]*3
    chenge = {"7":0, "5":1, "3":2}
    for s in string:
        bit[chenge[s]] = 1
    return all(bit)

while dq:
    n = dq.popleft()
    if int(n) <= N and judge(n):
        ans += 1
    if int(n) > N:
        continue
    for i,s in enumerate(option):
        dq.append(n+s)

print(ans)

# Optimized solution
N = int(eval(input()))
ans = 0
def dfs(n=0,a=0,b=0,c=0):
    if n > N:
        return
    if a*b*c > 0:
        global ans
        ans += 1
    dfs(10*n+3,a+1,b,c)
    dfs(10*n+5,a,b+1,c)
    dfs(10*n+7,a,b,c+1)

dfs()
print(ans)
# Original solution
from sys import stdin
import sys
sys.setrecursionlimit(10**6) 
import bisect

n = int(stdin.readline().rstrip())

li = [7,5,3]

if n < 357:
    print((0))
    exit()

def Base_10_to_n(X, n):
    if (int(X/n)):
        return Base_10_to_n(int(X/n), n)+str(X%n)
    return str(X%n)

kazu = 0
point = 0
k = "0"
while int(k) <= n:
    k = Base_10_to_n(kazu,4)
    k = k.replace("3","7").replace("1","3").replace("2","5")
    if all(k.count(c)>0 for c in "753")and k.count("0") == 0:
        if int(k) <= n:
            point += 1
    kazu += 1
print(point)

# Optimized solution
from sys import stdin
import sys
sys.setrecursionlimit(10**6) 
import bisect

n = int(stdin.readline().rstrip())

li = [7,5,3]

if n < 357:
    print((0))
    exit()

def Base_10_to_n(X, n):
    if (int(X/n)):
        return Base_10_to_n(int(X/n), n)+str(X%n)
    return str(X%n)

kazu = 0
point = 0
k = "0"
while int(k) <= n:
    k = Base_10_to_n(kazu,4)
    if k.count("0") > 0:
        kazu += 1
        continue
    k = k.replace("3","7").replace("1","3").replace("2","5")
    if all(k.count(c)>0 for c in "753"):
        if int(k) <= n:
            point += 1
    kazu += 1
print(point)
# Original solution
from sys import stdin
import sys
sys.setrecursionlimit(10**6) 
import bisect

n = int(stdin.readline().rstrip())

li = [7,5,3]

if n < 357:
    print((0))
    exit()

def Base_10_to_n(X, n):
    if (int(X/n)):
        return Base_10_to_n(int(X/n), n)+str(X%n)
    return str(X%n)

kazu = 0
point = 0
k = "0"
while int(k) <= n:
    k = Base_10_to_n(kazu,4)
    if k.count("0") > 0:
        kazu += 1
        continue
    k = k.replace("3","7").replace("1","3").replace("2","5")
    if all(k.count(c)>0 for c in "753"):
        if int(k) <= n:
            point += 1
    kazu += 1
print(point)

# Optimized solution
n = int(eval(input()))
point = 0
def sitigosan(num,keta):
    global point
    now = keta+num
    if int(now) > n:
        return
    else:
        if "3" in now and "5" in now and "7" in now:
            point += 1
        return sitigosan("3",str(now)),sitigosan("5",str(now)),sitigosan("7",str(now))
sitigosan("","3")
sitigosan("","5")
sitigosan("","7")

print(point)
# Original solution
#0,7,5,3で選んでくる
x=[0,7,5,3]
a=[]
k=0

def new_num(c):
    global x
    d=0
    for i in range(9):
        d+=(10**i)*x[c[i]]
    return d

for i0 in range(4):
    for i1 in range(4):
        for i2 in range(4):
            for i3 in range(4):
                for i4 in range(4):
                    for i5 in range(4):
                        for i6 in range(4):
                            for i7 in range(4):
                                for i8 in range(4):
                                    l1=new_num([i0,i1,i2,i3,i4,i5,i6,i7,i8])
                                    l2=str(l1)
                                    if ("3" in l2) and ("5" in l2) and ("7" in l2) and ("0" not in l2):
                                        a.append(l1)
a.sort()
co=0
n=int(eval(input()))
for i in a:
    if i<=n:
        #print(i)
        co+=1
    else:
        break
print(co)


# Optimized solution
from itertools import product
n=int(eval(input()))
ans=[]
for i in range(3,10):
    l=list(product(["3","5","7"],repeat=i))
    for j in l:
        if len(set(j))==3:
            ans.append(int("".join(list(j))))

ans.sort()
m=len(ans)
l,r=0,m-1
while l+1<r:
    k=(l+r)//2
    if ans[k]<n:
        l=k
    elif ans[k]>n:
        r=k
    else:
        l,r=k,k
        break
if ans[l]==n:
    print((l+1))
elif ans[r]==n:
    print((r+1))
elif ans[l]>n:
    print(l)
elif ans[r]<n:
    print((r+1))
elif ans[l]<n:
    print((l+1))
#print(l,r)
#print(ans)
# Original solution
import sys
sys.setrecursionlimit(10**6)

d={}

def c(s):
	a = [0] * 10
	for i in s:
		a[int(i)] += 1
	if a[3] != 0 and a[5] != 0 and a[7] != 0:
		return True
	else:
		return False

def r(m, s):
	global d
	if s == "":
		pass
	elif m < int(s) or (s in d):
		return 0
	ret = 0
	if c(s):
		ret += 1
		d[s] = 1
	ret += r(m,s+"3")
	ret += r(m,s+"5")
	ret += r(m,s+"7")
	ret += r(m,"3"+s)
	ret += r(m,"5"+s)
	ret += r(m,"7"+s)
	return ret

def main():
	n = int(eval(input()))
	print((r(n,"")))
	return
main()

# Optimized solution
import sys
sys.setrecursionlimit(10**6)

d={}

def c(s):
	a = [0] * 10
	for i in s:
		a[int(i)] += 1
	if a[3] != 0 and a[5] != 0 and a[7] != 0:
		return True
	else:
		return False

def r(m, s):
	global d
	if s == "":
		pass
	elif m < int(s) or (s in d):
		return 0
	ret = 0
	if c(s):
		ret += 1
	d[s] = 1
	ret += r(m,s+"3")
	ret += r(m,s+"5")
	ret += r(m,s+"7")
	ret += r(m,"3"+s)
	ret += r(m,"5"+s)
	ret += r(m,"7"+s)
	return ret

def main():
	n = int(eval(input()))
	print((r(n,"")))
	return
main()
# Original solution
def func(S, num):
    ret = 0
    if '3' in S and '5' in S and '7' in S and int(S) <= num:
        ret += 1
    if len(S) == 10:
        return 0
    ret += func(S + '3', num)
    ret += func(S + '5', num)
    ret += func(S + '7', num)
    return ret

print(func('', eval(input())))

# Optimized solution
def func(S, num):
    if len(S) == 10:
        return 0
    ret = 0
    if '3' in S and '5' in S and '7' in S and int(S) <= num:
        ret += 1
    ret += func(S + '3', num)
    ret += func(S + '5', num)
    ret += func(S + '7', num)
    return ret

print(func('', eval(input())))
# Original solution
import sys
from collections import deque

input = sys.stdin.readline

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

ans = 0
visited = set()
for i in range(N):
    q = deque()
    q.append(i)
    start = len(visited)
    while q:
        pos = q.popleft()
        if pos in visited:
            continue
        visited.add(pos)
        for n_pos in relations[pos]:
            if n_pos in visited:
                continue
            q.appendleft(n_pos)
    end = len(visited)
    ans = max(ans, end - start)

print(ans)

# Optimized solution
import sys

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

input = sys.stdin.readline

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

uf = UnionFind(N)
for a, b in relations:
    uf.union(a, b)

ans = 0
for i in range(N):
    ans = max(ans, uf.size(i))
print(ans)
# Original solution
from queue import deque
N,M=list(map(int, input().split()))
f=deque()
x=deque()
mx=0
for _ in range(M):
    a,b = list(map(int, input().split()))
    for i in f:
        if a in i[0]:
            if b not in i[0]:
                i[0].add(b)
                i[1]+=1
                mx=max(mx,i[1])
            break
        elif b in i[0]:
            i[0].add(a)
            i[1]+=1
            mx=max(mx,i[1])
            break
    else:
        f.append([set((a,b)),2])
        mx=max(mx,2)

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


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

N,M=list(map(int, input().split()))
mx=0
uf = UnionFind(N+1)
for i in range(M):
	a,b = list(map(int, input().split()))
	uf.union(a,b)
for i in uf.parents:
	mx = max(mx, uf.size(i))
if M == 0:
	mx = 1
print(mx)
# Original solution
(n,m),*ab = [list(map(int, s.split())) for s in open(0)]

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

u = UnionFind(n)

for a,b in ab:
    u.union(a-1,b-1)

print((max(list(map(len, list(u.all_group_members().values()))))))

# Optimized solution
n,m = list(map(int, input().split()))

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

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

    def unite(self, x, y):
        x, y = self.root(x), self.root(y)
        if x == y:
            return False
        if x > y:
            x, y = y, x
        self.d[x] += self.d[y]
        self.d[y] = x
        return True

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

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

u = UnionFind(n)

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

print((-min(u.d)))
# Original solution
from collections import defaultdict
from collections import deque

n, m = [int(x) for x in input().split()]
person_to_friends = defaultdict(set)

for _ in range(m):
    a, b = [int(x) for x in input().split()]
    person_to_friends[a].add(b)
    person_to_friends[b].add(a)

not_searched = set(range(1, n+1))
max_pool_num = 1

while len(not_searched) > 0:
#     print(not_searched)
    first_person = not_searched.pop()
    friend_pool = set([first_person])
    que = deque([first_person])
    while len(que) > 0:
        current_person = que.popleft()
        not_searched_friends = person_to_friends[current_person].intersection(not_searched)
#         print(not_searched_friends)
        for friend in not_searched_friends:
            not_searched.remove(friend)
            que.append(friend)
            friend_pool.add(friend)
    max_pool_num = max(len(friend_pool), max_pool_num)
print(max_pool_num)

# Optimized solution
# UnionFind

# 配列で、子のID番目:(親のID), 親のID番目:(その塊の-サイズ)
# Union Findを使う
class UnionFind:
    def __init__(self, size):
        self.parent_indexes = [-1] * size
        
    def find_parent(self, n):
#         print(self.parent_indexes[n])
        if self.parent_indexes[n] < 0:
            return n
#         print('hewe')
        # 探しているnodeが指し示しているのが現在の親ではない場合、
        # 現在の親に書き換え(memo化)た上で返す
        self.parent_indexes[n] = self.find_parent(self.parent_indexes[n])
        return self.parent_indexes[n] 
    
    def union(self, n1, n2):
        if self.same_group(n1, n2):
            return False
        
        # サイズの大きい方の親が親であり続ける
        if self.size(n1) >= self.size(n2):
            tmp = self.size(n2)
            self.parent_indexes[self.find_parent(n2)] = self.find_parent(n1)
            self.parent_indexes[self.find_parent(n1)] -= tmp
            return True
        
        tmp = self.size(n1)
        self.parent_indexes[self.find_parent(n1)] = self.find_parent(n2)
        self.parent_indexes[self.find_parent(n2)] -= tmp
        return True
        
    
    def size(self, n):
        return -self.parent_indexes[self.find_parent(n)]
    
    def same_group(self, n1, n2):
        return self.find_parent(n1) == self.find_parent(n2)



n, m = [int(x) for x in input().split()]
uf = UnionFind(n)

for _ in range(m):
    a, b = [int(x) for x in input().split()]
    uf.union(a-1, b-1)
    
print((-min(uf.parent_indexes)))
# Original solution
def main():
    import sys
    sys.setrecursionlimit(100000)
    n, m, *ab, = list(map(int, open(0).read().split()))

    p = [-1] * (n + 1)

    def f(x):
        if p[x] < 0:
            return x
        else:
            return f(p[x])

    def g(x, t):
        if p[x] < 0:
            return
        nx = p[x]
        p[x] = t
        g(nx, t)
        

    ans = -1
    order = set()
    for i, j in zip(ab[::2], ab[1::2]):
        if i > j:
            i, j = j, i
        if (i, j) in order:
            continue

        pi, pj = f(i), f(j)
        if pi == pj:
            continue
        p[pi] += p[pj]
        ans = min(ans, p[pi])
        p[j] = pi
        p[pj] = pi
        g(j, pi)
        order.add((i, j))
    print((-ans))


if __name__ == '__main__':
    main()


# Optimized solution
def main():
    n, m, *ab, = list(map(int, open(0).read().split()))
    p = [-1] * (n + 1)

    def find(x):
        while p[x] > 0:
            x = p[x]
        return x

    def union(i, j):
        pi, pj = find(i), find(j)
        if pi == pj:
            return
        if p[pi] < p[pj]:
            pi, pj = pj, pi
            i, j = j, i
        p[pi] += p[pj]
        p[pj] = pi
        reconnect(j, pi)

    def reconnect(i, j):
        while p[i] > 0:
            k = p[i]
            p[i] = j
            i = k

    for i, j in zip(ab[::2], ab[1::2]):
        union(i, j)

    print((-min(p)))


if __name__ == '__main__':
    main()
# Original solution
from collections import deque

n, m = list(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)

# Optimized solution
class union_find:
    def __init__(self, node_num):
        self.root_array = [-1] * node_num

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

    def unite(self, x, y):
        x = self.root(x)
        y = self.root(y)
        if x == y:
            return
        if self.root_array[x] > self.root_array[y]:
            x, y = y, x
        self.root_array[x] += self.root_array[y]
        self.root_array[y] = x

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


def solve(n, m, ab_array):
    uf = union_find(n)
    for ab in ab_array:
        a, b = ab
        uf.unite(a - 1, b - 1)

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

    return ans

if __name__ == '__main__':
    n, m = list(map(int, input().split()))
    ab_array = [list(map(int, input().split())) for _ in range(m)]
    ans = solve(n, m, ab_array)
    print(ans)
# Original solution
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 same(self, x, y):
        return self.find(x) == self.find(y)

    def size(self, x):
        return -self.parents[self.find(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())

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

    def max_group_members(self):
        ret = 1
        for r in self.roots():
            ret = max(len(self.members(r)), ret)
        return ret

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


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

print((Groups.max_group_members()))

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


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

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

print(ans)