Given a non-empty array of unique positive integers A, consider the following graph:

There are A.length nodes, labelled A[0] to A[A.length - 1];
There is an edge between A[i] and A[j] if and only if A[i] and A[j] share a common factor greater than 1.

Return the size of the largest connected component in the graph.
 



Example 1:
Input: [4,6,15,35]
Output: 4



Example 2:
Input: [20,50,9,63]
Output: 2



Example 3:
Input: [2,3,6,7,4,12,21,39]
Output: 8


Note:

1 <= A.length <= 20000
1 <= A[i] <= 100000

Difficulty: interview

Starter code:

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        

Solutions:
from collections import defaultdict


class Solution:
    MAXPRIME=100001
    isPrime=[0 for _ in range(MAXPRIME+1)]
    isPrime[0]=-1;isPrime[1]=-1 #0 and 1 are not prime numbers
    for i in range(2,MAXPRIME):
        if isPrime[i]==0: #i is prime
            for multiple in range(i*i,MAXPRIME+1,i):
                if isPrime[multiple]==0:
                    isPrime[multiple]=i
            isPrime[i] = i

    def largestComponentSize(self, A: List[int]) -> int:
        label = defaultdict(int)

        def findRoot(key):
            if label[key] > 0:
                label[key] = findRoot(label[key])
                return label[key]
            else:
                return key
        
        def mergeRoot(k1, k2):
            r1, r2 = findRoot(k1), findRoot(k2)  
            if r1 != r2:
                r1, r2 = min(r1, r2), max(r1, r2)
                label[r1] += label[r2]
                label[r2] = r1
            return r1

        for x in A:
            root_id = 0
            prime_factors = set()
            while Solution.isPrime[x]!=-1:
                p = Solution.isPrime[x]
                root_id = findRoot(p) if root_id == 0 else mergeRoot(root_id, p)
                x //= p
            label[root_id] -= 1
        
        return -min(label.values())


class UF:
    def __init__(self,n):
        self.p=[i for i in range(n)]  # parent array
        self.s=[1]*n  # size array
        
    def find(self,x): # find the representative/root of x
        if self.p[x]!=x:
            self.p[x]=self.find(self.p[x])
        return self.p[x]

class Solution:
    M=100000
    sieve=[0]*(M+1) # stores the largest prime divisor of integers up to M
    for i in range(2,M+1):
        if sieve[i]!=0:
            continue
        for j in range(1,M//i+1):
            sieve[j*i]=i
        
    def largestComponentSize(self, A: List[int]) -> int:   
        g=UF(len(A))
        primes=defaultdict(list) # {q:[nums]} list of integers that's divisible by prime q
        for i,num in enumerate(A):
            while num>1:
                q=self.sieve[num]
                primes[q].append(i) # add the ith element to be divisible by q
                while num%q==0:
                    num//=q
                    
        for l in primes.values():
            root=g.find(l[0]) # representative/root of the 1st integer divisible by q
            for i in l[1:]: # joins all components with root
                node=g.find(i)
                if node!=root:
                    if g.s[root]<g.s[node]: # connect the smaller set to the larger one (for efficiency)
                        root,node=node,root
                    g.p[node]=root
                    g.s[root]+=g.s[node]
        
        return max(g.s)

#
# @lc app=leetcode id=952 lang=python3
#
# [952] Largest Component Size by Common Factor
#

# @lc code=start
from collections import defaultdict


class Solution:
    MAXPRIME=100001
    isPrime=[0 for _ in range(MAXPRIME+1)]
    isPrime[0]=-1;isPrime[1]=-1 #0 and 1 are not prime numbers
    for i in range(2,MAXPRIME):
        if isPrime[i]==0: #i is prime
            for multiple in range(i*i,MAXPRIME+1,i):
                if isPrime[multiple]==0:
                    isPrime[multiple]=i
            isPrime[i] = i

    def largestComponentSize(self, A: List[int]) -> int:
        label = defaultdict(int)

        def findRoot(key):
            if label[key] > 0:
                label[key] = findRoot(label[key])
                return label[key]
            else:
                return key
        
        def mergeRoot(k1, k2):
            r1, r2 = findRoot(k1), findRoot(k2)  
            if r1 != r2:
                r1, r2 = min(r1, r2), max(r1, r2)
                label[r1] += label[r2]
                label[r2] = r1
            return r1

        for x in A:
            root_id = 0
            prime_factors = set()
            while Solution.isPrime[x]!=-1:
                p = Solution.isPrime[x]
                root_id = findRoot(p) if root_id == 0 else mergeRoot(root_id, p)
                x //= p
            label[root_id] -= 1
        
        return -min(label.values())
# @lc code=end


class DSU:
    def __init__(self, n):
        self.p = list(range(n))
        self.sz = [1]*(n)
    
    def find(self, x):
        if x == self.p[x]:
            return x
        self.p[x] = self.find(self.p[x])
        return self.p[x]

    def unite(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return
        if self.sz[x] < self.sz[y]:
            x, y = y, x
        self.p[y] = x
        self.sz[x] += self.sz[y]

class Solution:
    def largestComponentSize(self, a: List[int]) -> int:
        N = max(a)+1
        
        idx = [-1]*N
        for i, x in enumerate(a):
            idx[x] = i
            
        dsu = DSU(N)
        siv = [True]*N
        
        for i in range(2, N):
            if siv[i]:
                root = idx[i]
                for j in range(2*i, N, i):
                    siv[j] = False
                    if idx[j] != -1:
                        if root == -1:
                            root = idx[j]
                        dsu.unite(root, idx[j])

        return max(dsu.sz)


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        primes = []
        for x in range(2, int(max(A)**0.5)+1):
            for y in primes:
                if x % y == 0:
                    break
            else:
                primes.append(x)
    
        factors = collections.defaultdict(list)         # compute factors of each 'a'
        for a in A:
            x = a
            for p in primes:
                if p*p > x:
                    break
                if x % p == 0:
                    factors[a].append(p)
                    while x % p == 0:
                        x //= p
            if x > 1:                                   # a new prime found
                factors[a].append(x)
                primes.append(x)
                
        primes = list(set(primes))
        n = len(primes)
        p2i = {p: i for i,p in enumerate(primes)}       # prime to index
        
        parent = [i for i in range(n)]                  # union-find on primes
        
        def find(i):
            if i != parent[i]:
                parent[i] = find(parent[i])
            return parent[i]
        
        def union(i,j):
            pi, pj = find(i), find(j)
            if pi != pj:
                parent[pi] = pj

        for a in A:
            if factors[a]:
                p0 = factors[a][0]
                for p in factors[a][1:]:                # link two primes if they are factors of 'a'
                    union(p2i[p0], p2i[p])
        
        count = collections.Counter(find(p2i[factors[a][0]]) for a in A if factors[a])      # each 'a' corresponds to a prime index
        return max(count.values())


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        primes = []
        for x in range(2, int(max(A)**0.5)+1):
            for y in primes:
                if x % y == 0:
                    break
            else:
                primes.append(x)
    
        factors = collections.defaultdict(list)         # compute factors of each 'a'
        for a in A:
            x = a
            for p in primes:
                if p*p > x:
                    break
                if x % p == 0:
                    factors[a].append(p)
                    while x % p == 0:
                        x //= p
            if x > 1:                                   # a new prime found
                factors[a].append(x)
                primes.append(x)
                
        primes = list(set(primes))
        n = len(primes)
        p2i = {p: i for i,p in enumerate(primes)}       # prime to index
        
        parent = [i for i in range(n)]                  # union-find on primes
        
        def find(i):
            if i != parent[i]:
                parent[i] = find(parent[i])
            return parent[i]
        
        def union(i,j):
            pi, pj = find(i), find(j)
            if pi != pj:
                parent[pi] = pj

        for a in A:
            if factors[a]:
                p0 = factors[a][0]
                for p in factors[a][1:]:                # link two primes if they are factors of 'a'
                    union(p2i[p0], p2i[p])
        
        count = collections.Counter(find(p2i[factors[a][0]]) for a in A if factors[a])      # each 'a' corresponds to a prime index
        return max(count.values())

class ds:
    def __init__(self, n):
        self.arr = list(range(n))
        self.size = [1] * n
        
    def find(self, x):
        if self.arr[x] != x: self.arr[x] = self.find(self.arr[x])
        return self.arr[x]

    def union(self, x, y):
        Ax= self.find(x)
        Ay= self.find(y)
        if Ax == Ay: 
            return False
        if self.size[Ax] > self.size[Ay]: Ax, Ay = Ay, Ax
        self.arr[Ax] = Ay
        self.size[Ay] += self.size[Ax]
        return True
    
def primes(n):
    odds = range(3, n+1, 2)
    sieve = set(sum([list(range(q*q, n+1, q+q)) for q in odds], []))
    return [2] + [p for p in odds if p not in sieve]


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def factors(n):
            result = set()
            for p in primeNumber:
                while n % p == 0:
                    n //= p
                    result.add(p)
            if n > 1: result.add(n)
            return list(result) 
        
        n, m = len(A), max(A)
        dsa = ds(m+1)
        primeNumber=primes(round(m**.5)+1)
        for d in A:
            rest = factors(d)
            for i in rest:
                dsa.union(d, i)
        return Counter([dsa.find(x) for x in A]).most_common(1)[0][1]

import math
class disjoint(object):
    def __init__(self, size):
        self.root_node_size = [1] * size
        self.nodes = [n for n in range(size)]
        
    def findRoot(self, node):
        while(self.nodes[node] != node):            
            node = self.nodes[node]
        return node
    
    def merge(self, val_one, val_two):
        root_one = self.findRoot(val_one)
        root_two = self.findRoot(val_two)
        
        if root_one == root_two:
            return
        
        r1size = self.root_node_size[root_one]
        r2size = self.root_node_size[root_two]
        
        new_root = None
        old_root = None
        if r1size <= r2size:
            new_root = root_two
            old_root = root_one
        else:
            new_root = root_one 
            old_root = root_two
        self.root_node_size[new_root] += self.root_node_size[old_root]
        self.root_node_size[old_root] = 0
        self.nodes[old_root] = new_root
        
class Solution:
    
    def largestComponentSize(self, A: List[int]) -> int:
        def factors(n):
            known_factors = set()
            while n % 2 == 0:
                known_factors.add(2)
                n //= 2
            for possible_factor in range(3, math.floor(math.sqrt(n))+1, 2):
                while n % possible_factor == 0:
                    known_factors.add(possible_factor)
                    n //= possible_factor
            if n > 2:
                known_factors.add(n)
            return known_factors
        
        dj = disjoint(len(A))
        known_factors = dict()
        for (i,v) in enumerate(A):
            for p in factors(v):
                if p in known_factors:
                    dj.merge(i, known_factors[p])
                known_factors[p] = i
        return max(dj.root_node_size)


class DSU:
    def __init__(self, count):
        self.parent = [i for i in range(count)]
        self.size = [1 for _ in range(count)]
        self.max = 0
    
    def find(self, x):
        root = x
        while root != self.parent[root]:
            root = self.parent[root]
        while x != root:
            next_root = self.parent[x]
            self.parent[x] = root
            x = next_root
        return root
    
    def union(self, x, y):
        r1, r2 = self.find(x), self.find(y)
        if r1 == r2:
            return
        if self.size[r1] < self.size[r2]:
            self.size[r2] += self.size[r1]
            self.parent[r1] = r2
        else:
            self.size[r1] += self.size[r2]
            self.parent[r2] = r1
        self.max = max(self.max, self.size[r1], self.size[r2])
        
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        dsu = DSU(len(A))
        def getPrimeFactors( n):
            res = set()
            while n % 2 == 0:
                res.add(2)
                n //= 2
            for i in range(3, int(math.sqrt(n)) + 1, 2):
                while n % i == 0:
                    res.add(i)
                    n //= i
            if n > 2:
                res.add(n)
            return res
        prime_to_idx = {}
        for i, n in enumerate(A):
            primes = getPrimeFactors(n)
            for prime in primes:
                if prime in prime_to_idx:
                    dsu.union(i, prime_to_idx[prime])
                prime_to_idx[prime] = i
        return dsu.max

class UF(object):
    def uf(self, n):
        self.uf = [i for i in range(n)]
        self.size = [1] * n
        
    def find(self, x):
        if x != self.uf[x]:
            self.uf[x] = self.find(self.uf[x])
        return self.uf[x]

    def union(self, x, y):
        xx = self.find(x)
        yy = self.find(y)
        if xx == yy:
            return 
        self.uf[xx] = yy
        self.size[yy] += self.size[xx]
        # self.size[xx] = 0
        
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def primefactors(n):
            # 暴力求取因子
            out = set()
            # 第一步是提取2且n变成奇数
            while n % 2 == 0:
                out.add(2)
                n //= 2
            # 第二步是从3开始遍历奇数
            for i in range(3, int(math.sqrt(n)) + 1, 2):
                while n % i == 0:
                    out.add(i)
                    n //= i
            # 第三步关照额外corner情况
            if n > 2:
                out.add(n)
            return out
        '''
        idx_lookup = {A[i]: i for i in range(len(A))} 
        uf = UF()
        uf.uf(len(A))
        primeAndItsMultiples = collections.defaultdict(list)
        for i in A:
            factors = primefactors(i)
            for f in factors:
                primeAndItsMultiples[f].append(i)
        for idx, multiples in primeAndItsMultiples.items():
            if multiples:
                root = multiples[0] # use the first multiple as their root
                for node in multiples[1:]:
                    uf.union(idx_lookup[node], idx_lookup[root]) # connect node with root             
        return max(uf.size)
        '''
        uf = UF()
        uf.uf(len(A))
        
        prime = {}
        for i, v in enumerate(A):
            factors = primefactors(v)
            for p in factors:
                if p in prime:
                    uf.union(i, prime[p])
                else:
                    prime[p] = i
        return max(uf.size)

class UF:
    def __init__(self,n):
        self.p=[i for i in range(n)]  # parent array
        self.s=[1]*n  # size array
        
    def find(self,x): # find the representative/root of x
        if self.p[x]!=x:
            self.p[x]=self.find(self.p[x])
        return self.p[x]

class Solution:
    M=100000
    sieve=[0]*(M+1) # stores the minimum prime divisor of integers up to M
    for i in range(2,M+1):
        if sieve[i]!=0:
            continue
        for j in range(1,M//i+1):
            sieve[j*i]=i
        
    def largestComponentSize(self, A: List[int]) -> int:   
        g=UF(len(A))
        primes=defaultdict(list) # {q:[nums]} list of integers that's divisible by prime q
        for i,num in enumerate(A):
            tmp=-1
            while num>1:
                q=self.sieve[num]
                num//=q
                if q!=tmp:
                    primes[q].append(i) # add the element to be divisible by q
                    tmp=q
                    
        for l in primes.values():
            root=g.find(l[0]) # representative/root of the 1st integer divisible by q
            for i in l[1:]: # joins all components with root
                node=g.find(i)
                if node!=root:
                    if g.s[root]<g.s[node]: # connect the smaller set to the larger one
                        root,node=node,root
                    g.p[node]=root
                    g.s[root]+=g.s[node]
        
        return max(g.s)

class DisjSet:
    def __init__(self, n ):
        self.disj_set = [-1] * n
        
    def find(self, x):
        while self.disj_set[x] >= 0:
            x = self.disj_set[x]
        return x
    
    def union(self, x, y):
        i = self.find(x)
        j = self.find(y)
        if i == j:
            return
        if self.disj_set[i] < self.disj_set[j]:
            self.disj_set[i] += self.disj_set[j]
            self.disj_set[j] = i
        else:
            self.disj_set[j] += self.disj_set[i]
            self.disj_set[i] = j
    
    def maxset(self):
        return -min(self.disj_set)
    
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def gen_primes(n):
            candidates = [1] * n
            for i in range(2, int(math.sqrt(n)) + 1):
                if candidates[i]:
                    for j in range(i ** 2, n, i):
                        candidates[j] = 0
            return [i for i in range(2, n) if candidates[i]]
        primes = gen_primes(int(math.sqrt(max(A))) + 1)
        def factor(n):
            result = set()
            for i in primes:
                if i > int(math.sqrt(n)):
                    break
                if n % i == 0:
                    result.add(i)
                    while n % i == 0:
                        n //= i
            result.add(n)
            return result
        n = len(A)
        disj = DisjSet(n)
        g = {}
        for i, a in enumerate(A):
            factors = factor(a)
            for f in factors:
                if f == 1:
                    continue
                if f not in g:
                    g[f] = i
                else:
                    disj.union(i, g[f])
        return disj.maxset()

class UnionFindSet:
    def __init__(self, n):
        self.parents = list(range(n))
        self.ranks = [1] * n
        
    def find(self, u):
        if u != self.parents[u]:
            self.parents[u] = self.find(self.parents[u])
        return self.parents[u]
    
    def union(self, u, v):
        pu, pv = self.find(u), self.find(v)
        if pu == pv:
            return False
        if self.ranks[pu] > self.ranks[pv]:
            self.parents[pv] = pu
            self.ranks[pu] += self.ranks[pv]
        elif self.ranks[pu] < self.ranks[pv]:
            self.parents[pu] = pv
            self.ranks[pv] += self.ranks[pu]
        else:
            self.parents[pu] = pv
            self.ranks[pv] += self.ranks[pu]
        return True
            
            
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def get_prime_factors(n):
            ans = set()
            while n % 2 == 0: 
                ans.add(2)
                n //= 2
            for i in range(3, int(math.sqrt(n))+1, 2): 
                while n % i== 0: 
                    ans.add(i) 
                    n //= i 
            if n > 2: 
                ans.add(n)
            return ans
        
        n = len(A)
        uf = UnionFindSet(n)
        
        dic = {}
        for i, a in enumerate(A):
            primes = get_prime_factors(a)
            for p in primes:
                if p in dic:
                    uf.union(i, dic[p])
                dic[p] = i
        
        return max(uf.ranks)

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def decompose(n):
            def rec(n, start):
                for i in range(start, int(math.sqrt(n)) + 1, 2):
                    if n % i == 0:
                        return rec(n // i, i) | {i}
                return {n}
            if n % 2 == 0:
                while n % 2 == 0:
                    n //= 2
                if n == 1:
                    return {2}
                return {2} | rec(n, 3)
            return rec(n, 3)
        prime_set = collections.defaultdict(list)
        for i in range(len(A)):
            for f in decompose(A[i]):
                prime_set[f].append(i)
        ls = list(range(len(A)))
        def find(x):
            if ls[x] != x:
                ls[x] = find(ls[x])
            return ls[x]
        def union(x, y):
            ls[find(x)] = find(y)
        for v in prime_set.values():
            for i in range(len(v) - 1):
                union(v[i], v[i+1])
        return max(Counter([find(i) for i in range(len(A))]).values())

class UF(object):
    def uf(self, n):
        self.uf = [i for i in range(n)]
        self.size = [1] * n
        
    def find(self, x):
        if x != self.uf[x]:
            self.uf[x] = self.find(self.uf[x])
        return self.uf[x]

    def union(self, x, y):
        xx = self.find(x)
        yy = self.find(y)
        if xx == yy:
            return 
        self.uf[xx] = yy
        self.size[yy] += self.size[xx]
        # self.size[xx] = 0
        
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def primefactors(n):
            # 暴力求取因子
            out = set()
            # 第一步是提取2且n变成奇数
            while n % 2 == 0:
                out.add(2)
                n //= 2
            # 第二步是从3开始遍历奇数
            for i in range(3, int(math.sqrt(n)) + 1, 2):
                while n % i == 0:
                    out.add(i)
                    n //= i
            # 第三步关照额外corner情况
            if n > 2:
                out.add(n)
            return out
        '''
        idx_lookup = {A[i] : i for i in range(len(A))} 
        uf = UF()
        uf.uf(len(A))
        # 使用因子作为key 来收集index表示公有相同因子
        primeAndItsMultiples = collections.defaultdict(list)
        for i in A:
            factors = primefactors(i)
            for f in factors:
                primeAndItsMultiples[f].append(i)
        for idx, multiples in primeAndItsMultiples.items():
            if multiples:
                root = multiples[0] # use the first multiple as their root
                for node in multiples[1:]:
                    uf.union(idx_lookup[node], idx_lookup[root]) # connect node with root             
        return max(uf.size)
        '''
        uf = UF()
        uf.uf(len(A))
        
        prime = {}
        for i, v in enumerate(A):
            factors = primefactors(v)
            for p in factors:
                if p in prime:
                    uf.union(i, prime[p])
                else:
                    prime[p] = i
        return max(uf.size)

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        uf = {}
        rank = {i: 1 for i in range(len(A))}
        
        def find(x):
            uf.setdefault(x, x)
            if uf[x] != x:
                uf[x] = find(uf[x])
            return uf[x]
        
        def union(x, y):
            px, py = find(x), find(y)
            if px != py:
                if rank[px] > rank[py]:
                    px, py = py, px
                rank[py] += rank[px]
                uf[px] = py
            
        def primeFactor(x):
            ans = set()
            if not x % 2:
                ans.add(2)
                while not x % 2: x //= 2
            for k in range(3, int(sqrt(x)) + 1, 2):
                if not x % k:
                    ans.add(k)
                    while not x % k: x //= k
                # if x == 1: break
            if x > 1: ans.add(x)
            return ans
                
        dic = {}
        for i in range(len(A)):
            for k in primeFactor(A[i]):
                dic.setdefault(k, i)
                union(i, dic[k])
        # print(rank)
        return max(Counter([find(i) for i in range(len(A))]).values())

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        uf = {}
        rank = {i: 1 for i in range(len(A))}

        def find(x):
            uf.setdefault(x, x)
            if uf[x] != x:
                uf[x] = find(uf[x])
            return uf[x]

        def union(x, y):
            px = find(x)
            py = find(y)
            if px != py:
                if rank[px] > rank[py]:
                    px, py = py, px
                rank[py] += rank[px]
                uf[px] = py

        def primeFactor(x):
            ans = set()
            if not x % 2:
                ans.add(2)
                while not x % 2: x //= 2
            for i in range(3, int(math.sqrt(x)) + 1, 2):
                if not x % i:
                    ans.add(i)
                    while not x % i: x //= i
            if x > 1: ans.add(x)
            return ans

        dic = {}
        for i in range(len(A)):
            for j in primeFactor(A[i]):
                dic.setdefault(j, i)
                union(i, dic[j])
        cnt = Counter()
        for i in range(len(A)):
            cnt[find(i)] += 1
        return max(cnt.values())

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        def sieve():
            i = 2
            while i < len(spf):
                spf[i] = 2
                i += 2
            i = 3
            while i * i < len(spf):
                if spf[i] == i:
                    j = i
                    while j < len(spf):
                        if spf[j] == j:
                            spf[j] = i
                        j += i
                i += 2
        
        spf, di, factors, visited_nums, visited_factors, ans = [i for i in range(max(A) + 1)], defaultdict(set), defaultdict(set), set(), set(), 1
        
        sieve()  # 1
        
        for num in A:
            x = num
            while x != 1:
                di[spf[x]].add(num)
                factors[num].add(spf[x])
                x //= spf[x]
        
        for num in A:  # 2
            if num in visited_nums:
                continue
                
            visited_nums.add(num)
            cur, queue = 1, deque([])
            for factor in factors[num]:
                queue.append(factor)
                
            while queue: 
                factor = queue.popleft()
                visited_factors.add(factor)
                for next_num in di[factor]:  # 3
                    if next_num in visited_nums:
                        continue
                        
                    visited_nums.add(next_num)
                    cur += 1
                    for next_factor in factors[next_num]:
                        if next_factor in visited_factors:
                            continue
                        
                        visited_factors.add(next_factor)
                        queue.append(next_factor)
                
            ans = max(ans, cur)
        
        return ans

class Solution:    
    def get_prime_numbers(self, num_to_idx_dict, max_num: int) -> List[int]:
        is_prime_list = [True] * (max_num + 1)        
        prime_to_nums_dict = defaultdict(list)
        
        for i in range(2, max_num // 2 + 1):            
            if is_prime_list[i] == False: continue
            
            num = i
            while num <= max_num:
                if num in num_to_idx_dict:
                    prime_to_nums_dict[i].append(num_to_idx_dict[num])
                is_prime_list[num] = False
                num += i         
        
        return prime_to_nums_dict
    
    def find(self, union_list, index: int) -> int:
        if index == union_list[index]: return index
        #return self.find(union_list, union_list[index])    
        parent = self.find(union_list, union_list[index])
        union_list[index] = parent
        return parent
        
    def union(self, union_list, index1: int, index2: int) -> None:
        union1, union2 = self.find(union_list, index1), self.find(union_list, index2)                
        #union_list[union1], union_list[index2] = union2, union2
        union_list[union1] = union2
        
    def largestComponentSize(self, A: List[int]) -> int:
        if len(A) == 0: return 0        
        max_num = max(A)
        union_list = [i for i in range(len(A))]
        count_list = [0] * (len(A))
        num_to_idx_dict = dict(list(zip(A, list(range(len(A))))))
        
        # get prime numbers
        prime_to_nums_dict = self.get_prime_numbers(num_to_idx_dict, max_num) # prime numbers of A's numbers
        
        # linking numbers having the same prime 
        for prime, nums in list(prime_to_nums_dict.items()):
            for i in range(len(nums) - 1):
                self.union(union_list, nums[i], nums[i + 1])
        
        # counting numbers in a component        
        for i, num in enumerate(A):
            count_list[self.find(union_list, i)] += 1        
            
        return max(count_list)
# Time complexity: O(n * p) where n is the maximum number of A and p is the number of prime numbers less than n
# Space complexity: O(n + p) we can ignore p


class DisjSet:
    def __init__(self, n ):
        self.disj_set = [-1] * n
        
    def find(self, x):
        while self.disj_set[x] >= 0:
            x = self.disj_set[x]
        return x
    
    def union(self, x, y):
        i = self.find(x)
        j = self.find(y)
        if i == j:
            return
        if self.disj_set[i] < self.disj_set[j]:
            self.disj_set[i] += self.disj_set[j]
            self.disj_set[j] = i
        else:
            self.disj_set[j] += self.disj_set[i]
            self.disj_set[i] = j
    
    def maxset(self):
        return -min(self.disj_set)
    
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def gen_primes(n):
            candidates = [1] * n
            for i in range(2, int(math.sqrt(n)) + 1):
                if candidates[i]:
                    for j in range(i ** 2, n, i):
                        candidates[j] = 0
            return [i for i in range(2, n) if candidates[i]]
        primes = gen_primes(int(math.sqrt(max(A))) + 1)
        def factor(n):
            result = []
            for i in primes:
                if i > int(math.sqrt(n)):
                    break
                if n % i == 0:
                    result.append(i)
                    while n % i == 0:
                        n //= i
            result.append(n)
            return result
        n = len(A)
        disj = DisjSet(n)
        g = {}
        for i, a in enumerate(A):
            factors = factor(a)
            for f in factors:
                if f == 1:
                    continue
                if f not in g:
                    g[f] = i
                else:
                    disj.union(i, g[f])
        return disj.maxset()

class Solution:    
    def get_prime_numbers(self, num_to_idx_dict, max_num: int) -> List[int]:
        is_prime_list = [True] * (max_num + 1)        
        prime_to_nums_dict = defaultdict(list)
        
        for i in range(2, max_num // 2 + 1):            
            if is_prime_list[i] == False: continue 
            num = i
            while num <= max_num:
                if num in num_to_idx_dict: prime_to_nums_dict[i].append(num_to_idx_dict[num])
                is_prime_list[num], num = False, num + i
                
        return prime_to_nums_dict
    
    def find(self, union_list, index: int) -> int:
        if index == union_list[index]: return index
        parent = self.find(union_list, union_list[index])
        union_list[index] = parent
        return parent
        
    def union(self, union_list, index1: int, index2: int) -> None:
        union1, union2 = self.find(union_list, index1), self.find(union_list, index2)                
        union_list[index2] = union2
        union_list[union1] = union2
        
    def largestComponentSize(self, A: List[int]) -> int:
        if len(A) == 0: return 0        
        max_num = max(A)
        union_list, count_list = [i for i in range(len(A))], [0] * (len(A))
        num_to_idx_dict = dict(list(zip(A, list(range(len(A))))))
        
        # get prime numbers
        prime_to_nums_dict = self.get_prime_numbers(num_to_idx_dict, max_num) # prime numbers of A's numbers
        
        # linking numbers having the same prime 
        for prime, nums in list(prime_to_nums_dict.items()):
            for i in range(len(nums) - 1):
                self.union(union_list, nums[i + 1], nums[i])
        
        # counting numbers in a component        
        for i, num in enumerate(A):
            count_list[self.find(union_list, i)] += 1        
            
        return max(count_list)
# Time complexity: O(n * p) where n is the maximum number of A and p is the number of prime numbers less than n
# Space complexity: O(n + p) we can ignore p


class DSU:
    def __init__(self, N):
        self.parent = list(range(N))
        self.size = [1] * N

    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def union(self, x, y):
        xr = self.find(x)
        yr = self.find(y)
        
        if xr == yr: return
        
        if self.size[xr] >= self.size[yr]:
            self.size[xr] += self.size[yr]
            self.size[yr] = self.size[xr]
            self.parent[yr] = xr
        else:
            self.size[yr] += self.size[xr]
            self.size[xr] = self.size[yr]
            self.parent[xr] = yr


class Solution:
        
    def largestComponentSize(self, A: List[int]) -> int:
        N = len(A)
        max_A = max(A)
        is_prime = [True] * (max_A+1)
        index = {x: i for i, x in enumerate(A)}
        dsu = DSU(N)
        
        for factor in range(2, max_A + 1):
            if is_prime[factor]:
                multiplier = factor << 1
                previous = index.get(factor)
                
                while multiplier <= max_A:
                    is_prime[multiplier] = False
                    if multiplier in index:
                        if previous is not None: 
                            dsu.union(previous, index.get(multiplier))
                        previous = index[multiplier]
                        
                    multiplier += factor
                    
                    
        # Browse DSU for result
        return max(dsu.size)

class DSU:
    
    def __init__(self, count):
        self.size = [1 for _ in range(count)]
        self.parent = [i for i in range(count)]
        self.max_size = 0
    
    def find(self, x):
        root = x
        while root != self.parent[root]:
            root = self.parent[root]
        while x != root:
            next_node = self.parent[x]
            self.parent[x] = root
            x = next_node
        return root
    
    def union(self, x, y):
        r1, r2 = self.find(x), self.find(y)
        if r1 == r2:
            return
        if self.size[r1] < self.size[r2]:
            self.size[r2] += self.size[r1]
            self.parent[r1] = r2
        else:
            self.size[r1] += self.size[r2]
            self.parent[r2] = r1
        self.max_size = max(self.max_size, self.size[r1], self.size[r2])

class Solution:
    
    def getPrimeFactors(self, n):
        res = set()
        while n % 2 == 0:
            res.add(2)
            n //= 2
        for i in range(3, int(math.sqrt(n)) + 1, 2):
            while n % i == 0:
                res.add(i)
                n //= i
        if n > 2:
            res.add(n)
        return res
                
    def largestComponentSize(self, A: List[int]) -> int:
        dsu = DSU(len(A))
        prime_to_idx = {}
        for i, n in enumerate(A):
            primes = self.getPrimeFactors(n)
            for prime in primes:
                if prime in prime_to_idx:
                    dsu.union(i, prime_to_idx[prime])
                prime_to_idx[prime] = i
        return dsu.max_size

class UnionFind(object):
    def uf(self, n):  
        self.uf = [i for i in range(n)]
        self.size = [1] * n
        
    def find(self, x):  
        while x != self.uf[x]:
            self.uf[x] = self.uf[self.uf[x]]
            x = self.uf[x]
        return self.uf[x]

    def union(self, x, y):  
        x_root = self.find(x)
        y_root = self.find(y)
        if x_root == y_root:
            return
        self.uf[x_root] = y_root
        self.size[y_root] += self.size[x_root]
        self.size[x_root] = 0
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def primeFactors(n):  # Prime factor decomposition
            out = set()
            while n % 2 == 0: 
                out.add(2)
                n //= 2
            for i in range(3, int(math.sqrt(n))+1, 2): 
                while n % i== 0: 
                    out.add(i) 
                    n //= i 
            if n > 2: 
                out.add(n)
            return out
        
        idx_lookup = {A[i]: i for i in range(len(A))} # in order to find idx in uf
        uf = UnionFind()
        uf.uf(len(A))
        primeAndItsMultiples = collections.defaultdict(list) # {2: [4, 6], 3: [6, 15], 5: [15, 35], 7: [35]})
        
        for i in A:
            factors = primeFactors(i)
            for f in factors:
                primeAndItsMultiples[f].append(i)

        # we don't need to connect all the multiples of a prime, 
        # just use the first multiple as their root
        for idx, multiples in primeAndItsMultiples.items():
            if multiples:
                root = multiples[0] # use the first multiple as their root
                for node in multiples[1:]:
                    uf.union(idx_lookup[node], idx_lookup[root]) # connect node with root
                    
        return max(uf.size)

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        uf = {}
        # rank = {i: 1 for i in range(len(A))}
        
        def find(x):
            uf.setdefault(x, x)
            if uf[x] != x:
                uf[x] = find(uf[x])
            return uf[x]
        
        def union(x, y):
            px, py = find(x), find(y)
            if px != py:
                # if rank[px] > rank[py]:
                #     px, py = py, px
                # rank[py] += rank[px]
                uf[px] = py
            
        def primeFactor(x):
            ans = set()
            if not x % 2:
                ans.add(2)
                while not x % 2: x //= 2
            for k in range(3, int(sqrt(x)) + 1, 2):
                if not x % k:
                    ans.add(k)
                    while not x % k: x //= k
                # if x == 1: break
            if x > 1: ans.add(x)
            return ans
                
        dic = {}
        for i in range(len(A)):
            for k in primeFactor(A[i]):
                dic.setdefault(k, i)
                union(i, dic[k])
        # print(rank)
        return max(Counter([find(i) for i in range(len(A))]).values())

from collections import defaultdict as d
class Solution:
    MAXPRIME=100001
    isPrime=[0 for _ in range(MAXPRIME+1)]
    isPrime[0]=-1;isPrime[1]=-1 #0 and 1 are not prime numbers
    for i in range(2,MAXPRIME//2):
        if isPrime[i]==0: #i is prime
            for multiple in range(i*i,MAXPRIME+1,i):
                if isPrime[multiple]==0:
                    isPrime[multiple]=i         
    def largestComponentSize(self, A: List[int]) -> int:
        arr=A
        n=len(arr)
        
        primeConnections=d(set) #primeConnections[i]={connected prime numbers}
        primeFactorCnts=d(lambda:0)
        
        for x in arr:
            if x==1:continue
            primeFactors=set()
            while Solution.isPrime[x]!=0:
                primeFactors.add(Solution.isPrime[x])
                x//=Solution.isPrime[x]
            primeFactors.add(x)
            primeFactors=list(primeFactors)
            if len(primeFactors)>0:
                primeFactorCnts[primeFactors[0]]+=1 #only increment the smallest prime factor since all the prime factors will be linked
                for i in range(len(primeFactors)-1):
                    for j in range(i+1,len(primeFactors)):
                        primeConnections[primeFactors[i]].add(primeFactors[j]) #create links between all prime factors for the number
                        primeConnections[primeFactors[j]].add(primeFactors[i])
        
        def dfs(p,componentSize): #find the total size of each component
            exploredSet.add(p)
            componentSize[0]+=primeFactorCnts[p]
            for nex in primeConnections[p]:
                if nex not in exploredSet:
                    dfs(nex,componentSize)
                    
        connectedComponentsSizes=[]
        exploredSet=set()
        for p in primeConnections.keys():
            if p not in exploredSet:
                componentSize=[0]
                dfs(p,componentSize)
                connectedComponentsSizes.append(componentSize[0])
        ans=max(connectedComponentsSizes)
        return ans

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        A = set(A)
        n = max(A)+1
        p = [True]*n
        p[0] = p[1] = False
        dic1, dic2 = collections.defaultdict(set), collections.defaultdict(set)
        for i in range(2, n):
            if p[i]:
                for j in range(i, n, i):
                    p[j] = False if j != i else True
                    if j in A:
                        dic1[i].add(j)
                        dic2[j].add(i)
        
        seen, res = set(), 0
        for num in A:
            if num not in seen:
                seen.add(num)
                cur, s = 0, [num]
                while s:
                    node = s.pop()
                    cur +=1
                    for m in dic2[node]:
                        for nxt in dic1[m]:
                            if nxt not in seen:
                                seen.add(nxt)
                                s.append(nxt)
                        dic1.pop(m)
                res = max(res, cur)
        return res


class DUS(object):
    
    def __init__(self, n):
        self.p = [ *list(range(n)) ]
        self.size = [1] * n
        
    def Find(self, x):
        if self.p[x] == x:
            return x
        tmp = []
        while self.p[x] != x:
            tmp.append(x)
            x = self.p[x]
        for t in tmp:
            self.p[t] = x
        return x
    
    def Union(self, x, y):
        xr = self.Find(x)
        yr = self.Find(y)
        if xr != yr:
            self.p[yr] = xr
            self.size[xr] += self.size[yr]
            self.size[yr] = 0
    

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        def PFD(num):
            ret = set()
            if num % 2 == 0:
                ret.add(2)
                while num % 2 == 0:
                    num //= 2
            for i in range(3, int(num ** 0.5)+1 , 2 ):
                if num % i == 0:
                    ret.add(i)
                    while num % i == 0:
                        num //= i
            if num > 2:
                ret.add(num)
            return ret
        
        dic = {}
        dus = DUS(len(A))
        for idx, a in enumerate(A):
            for p in PFD(a):
                if p in dic:
                    dus.Union(dic[p], idx)
                dic[p] = idx
        
        return max(dus.size)
        
        


class UFDS:
    def __init__(self, n, nums):
        self.p = list(range(n+1))
        self.size = [0]*(n+1)
        for num in nums:
            self.size[num] = 1
    
    def find(self, n):
        if n != self.p[n]:
            self.p[n] = self.find(self.p[n])
        return self.p[n]
    
    def union(self, i, j):
        p1 = self.find(i)
        p2 = self.find(j)
        if p1 != p2:
            if self.size[p1] > self.size[p2]:
                self.p[p2] = p1
                self.size[p1] += self.size[p2]
            else:
                self.p[p1] = p2
                self.size[p2] += self.size[p1]                

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        hi = max(A)
        ufds = UFDS(hi, A)
        isPrime = [True]*(hi+1)
        for i in range(2, hi+1):
            if not isPrime[i]: continue
            for j in range(2*i, hi+1, i):
                isPrime[j] = False
                if ufds.size[j]:
                    ufds.union(i, j)
        return max(ufds.size)


class UnionFind(object):
    def uf(self, n):
        self.uf=[i for i in range(n)]
        self.size = [1]*n
       
    def find(self, x):
        while x!=self.uf[x]:
            self.uf[x]=self.uf[self.uf[x]]
            x=self.uf[x]
        return self.uf[x]
    
    def union(self,x,y):
        x_root = self.find(x)
        y_root = self.find(y)
        if x_root == y_root:
            return
        self.uf[x_root]=y_root
        self.size[y_root]+=self.size[x_root]
        self.size[x_root]=0
        
class Solution:
    def uf(self, n):
        self.uf=[i for i in range(n)]
        self.size = [1]*n
        
    
    def largestComponentSize(self, A: List[int]) -> int:
        def primeFactors(n): 
            out=set()
            while n%2==0:
                out.add(2)
                n//=2
            for i in range(3, int(math.sqrt(n))+1,2):
                while n%i ==0:
                    out.add(i)
                    n//=i
            if n>2:
                out.add(n)
            return out
        
        idx_lookup ={A[i]: i for i in range(len(A))} # in order to find idx in uf
        uf=UnionFind()
        uf.uf(len(A))
        primeAndItsMultiples = collections.defaultdict(list) # {2: [4,6], 3: [6,15], 5: [15,35], 7:[35]}
        
        for i in A:
            factors = primeFactors(i)
            for f in factors:
                primeAndItsMultiples[f].append(i)
                
        # we don't need to connec all the multiples of a prime,
        # just use the first multiple as their root
        for idx, multiples in list(primeAndItsMultiples.items()):
            if multiples:
                root=multiples[0] # use the first multiple as their root
                for node in multiples[1:]:
                    uf.union(idx_lookup[node], idx_lookup[root]) # connect node with root
        return max(uf.size)


class UnionFind(object):
    def uf(self, n):  
        self.uf = [i for i in range(n)]
        self.size = [1] * n
        
    def find(self, x):  
        while x != self.uf[x]:
            self.uf[x] = self.uf[self.uf[x]]
            x = self.uf[x]
        return self.uf[x]

    def union(self, x, y):  
        x_root = self.find(x)
        y_root = self.find(y)
        if x_root == y_root:
            return
        self.uf[x_root] = y_root
        self.size[y_root] += self.size[x_root]
        self.size[x_root] = 0
        
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def primeFactors(n):  # Prime factor decomposition
            out = set()
            while n % 2 == 0: 
                out.add(2)
                n //= 2
            for i in range(3, int(math.sqrt(n))+1, 2): 
                while n % i== 0: 
                    out.add(i) 
                    n //= i 
            if n > 2: 
                out.add(n)
            return out
        
        idx_lookup = {A[i]: i for i in range(len(A))} # in order to find idx in uf
        uf = UnionFind()
        uf.uf(len(A))
        primeAndItsMultiples = collections.defaultdict(list) # {2: [4, 6], 3: [6, 15], 5: [15, 35], 7: [35]})
        
        for i in A:
            factors = primeFactors(i)
            for f in factors:
                primeAndItsMultiples[f].append(i)

        # we don't need to connect all the multiples of a prime, 
        # just use the first multiple as their root
        for idx, multiples in list(primeAndItsMultiples.items()):
            if multiples:
                root = multiples[0] # use the first multiple as their root
                for node in multiples[1:]:
                    uf.union(idx_lookup[node], idx_lookup[root]) # connect node with root
                    
        return max(uf.size)


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        graphs = {}

        def prime_factors(n):
            factors = set()
            # Print the number of two's that divide n
            while n % 2 == 0:
                factors.add(2)
                n = n // 2

            # n must be odd at this point
            # so a skip of 2 ( i = i + 2) can be used
            for i in range(3, int(math.sqrt(n)) + 1, 2):
                # while i divides n , print i ad divide n
                while n % i == 0:
                    factors.add(i)
                    n = n // i

                    # Condition if n is a prime
            # number greater than 2
            if n > 2:
                factors.add(n)
            return factors

        for num in A:
            facts = prime_factors(num)

            if num not in graphs:
                graphs[num] = set()
            for fact in facts:
                if fact not in graphs:
                    graphs[fact] = set()
                graphs[fact].add(num)
                graphs[num].add(fact)

        groups, n_group = {}, 0

        def dfs(factor, group_id):
            groups[factor] = group_id
            for next_factor in graphs[factor]:
                if next_factor not in groups:
                    dfs(next_factor, group_id)

        for f in graphs:
            if f not in groups:
                n_group += 1
                dfs(f, n_group)

        group_count = {}
        for num in A:
            group_id = groups[num]
            if group_id not in group_count:
                group_count[group_id] = 0
            group_count[group_id] += 1

        return max(group_count.values())


from typing import Deque, Dict, List, Set, Tuple
'''
952. Largest Component Size by Common Factor.  Hard

Given a non-empty array of unique positive integers A,
consider the following graph:

There are A.length nodes, labelled A[0] to A[A.length - 1];
There is an edge between A[i] and A[j] if and only if
A[i] and A[j] share a common factor greater than 1.
Return the size of the largest connected component in the graph.

Example 1:
Input: [4,6,15,35]
Output: 4

Example 2:
Input: [20,50,9,63]
Output: 2

Example 3:
Input: [2,3,6,7,4,12,21,39]
Output: 8

Note:
1 <= A.length <= 20000
1 <= A[i] <= 100000

Accepted 18,093 / 53,552 submissions.
'''


def gen_primes():
    '''
    Prime number generator, optimized to try only odd numbers.
    How to populate a list with some range of generated values:
        list(itertools.islice((p for p in gen_primes_opt()), beg_num, end_num)))
    '''
    yield 2                                     # return the first prime number
    prime_divs = collections.defaultdict(list)  # map numbers to their prime divisors
    candidate = 3
    while True:
        if candidate in prime_divs:
            for prime_div in prime_divs[candidate]:
                prime_divs[prime_div*2 + candidate].append(prime_div)
            del prime_divs[candidate]           # sieve no longer needed for candidate
        else:
            yield candidate                     # yield the next prime number
            prime_divs[candidate * candidate] = [candidate] # start sieve for sqaure
        candidate += 2



class Solution:

    def __init__(self):
        self.prime_gen = gen_primes()
        self.primes = [next(self.prime_gen) for _ in range(55)]


    def get_primes(self, lower_bound: int) -> List[int]:
        while self.primes[-1] < lower_bound:
            self.primes.append(next(self.prime_gen))
        return self.primes

    def prime_fac_set(self, num: int):
        pfs = set()
        for prime in self.primes:
            if num % prime == 0:
                pfs.add(prime)

            if prime >= num:
                break
        return pfs


    def largestComponentSizeWip(self, A: List[int]) -> int:
        return 0


        pcomps = collections.defaultdict(set)
        edges = collections.defaultdict(set)
        for num in A:
            pfs = self.prime_fac_set(num)
            prv = None
            for prime in pfs:
                pcomps[prime].add(num)
                if prv is None:
                    prv = prime
                else:
                    edges[prv].add(prime)
                    prv = prime
        max_size = 0
        print(edges)
        for prm, num_set in list(pcomps.items()):
            the_set = num_set
            the_prm = prm
            while the_prm in edges:
                the_set.update(edges[the_prm])
            max_size = max(max_size, len(the_set))


        return max_size



    def largestComponentSize(self, A: List[int]) -> int:
        '''
        Step 1: get primes less than sqrt(max(A))
        Step 2: compute factors for each number in A
        Step 3: use union-find to link two primes
                if they are factors of the same number in A
        Step 4: for each number in A, add to its union
                (the union represented by its smallest prime)
                
        Runtime: 1000 ms, faster than 99.35% of Python3 online submissions for Largest Component Size by Common Factor.
        Memory Usage: 19.4 MB, less than 55.56% of Python3 online submissions for Largest Component Size by Common Factor.
        '''
        # primes = []
        # for x in range(2, int(max(A)**0.5)+1):
        #     for y in primes:
        #         if x % y == 0:
        #             break
        #     else:
        #         primes.append(x)

        lowerb = int(max(A)**0.5) + 1
        primes = self.get_primes(lowerb)

        factors = collections.defaultdict(list)         # compute factors of each 'a'
        for a in A:
            x = a
            for p in primes:
                if p*p > x:
                    break
                if x % p == 0:
                    factors[a].append(p)
                    while x % p == 0:
                        x //= p
            if x > 1:                                   # a new prime found
                factors[a].append(x)
                primes.append(x)

        primes = list(set(primes))
        n = len(primes)
        p2i = {p: i for i,p in enumerate(primes)}       # prime to index

        parent = [i for i in range(n)]                  # union-find on primes

        def find(i):
            if i != parent[i]:
                parent[i] = find(parent[i])
            return parent[i]

        def union(i,j):
            pi, pj = find(i), find(j)
            if pi != pj:
                parent[pi] = pj

        for a in A:
            if factors[a]:
                p0 = factors[a][0]
                for p in factors[a][1:]:                # link two primes if they are factors of 'a'
                    union(p2i[p0], p2i[p])

        count = collections.Counter(find(p2i[factors[a][0]]) for a in A if factors[a])      # each 'a' corresponds to a prime index
        return max(count.values())


from math import sqrt, floor

class Solution:
        
    def largestComponentSize(self, A: List[int]) -> int:
        def find(i, parent):
            if parent[i] == i:
                return i
            return find(parent[i], parent)
        
        def union(i, j, parent, cnt):
            p = find(i, parent)
            q = find(j, parent)
            if p == q:
                return

            if cnt[p] < cnt[q]:
                p, q = q, p

            cnt[p] += cnt[q]
            parent[q] = p

        m = max(A)
        arr = [True] * (m + 1)
        cnt = [1] * len(A)
        parent = [*list(range(len(A)))]
        
        for i in range(2, floor(sqrt(m)) + 1):
            if arr[i]:
                k = -1
                for j in range(len(A)):
                    if A[j]%i == 0:
                        while A[j]%i == 0:
                            A[j] = floor(A[j]/i)
                        if k == -1:
                            k = j
                        else:
                            union(k, j, parent, cnt)
                for j in range(i*i, m + 1, i):
                    arr[j] = False
        A = sorted([(x, i) for i, x in enumerate(A) if x > 1])
        for i in range(1, len(A)):
            if A[i-1][0]==A[i][0]:
                union(A[i-1][1], A[i][1], parent, cnt)
        
        return max(cnt)


class Solution:
    def find(self, g,i):
        # find the group id of element i
        if i in g:   gid=g[i]
        else: gid=g[i]=i
            
        if gid!=i:
            new_gid=self.find(g,gid)
            g[i]=new_gid
        return g[i]
            
    def merge(self,g,i,j):
        # merge two groups
        gid=self.find(g,i)
        gjd=self.find(g,j)
        if gid!=gjd:
            g[gid]=gjd

    def prime_factors(self, x):
        if x==1: return [1]
        
        primes=[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 
               67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 
               139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 
               223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 
               293, 307, 311, 313, 317 ]
        
        ans={x}
        idx,p=0,primes[0]
        while p*p<=x:
            if x % p == 0:  
                ans.add(p)
                x//=p
            else:
                idx+=1
                p=primes[idx]
        if x>1: ans.add(x)
        return ans
        
    def largestComponentSize(self, A: List[int]) -> int:
        
        n=len(A)
        print(n)
        g=dict()
        
        for x in A:
            pfs=list(self.prime_factors(x))
            
            for p in pfs[1:]:
                self.merge(g, pfs[0], p)
            
        groups=[self.find(g,x) for x in A]
        ans=collections.Counter(groups).most_common(1)
        return ans[0][1]
            
        


class UnionFind:
  def __init__(self, nodes):
    self.parents = [-1]* len(nodes)
    self.map = {node: idx for idx, node in enumerate(nodes)}
    
  def find(self, node):
    
    idx = self.map[node]
    
    orig = idx
    while(self.parents[idx] >= 0):
      idx = self.parents[idx]
      
    parent, rank = idx, abs(self.parents[idx])
    while(self.parents[orig] >= 0):
      temp_parent = self.parents[orig]
      self.parents[orig] = parent
      orig = temp_parent
    return parent, rank
      
  
  def union(self, n1, n2):
    idx1, idx2 = self.map[n1], self.map[n2]
    parent1, rank1 = self.find(n1)
    parent2, rank2 = self.find(n2)
    
    if parent1 == parent2:
      return
    
    if rank1 >= rank2:
      self.parents[parent1] -= rank2
      self.parents[parent2] = parent1
    else:
      self.parents[parent2] -= rank1
      self.parents[parent1] = parent2
      
  def get_max_rank(self):
    return abs(min(self.parents))
      

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        max_num = max(A)
        primes_nodes = collections.defaultdict(set)
        
        def prime_factors(n):
          original = n
          result = set()
          while n % 2 == 0: 
                 
            n = n // 2
            result.add(2)

          # n must be odd at this point 
          # so a skip of 2 ( i = i + 2) can be used 
          for i in range(3,int(math.sqrt(n))+1,2): 

              # while i divides n , print i ad divide n 
              while n % i== 0: 
                  result.add(i)
                  n = n // i 

          # Condition if n is a prime 
          # number greater than 2 
          if n > 2: 
               result.add(n) 
              
          return result
          
        uf_obj = UnionFind(A)
        factor_first_multiple_map = {}
        for node in A:
          p_factors = prime_factors(node)
          
          for pf in p_factors:
            #if pf already a prime factor of prev encountered num, union with that num the curr num
            if pf in factor_first_multiple_map:
              uf_obj.union(node, factor_first_multiple_map[pf])
            else:
              factor_first_multiple_map[pf] = node

          
        return uf_obj.get_max_rank()
          
        


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        primes = []
        for x in range(2, int(max(A)**0.5+1)):
            #isPrime = True
            for p in primes:
                if x%p==0:
                    isPrime = False
                    break
            else:
                primes.append(x)
                
        factors = collections.defaultdict(list)
        for a in A:
            x = a
            for p in primes:
                if p*p>x:
                    break
                if x%p == 0:
                    factors[a].append(p)
                    while x%p==0:
                        x //= p
            if x>1:
                factors[a].append(x)
                primes.append(x)
        
        primes = list(set(primes))
        n = len(primes)
        p2i = {p:i for i,p in enumerate(primes)}
        
        parent = [i for i in range(n)]
        
        def find(i):
            if i!=parent[i]:
                parent[i]=find(parent[i])
            return parent[i]
        
        def union(i,j):
            pi, pj = find(i), find(j)
            if pi!=pj:
                parent[pi]=pj
        
        for a in A:
            if factors[a]:
                p0 = factors[a][0]
                for p in factors[a][1:]:
                    union(p2i[p0], p2i[p])
                    
        count = collections.Counter(find(p2i[factors[a][0]]) for a in A if factors[a])
        
        return max(count.values())


from collections import defaultdict

class UnionFind:
    def __init__(self, length):
        self.parent = list(range(length))
        self.size = [1] * length
        
    def find(self,i):
        if self.parent[i] == i:
            return i
        if self.parent[i] != i:
            return self.find(self.parent[i])

    # A utility function to do union of two subsets
    def union(self,x,y):
        x_set, y_set = self.find(x), self.find(y)
        if x_set == y_set:
            return
        self.parent[x_set] = y_set
        self.size[y_set] += self.size[x_set]
        self.size[x_set] = 0

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        # brute force is look at each node and see if we can connect it to every other node
        # after we are done connecting, we check every node and see keep track of longest path
        
        if len(A) <= 0:
            return 0
        
        '''# key: node value
        # values: list of connected components
        nodes = defaultdict(list)
        
        gcf_cache = {}
        def greatest_common_factor(a, b):
            if (a,b) in gcf_cache:
                return gcf_cache[(a,b)]
            
            if (b,a) in gcf_cache:
                return gcf_cache[(b,a)]
            
            # euclidean algo
            # Everything divides 0  
            if (a == 0): 
                return b 
            if (b == 0): 
                return a 

            # base case 
            if (a == b): 
                return a 

            # a is greater 
            if (a > b): 
                gcf = greatest_common_factor(a-b, b)
                gcf_cache[(a,b)] = gcf
                gcf_cache[(b,a)] = gcf
                return gcf
            gcf = gcd(a, b-a)
            gcf_cache[(a,b)] = gcf
            gcf_cache[(b,a)] = gcf
            return gcf
        
        def dfs(node):
            visited = set()
            stack = [(node,0)]
            max_path = -float('inf')
            while(stack):
                current_node, current_path = stack.pop()
                if current_node:
                    visited.add(current_node)
                    current_path += 1
                    max_path = max(max_path, current_path)
                    neighbors = nodes[current_node]

                    for i in range(len(neighbors)):
                        if neighbors[i] not in visited:
                            stack.append((neighbors[i], current_path))
            return max_path
        
        for i in range(len(A)):
            for j in range(i+1, len(A)):
                gcf = greatest_common_factor(A[i], A[j])
                if gcf > 1:
                    nodes[A[i]].append(A[j])
                    nodes[A[j]].append(A[i])
        
        result = 1
        for i in nodes.keys():
            path = dfs(i)
            print(path)
            result = max(result, dfs(i))
        return result'''
        
        # try union find
        # reference: https://leetcode.com/problems/largest-component-size-by-common-factor/discuss/200643/Python-1112-ms-beats-100-Union-Find-and-Prime-factor-decomposition-with-Optimization
        def primeFactors(n):
            out = set()
            while n % 2 == 0: 
                out.add(2)
                n //= 2
            for i in range(3, int(math.sqrt(n))+1, 2): 
                while n % i== 0: 
                    out.add(i) 
                    n //= i 
            if n > 2: 
                out.add(n)
            return out
        
        uf = UnionFind(len(A))
        
        primeToIndex = {} 
        for i,a in enumerate(A):
            primes = primeFactors(a)
            for p in primes:
                if p in primeToIndex:
                    uf.union(i, primeToIndex[p])
                primeToIndex[p] = i
        return max(uf.size)



class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        n=len(A)
        if n<2:
            return n
        A=set(A)
        if 1 in A:
            A.remove(1)
        if len(A)==0:
            return 1
        #A=list(A)
        #A.sort()
        
        def list_primes(m):
            p=[True]*(m+1)
            for i in range(2,m+1):
                if p[i]:
                    for j in range(2*i,m+1,i):
                        p[j]=False
            return [i for i in range(2,m+1) if p[i]]
        
        def find_prime_factors(x,prime_list,prime_set):
            if x in prime_set:
                return [x]
            prime_factors=[]
            for prime_num in prime_list:
                if prime_num*prime_num>x:
                    break
                if x%prime_num==0:
                    prime_factors.append(prime_num)
                    while x%prime_num==0:
                        x//=prime_num
            if x!=1:
                prime_factors.append(x)
            return prime_factors
        
        def prime_decompose(x):
            f=2
            prime_factors=[]
            while x>=f*f:
                if x%f==0:
                    prime_factors.append(f)
                    x//=f
                else:
                    f+=1
            prime_factors.append(x)
            return prime_factors
        #print(prime_decompose(60))
        #print(prime_decompose(5120))
        #return 0
        
        prime_list=list_primes(max(A))
        prime_set=set(prime_list)
        #print(prime_list)
        d={x:find_prime_factors(x,prime_list,prime_set) for x in A}
        #d={x:list(set(prime_decompose(x))) for x in A}
        #print([len(d[x]) for x in A])
        all_factors=set()
        for x in A:
            for f in d[x]:
                all_factors.add(f)
        #print(all_factors)
        find_dict={f:f for f in all_factors}
        sink_size={f:1 for f in all_factors}
        def find(f):
            if find_dict[f]!=f:
                find_dict[f]=find(find_dict[f])
            return find_dict[f]
        
        def union(fi,fj):
            sink_i=find(fi)
            sink_j=find(fj)
            if sink_i==sink_j:
                return
            if sink_size[sink_i]>sink_size[sink_j]:
                find_dict[sink_j]=sink_i
                sink_size[sink_i]+=sink_size[sink_j]
            else:
                find_dict[sink_i]=sink_j
                sink_size[sink_j]+=sink_size[sink_i]
        
        def union_hyperedge(hyperedge):
            for i in range(1,len(hyperedge)):
                union(hyperedge[i],hyperedge[0])
            
        def union_no_load_balance(hyperedge):
            sink=find(hyperedge[0])
            for f in hyperedge:
                find_dict[find(f)]=sink
                find(f)
            
        for x in A:
            union_hyperedge(d[x])
        #print('Union done.')
        sinks=set()
        for f in all_factors:
            sinks.add(find(f))
        
        count={sink:0 for sink in sinks}
        
        for x in A:
            count[find(d[x][0])]+=1
        
        return max(count.values())


prime, idx = [2,3], [0,1,2,3]
def ensure(n):
    n0 = len(idx)
    if n <= n0: return
    prime.extend([ x for i,x in enumerate(idx[prime[-1] + 1:], prime[-1] + 1)
                 if i == x ])
    idx.extend(range(n0, n))
    for x in prime:
        for j in range(max(x, (n0 - 1) // x + 1) * x, n, x): idx[j] = x
    for i,x in enumerate(idx[n0:], n0):
        if n <= i * i: break
        if i != x: continue
        prime.append(x)
        for j in range(x * x, n, x): idx[j] = x
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        ensure(max(A) + 1)
        best, src, dst, visited = 0, {}, {}, set()
        for x in A:
            x0, ps = x, set()
            while x != 1:
                p = idx[x]
                if p not in ps:
                    ps.add(p)
                    if p in dst: dst[p].add(x0)
                    else: dst[p] = {x0}
                x //= p
            if idx[x0] == x0: best = 1
            else: src[x0] = ps
        for p in dst:
            if p in visited: continue
            work, grp, xs = {p}, set(), set()
            while work:
                grp |= work
                old, work = work, set()
                for p in old:
                    xs |= dst[p]
                    for x in dst[p] - {p}: work |= src[x] - grp
            visited |= grp
            best = max(len(xs), best)
        return best

class DSU:
  def __init__(self):
    self.N = 0
    self.map = {}
    self.parent = []
    self.count = []
  
  def __contains__(self, obj):
    return obj in self.map
  
  def add(self, obj):
    if obj in self:
      return
    i = self.N
    self.N += 1
    self.map[obj] = i
    self.parent.append(i)
    self.count.append(0)

  def find(self, obj):
    p = self.parent
    
    origI = self.map[obj]
    
    i = origI
    while p[i] != i:
      i = p[i]
    root = i
    
    i = origI
    while p[i] != i:
        p[i], i = root, p[i]
    
    return root

  def union(self, objA, objB):
    rObjA = self.find(objA)
    rObjB = self.find(objB)
    if rObjA == rObjB:
      return
    self.count[rObjA] += self.count[rObjB]
    self.parent[rObjB] = rObjA

  def incCount(self, obj):
    rObj = self.find(obj)
    self.count[rObj] += 1
    return self.count[rObj]

class Solution:
  def largestComponentSize(self, nums) -> int:
    UF = DSU()
    max_ = 1
    for num in nums:
      if num == 1:
        continue
      pDs = self.primeDivisors(num)
      pD0 = pDs.pop()
      UF.add(pD0)
      for pD in pDs:
        UF.add(pD)
        UF.union(pD0, pD)
      count = UF.incCount(pD0)
      max_ = max(max_, count)
    return max_
    
  def primeDivisors(self, num: int):
      x = num
      
      pDs = set()
      
      if x % 2 == 0:
          pDs.add(2)
          while x % 2 == 0:
              x >>= 1
          
      if x % 3 == 0:
          pDs.add(3)
          while x % 3 == 0:
              x //= 3
      
      div = 5
      d2 = True
      while x >= div*div:
          if x % div == 0:
              pDs.add(div)
              while x % div == 0:
                  x //= div
          div += 2 if d2 else 4
          d2 = not d2
      
      if x > 1:
        pDs.add(x)
      
      return pDs


class UnionFind(object):
    def __init__(self, n, recursion = False):
        self._par = list(range(n))
        self._size = [1] * n
        self._recursion = recursion

    def root(self, k):
        if self._recursion:
            if k == self._par[k]:
                return k
            self._par[k] = self.root(self._par[k])
            return self._par[k]
        else:
            root = k
            while root != self._par[root]: root = self._par[root]
            while k != root: k, self._par[k] = self._par[k], root
            return root

    def unite(self, i, j):
        i, j = self.root(i), self.root(j)
        if i == j: return False
        if self._size[i] < self._size[j]: i, j = j, i
        self._par[j] = i
        self._size[i] += self._size[j]
        return True

    def is_connected(self, i, j):
        return self.root(i) == self.root(j)

    def size(self, k):
        return self._size[self.root(k)]

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        n = len(A)
        M = max(A)
        
        primes = []
        sieve = list(range(M + 1))
        for i in range(2, M + 1):
            if sieve[i] == i:
                primes.append(i)
            for p in primes:
                if i * p > M or sieve[i] < p:
                    break
                sieve[i * p] = p
        
        uf = UnionFind(n)
        color = [-1] * (M + 1) 
        for i, a in enumerate(A):
            while a != 1:
                p = sieve[a]
                if color[p] != -1:
                    uf.unite(i, color[p])
                else:
                    color[p] = i
                a //= p
        
        return max(uf.size(i) for i in range(n))

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        primes = []
        for x in range(2, int(max(A)**0.5+1)):
            isPrime = True
            for p in primes:
                if x%p==0:
                    isPrime = False
                    break
            if isPrime:
                primes.append(x)
                
        factors = collections.defaultdict(list)
        for a in A:
            x = a
            for p in primes:
                if p*p>x:
                    break
                if x%p == 0:
                    factors[a].append(p)
                    while x%p==0:
                        x //= p
            if x>1:
                factors[a].append(x)
                primes.append(x)
        
        primes = list(set(primes))
        n = len(primes)
        p2i = {p:i for i,p in enumerate(primes)}
        
        parent = [i for i in range(n)]
        
        def find(i):
            if i!=parent[i]:
                parent[i]=find(parent[i])
            return parent[i]
        
        def union(i,j):
            pi, pj = find(i), find(j)
            if pi!=pj:
                parent[pi]=pj
        
        for a in A:
            if factors[a]:
                p0 = factors[a][0]
                for p in factors[a][1:]:
                    union(p2i[p0], p2i[p])
                    
        count = collections.Counter(find(p2i[factors[a][0]]) for a in A if factors[a])
        
        return max(count.values())


class Solution:
    def largestComponentSize(self, nums: List[int]) -> int:
        upper_p = max(nums)
        is_prime = [1] * (upper_p + 1)
        primes = []
        for p in range(2, upper_p + 1):
            if not is_prime[p]:
                continue
            primes.append(p)
            for multi in range(2 * p, upper_p + 1, p):
                is_prime[multi] = 0
        primes_set = set(primes)
        p_par = {p: p for p in primes}
        p_cnt = {p: 0 for p in primes}
        
        def find_par(ind):
            path = []
            while p_par[ind] != ind:
                path.append(ind)
                ind = p_par[ind]
            for mid in path:
                p_par[mid] = ind
                p_cnt[ind] += p_cnt[mid]
                p_cnt[mid] = 0
            return ind
        
        def union(p1, p2):
            par1 = find_par(p1)
            par2 = find_par(p2)
            if par1 != par2:
                p_par[par2] = par1
                p_cnt[par1] += p_cnt[par2]
                p_cnt[par2] = 0
            return
        
        for num in nums:
            if num == 1:
                continue
            factors = []
            for p in primes:
                if p * p > num:
                    break
                if num % p == 0:
                    factors.append(p)
                    while num % p == 0:
                        num //= p
            if num in primes_set:
                factors.append(num)
                
            for other_p in factors[1:]:
                union(factors[0], other_p)
            p_cnt[find_par(factors[0])] += 1
                                
        return max(p_cnt.values())

# class UnionFind:
#     def __init__(self, nums):
#         self.parents = {num: num for num in nums}
#         self.ranks = {num: 1 for num in nums}
    
#     def find(self, src):
#         if self.parents[src] == src:
#             return src
        
#         self.parents[src] = self.find(self.parents[src])
#         return self.parents[src]

#     def union(self, src, dest):
#         rootSrc, rootDest = self.find(src), self.find(dest)
#         if rootSrc == rootDest:
#             return -1
        
#         if self.ranks[rootSrc] > self.ranks[rootDest]:
#             self.parents[rootDest] = rootSrc
#             self.ranks[rootSrc] += self.ranks[rootDest]
#             return self.ranks[rootSrc]
#         else:
#             self.parents[rootSrc] = rootDest
#             self.ranks[rootDest] += self.ranks[rootSrc]
#             return self.ranks[rootDest]
        
# class Solution:
#     def largestComponentSize(self, A: List[int]) -> int:
#         def gcd(num1, num2):
#             if num1 < num2:
#                 return gcd(num2, num1)
#             if num2 == 0:
#                 return num1

#             return gcd(num2, num1 % num2)

#         uf = UnionFind(A)
#         for i in range(len(A) - 1):
#             for j in range(i + 1, len(A)):
#                 if gcd(A[i], A[j]) > 1:
#                     uf.union(A[i], A[j])
#         return max(uf.ranks.values())

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        primes = []
        for x in range(2, int(max(A)**0.5)+1):
            for y in primes:
                if x % y == 0:
                    break
            else:
                primes.append(x)
    
        factors = collections.defaultdict(list)         # compute factors of each 'a'
        for a in A:
            x = a
            for p in primes:
                if p*p > x:
                    break
                if x % p == 0:
                    factors[a].append(p)
                    while x % p == 0:
                        x //= p
            if x > 1:                                   # a new prime found
                factors[a].append(x)
                primes.append(x)
                
        primes = list(set(primes))
        n = len(primes)
        p2i = {p: i for i,p in enumerate(primes)}       # prime to index
        
        parent = [i for i in range(n)]                  # union-find on primes
        
        def find(i):
            if i != parent[i]:
                parent[i] = find(parent[i])
            return parent[i]
        
        def union(i,j):
            pi, pj = find(i), find(j)
            if pi != pj:
                parent[pi] = pj

        for a in A:
            if factors[a]:
                p0 = factors[a][0]
                for p in factors[a][1:]:                # link two primes if they are factors of 'a'
                    union(p2i[p0], p2i[p])
        
        count = collections.Counter(find(p2i[factors[a][0]]) for a in A if factors[a])      # each 'a' corresponds to a prime index
        return max(count.values())

class UF:
    def __init__(self,n):
        self.p=[i for i in range(n)]
        self.s=[1]*n
        
    def find(self,x):
        if self.p[x]!=x:
            self.p[x]=self.find(self.p[x])
        return self.p[x]
    
    def unite(self,x,y): #x and y are roots
        if self.s[x]<self.s[y]:
            x,y=y,x
        self.p[y]=x
        self.s[x]+=self.s[y]
        return x

class Solution:
    M=100000
    sieve=[0]*(M+1)
    for i in range(2,M+1):
        if sieve[i]!=0:
            continue
        for j in range(1,M//i+1):
            sieve[j*i]=i
        
    def largestComponentSize(self, A: List[int]) -> int:
        n=len(A)        
        g=UF(n)
        primes=defaultdict(list)
        for i,num in enumerate(A):
            while num>1:
                q=self.sieve[num]
                primes[q].append(i)
                while num%q==0:
                    num//=q
                    
        for l in primes.values():
            root=g.find(l[0])
            for i in l[1:]:
                node=g.find(i)
                if node!=root:
                    root=g.unite(root,node)
        
        return max(g.s)

class Solution:
    def largestComponentSize(self, nums: List[int]) -> int:
        graph = defaultdict(list)
        nodes = set(nums)
        roots = set()
        m, n = len(nums), max(nums)
        primes = [True] * (n+1)
        for i in range(2, n//2+1):
            if not primes[i]:
                continue
            j = i*2
            while j <= n:
                primes[j] = False
                if j in nodes:
                    graph[i].append(j)
                    graph[j].append(i)
                    roots.add(i)
                j += i
        # print(graph)
        ans = self.traverse(graph, roots, nodes)
        # print(ans)
        return max(ans)
        
        
    def traverse(self, graph, roots, real_nodes):
        counts = []
        vztd = set()
        for node in roots:
            if node in vztd:
                continue
            cnt = 0
            vztd.add(node)
            q = [node]
            while q:
                next_q = []
                for n in q:
                    if n in real_nodes:
                        cnt += 1
                    for nab in graph[n]:
                        if nab not in vztd:
                            vztd.add(nab)
                            next_q.append(nab)
                q = next_q 
            counts.append(cnt)
        return counts

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        # discuss
        primes = []
        for x in range(2, int(max(A)**0.5)+1):
            for y in primes:
                if x % y == 0:
                    break
            else:
                primes.append(x)
    
        factors = collections.defaultdict(list)         # compute factors of each 'a'
        for a in A:
            x = a
            for p in primes:
                if p*p > x:
                    break
                if x % p == 0:
                    factors[a].append(p)
                    while x % p == 0:
                        x //= p
            if x > 1:                                   # a new prime found
                factors[a].append(x)
                primes.append(x)
                
        primes = list(set(primes))
        n = len(primes)
        p2i = {p: i for i,p in enumerate(primes)}       # prime to index
        
        parent = [i for i in range(n)]                  # union-find on primes
        
        def find(i):
            if i != parent[i]:
                parent[i] = find(parent[i])
            return parent[i]
        
        def union(i,j):
            pi, pj = find(i), find(j)
            if pi != pj:
                parent[pi] = pj

        for a in A:
            if factors[a]:
                p0 = factors[a][0]
                for p in factors[a][1:]:                # link two primes if they are factors of 'a'
                    union(p2i[p0], p2i[p])
        
        count = collections.Counter(find(p2i[factors[a][0]]) for a in A if factors[a])      # each 'a' corresponds to a prime index
        return max(count.values())

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def find(v):
            if parent[v] != v:
                parent[v] = find(parent[v])
            return parent[v]

        def union(v1, v2):
            p1 = find(v1)
            p2 = find(v2)
            if p1 not in rank:
                rank[p1] = 0
            if p2 not in rank:
                rank[p2] = 0
            if p1 != p2:
                if rank[p1] > rank[p2]:
                    parent[p2] = p1
                else:
                    parent[p1] = p2
                    if rank[p1] == rank[p2]:
                        rank[p2] += 1
                        
        def sieve(n):
            primes = [True] * (n + 1)
            p = 2
            while p * p <= n:
                if primes[p]:
                    for i in range(p * 2, n + 1, p):
                        primes[i] = False
                p += 1
            return [element for element in range(2, n) if primes[element]]

        rank = {}
        primes = sieve(max(A) // 2 + 1)
        parent = {i: i for i in A + primes}
        for num in A:
            up = int(sqrt(num))
            t = num
            for p in primes:
                if p > up:
                    break
                if num % p == 0:
                    union(num, p)
                while t % p == 0:
                    t //= p
            if t > 1:
                union(num, t)

        return max(Counter([find(n) for n in A]).values())

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        N = len(A)
        maxi = max(A)
        p = [i for i in range(N)]
        size = [1] * N
        ret = 1
        primes, isPrime = [], [True] * (maxi + 1)
        for i in range(2, maxi + 1):
            if isPrime[i]: 
                primes.append(i)
                for j in range(2, maxi // i + 1):
                    isPrime[i * j] = False
        prime2Id = {}
        def find(x):
            if p[x] != x: p[x] = find(p[x])
            return p[x]
        def union(x, y):
            nonlocal ret
            px, py = find(x), find(y)
            if px == py: return
            p[py] = px
            size[px] += size[py]
            size[py] = 0
            ret = max(ret, size[px])
            
        for i in range(N):
            a = A[i]
            for f in primes:
                if isPrime[a]:
                    if a in prime2Id: 
                        union(prime2Id[a], i)
                    prime2Id[a] = i
                    break 
                if f*f > A[i]: break
                if a % f == 0:
                    if f in prime2Id: 
                        union(prime2Id[f], i)
                    prime2Id[f] = i
                    while a % f == 0: a //= f
                if a == 1: break
        
        return ret
        


class UF(object):
    def __init__(self, n):  
        self.uf = [i for i in range(n)]
        self.size = [1] * n
        
    def find(self, x):  
        while x != self.uf[x]:
            self.uf[x] = self.uf[self.uf[x]]
            x = self.uf[x]
        return x

    def union(self, x, y):  
        xr = self.find(x)
        yr = self.find(y)
        if xr == yr:
            return
        self.uf[xr] = yr
        self.size[yr] += self.size[xr]
        self.size[xr] = 0

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def pf(n):
            F = set()
            if n % 2 == 0:
                F.add(2)
                while n % 2 == 0:
                    n //= 2
            for f in range(3,int(n**0.5)+1,2):
                if n % f == 0:
                    F.add(f)
                    while n % f == 0:
                        n //= f
            if n > 1:
                F.add(n)
            return F
        
        
        uf = UF(len(A))
        
        pd = {}
        for i,a in enumerate(A):
            F = pf(a)
            print((a, F))
            for p in F:
                if p in pd:
                    uf.union(i, pd[p])
                pd[p] = i
        
        return max(uf.size)


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        n=len(A)
        if n<2:
            return n
        A=set(A)
        if 1 in A:
            A.remove(1)
        if len(A)==0:
            return 1
        
        def list_primes(m):
            p=[True]*(m+1)
            for i in range(2,m+1):
                if p[i]:
                    for j in range(2*i,m+1,i):
                        p[j]=False
            return [i for i in range(2,m+1) if p[i]]
        
        def find_prime_factors(x,prime_list,prime_set):
            if x in prime_set:
                return [x]
            prime_factors=[]
            for prime_num in prime_list:
                if prime_num*prime_num>x:
                    break
                if x%prime_num==0:
                    prime_factors.append(prime_num)
                    while x%prime_num==0:
                        x//=prime_num
            if x!=1:
                prime_factors.append(x)
            return prime_factors
        
        prime_list=list_primes(max(A))
        prime_set=set(prime_list)
        d={x:find_prime_factors(x,prime_list,prime_set) for x in A}
        
        all_factors=set()
        for x in A:
            for f in d[x]:
                all_factors.add(f)
                
        find_dict={f:f for f in all_factors}
        sink_size={f:1 for f in all_factors}
        def find(f):
            if find_dict[f]!=f:
                find_dict[f]=find(find_dict[f])
            return find_dict[f]
        
        def union(fi,fj):
            sink_i=find(fi)
            sink_j=find(fj)
            if sink_i==sink_j:
                return
            if sink_size[sink_i]>sink_size[sink_j]:
                find_dict[sink_j]=sink_i
                sink_size[sink_i]+=sink_size[sink_j]
            else:
                find_dict[sink_i]=sink_j
                sink_size[sink_j]+=sink_size[sink_i]
        
        def union_hyperedge(hyperedge):
            for i in range(1,len(hyperedge)):
                union(hyperedge[i],hyperedge[0])
                        
        for x in A:
            union_hyperedge(d[x])
            
        sinks=set()
        for f in all_factors:
            sinks.add(find(f))
        
        count={sink:0 for sink in sinks}
        
        for x in A:
            count[find(d[x][0])]+=1
        
        return max(count.values())


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def pfactorization(a):
            N = a
            if a >= 2 and a % 2 == 0:   #treat 2 alone
                Gp[2].append(N)
                Gn[N].append(2)
                while a % 2 == 0:   a //= 2
            for d in range(3, math.floor(a**(1/2)) + 1, 2): #possible odd numbers
                if d > a:   break
                if a % d == 0:
                    Gn[N].append(d)
                    Gp[d].append(N)
                    while a % d == 0:   a //= d
            if a > 1:   #check if what remains is itself a prime
                Gp[a].append(N)
                Gn[N].append(a)
        def dfs(curr):
            if curr in seenNodes:   return 0
            seenNodes.add(curr)
            total = 1
            for p in Gn[curr]:
                if p in seenPrimes: continue
                seenPrimes.add(p)
                for owner in Gp[p]: total += dfs(owner)
            return total
        Gp = collections.defaultdict(list)
        Gn = collections.defaultdict(list)
        for a in A: pfactorization(a)   #build our graphs
        seenPrimes, seenNodes = set(), set()
        return max([dfs(a) for a in A])


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        uf = {}
        rank = {i: 1 for i in range(len(A))}
        
        def find(x):
            uf.setdefault(x, x)
            if uf[x] != x:
                uf[x] = find(uf[x])
            return uf[x]
        
        def union(x, y):
            px, py = find(x), find(y)
            if px != py:
                if rank[px] > rank[py]:
                    px, py = py, px
                rank[py] += rank[px]
                uf[px] = py
            
        def primeFactor(x):
            ans = set()
            if not x % 2:
                ans.add(2)
                while not x % 2: x //= 2
            for k in range(3, int(sqrt(x)) + 1, 2):
                if not x % k:
                    ans.add(k)
                    while not x % k: x //= k
                if x == 1: break
            if x > 1: ans.add(x)
            return ans
                
        dic = {}
        for i in range(len(A)):
            for k in primeFactor(A[i]):
                dic.setdefault(k, i)
                union(i, dic[k])
        # print(rank)
        return max(Counter([find(i) for i in range(len(A))]).values())

class UnionFind:
    def __init__(self):
        self.rblong = dict() # aRe BeLong to
        
    def find(self, n):
        if n not in self.rblong:
            self.rblong[n] = n
            return n
        
        if n == self.rblong[n]:
            return n
        
        self.rblong[n] = self.find(self.rblong[n])
        return self.rblong[n]
    
    def union(self, n1, n2):
        u1, u2 = self.find(n1), self.find(n2)
        if u1 == u2:
            return
        
        self.rblong[u1] = u2
        return
    
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        uf = UnionFind()
        prime = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313]
    
        for num in A:
            if num == 1:
                continue
            
            num2 = num
            for i in prime:
                if num2 < i:
                    break
                    
                if num2 % i == 0:
                    uf.union(num2, i)
                    num2 = num2 // i
                    if num2 > 1:
                        uf.union(num2, i)
                    while num2 % i == 0:
                        num2 = num2 // i
                        if num2 > 1:
                            uf.union(num2, i)
        
            if num2 > 1:
                uf.union(num, num2)
                            
        #print(uf.rblong)
        count = dict()
        for num in A:
            tmp = uf.find(num)
            #print('num == {}, tmp == {}'.format(num, tmp))
        
            if tmp not in count:
                count[tmp] = 1
            
            else:
                count[tmp] += 1
                            
        return max(count.values())

class UF:
    def __init__(self,n):
        self.p=[i for i in range(n)]
        self.s=[1]*n
        
    def find(self,x):
        if self.p[x]!=x:
            self.p[x]=self.find(self.p[x])
        return self.p[x]

class Solution:
    sieve=[0]*100001
    for i in range(2,100001):
        if sieve[i]!=0:
            continue
        for j in range(1,100000//i+1):
            sieve[j*i]=i
        
    def largestComponentSize(self, A: List[int]) -> int:
        # def add_prime(q,i,primes):
        #     if q not in primes:
        #         primes[q]=[i]
        #     else:
        #         primes[q].append(i)
        n=len(A)        
        g=UF(n)
        primes=defaultdict(list)
        for i,num in enumerate(A):
            while num>1:
                q=self.sieve[num]
                primes[q].append(i)
                while num%q==0:
                    num//=q
        # print(primes)
        for l in primes.values():
            j,r=l[0],g.find(l[0])
            for i in l[1:]:
                nd=g.find(i)
                if nd!=r:
                    g.p[nd]=r
                    g.s[r]+=g.s[nd]
        
        return max(g.s)

import math
from functools import lru_cache


@lru_cache(None)
def get_primes(n):
    for i in range(2, int(math.sqrt(n)) + 1):
        if n % i == 0:
            return get_primes(n // i) | set([i])
        
    return set([n])


class DSU:
    def __init__(self, n):
        self.store = list(range(n))
        
    def find(self, i):
        assert 0 <= i < len(self.store)
        
        if i != self.store[i]:
            self.store[i] = self.find(self.store[i])
            
        return self.store[i]
    
    def union(self, x, y):
        x_idx = self.find(x)
        y_idx = self.find(y)
        
        self.store[y_idx] = x_idx


class Solution:
    def largestComponentSize(self, a: List[int]) -> int:
        
        common_primes = defaultdict(list)
        for i, num in enumerate(a):
            for prime in get_primes(num):
                common_primes[prime].append(i)
                
        # print(common_primes)
        
        dsu = DSU(len(a))
        
        for idxs in list(common_primes.values()):
            for i in range(len(idxs) - 1):
                dsu.union(idxs[i], idxs[i+1])
                
        return Counter(dsu.find(i) for i in range(len(a))).most_common(1)[0][1]
                


class DisjSet:
    def __init__(self, n ):
        self.disj_set = [-1] * n
        
    def find(self, x):
        while self.disj_set[x] >= 0:
            x = self.disj_set[x]
        return x
    
    def union(self, x, y):
        i = self.find(x)
        j = self.find(y)
        if i == j:
            return
        if self.disj_set[i] < self.disj_set[j]:
            self.disj_set[i] += self.disj_set[j]
            self.disj_set[j] = i
        else:
            self.disj_set[j] += self.disj_set[i]
            self.disj_set[i] = j
    
    def maxset(self):
        return -min(self.disj_set)
    
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def factor(n):
            f = []
            while True:
                for i in range(2, int(math.sqrt(n)) + 1):
                    if n % i == 0:
                        f.append(i)
                        n //= i
                        break
                else:
                    f.append(n)
                    break
            return f
        n = len(A)
        disj = DisjSet(n)
        g = {}
        for i, a in enumerate(A):
            for f in factor(a):
                if f not in g:
                    g[f] = i
                else:
                    disj.union(i, g[f])
        return disj.maxset()

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:

        def pfactorization(a):
            N = a
            if a >= 2 and a % 2 == 0:   #treat 2 alone
                Gp[2].append(N)
                Gn[N].append(2)
                while a % 2 == 0:   a //= 2
            for d in range(3, math.floor(a**(1/2)) + 1, 2): #possible odd numbers
                if d > a:   break
                if a % d == 0:
                    Gn[N].append(d)
                    Gp[d].append(N)
                    while a % d == 0:   a //= d
            if a > 1:   #check if what remains is itself a prime
                Gp[a].append(N)
                Gn[N].append(a)
        def dfs(curr):
            if curr in seenNodes:   return 0
            seenNodes.add(curr)
            total = 1
            for p in Gn[curr]:
                if p in seenPrimes: continue
                seenPrimes.add(p)
                for owner in Gp[p]: total += dfs(owner)
            return total
        Gp = collections.defaultdict(list)
        Gn = collections.defaultdict(list)
        for a in A: pfactorization(a)   #build our graphs
        seenPrimes, seenNodes = set(), set()
        return max([dfs(a) for a in A])

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        parent, size = {x: x for x in A}, {x: 1 for x in A}
        
        def find(a):
            if parent[a] != a:
                parent[a] = find(parent[a])
            return parent[a]
        
        def union(a, b):
            if b not in parent:
                parent[b] = b
                size[b] = 0
            x, y = find(a), find(b)
            if x != y:
                if size[x] < size[y]:
                    x, y = y, x
                parent[y] = x
                size[x] += size[y]

        for x in A:
            num = x
            if not(x & 1):
                union(x, -2)
                x >>= 1
                while not(x & 1):
                    x >>= 1
            i = 3
            while i*i <= x:
                if x % i == 0:
                    union(num, -i)
                    while x % i == 0:
                        x //= i
                i += 2
            if x > 1:
                union(num, -x)
        
        return max(size.values())


from collections import defaultdict

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


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def prime_factorize(n):
            a = set()
            while n % 2 == 0:
                a.add(2)
                n //= 2
            f = 3
            while f * f <= n:
                if n % f == 0:
                    a.add(f)
                    n //= f
                else:
                    f += 2
            if n != 1:
                a.add(n)
            return a

        uf = UnionFind(len(A))
        res = 0
        primes = defaultdict(list)

        for i, a in enumerate(A):
            for p in prime_factorize(a):
                primes[p].append(i)

        for _, indices in primes.items():
            i0 = indices[0]
            for i1 in indices[1:]:
                uf.union(i0, i1)

        return -min(uf.parents)

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        uf = UnionFind(len(A))
        prime_index = {}
        for i, n in enumerate(A):
            pfs = get_prime_factors(n)
            for p in pfs:
                if p in prime_index:
                    uf.union(i, prime_index[p])
                prime_index[p] = i
        return max(uf.size)
class UnionFind:
    def __init__(self, N):
        self.uf = [i for i in range(N)]
        self.size = [1] * N
    
    def find(self, x):
        while x != self.uf[x]:
            x = self.uf[x]
        return x
    
    def union(self, x, y):
        x_root = self.find(x)
        y_root = self.find(y)

        if x_root == y_root:
            return
        
        if self.size[x_root] > self.size[y_root]:
            self.uf[y_root] = x_root
            self.size[x_root] += self.size[y_root]
            self.size[y_root] = 0
        else:
            self.uf[x_root] = y_root
            self.size[y_root] += self.size[x_root]
            self.size[x_root] = 0

def get_prime_factors(n):
    prime_factors = set()
    while n % 2 == 0:
        prime_factors.add(2)
        n //=2
    
    for d in range(3, int(math.sqrt(n))+1, 2 ):
        while n % d == 0:
            prime_factors.add(d)
            n //= d
    
    if n > 2:
        prime_factors.add(n)

    return prime_factors

class Solution:
    def primeFactors(self, n):
        pset = set()
        # While n is even, divide by two
        while n % 2 == 0:
            pset.add(2)
            n = n // 2
        
        # For every odd i between 3 and sqrt(n), check if it's a factor
        for i in range(3, int(math.sqrt(n))+1, 2):
            while n % i == 0:
                pset.add(i)
                n = n // i
        
        # If n is still greater than 2, it's a prime
        if n > 2:
            pset.add(n)
            
        return pset
    
    def largestComponentSize(self, A: List[int]) -> int:
        # Creates a disjoint set (union find) for the list A
        ds = DisjointSet(A)
        
        # Dict to keep the index of the disjoint set root for every prime divisor set found
        primeRoots = {}
        
        # Iterate over A and find it's prime divisors
        for i, a in enumerate(A):
            primes = self.primeFactors(a)
            # For every prime, set the index of a as it's root
            for p in primes:
                # If already have a set for this prime, join the current element to it
                if p in primeRoots:
                    ds.union(i, primeRoots[p])
                primeRoots[p] = i

        return max(ds.sizes)
    

class DisjointSet:
    def __init__(self, elements):
        self.parents = [x for x in range(len(elements))]
        self.sizes = [1] * len(elements)
        
    # Path splitting find algorithm.
    def find(self, x):
        while x != self.parents[x]:
                x, self.parents[x] = self.parents[x], self.parents[self.parents[x]]
        return x
        
    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        
        if px == py:
            return px
        
        if self.sizes[px] > self.sizes[py]:
            py, px = px, py
            
        self.parents[px] = py
        self.sizes[py] += self.sizes[px]

class UF:
    def __init__(self, n):
        self.f = list(range(n))
        self.cc = [1] * n
        
    def find(self, x):
        while x != self.f[x]: # while, not if
            x = self.f[x]
        return x

    def union(self, x, y):
        fx, fy = self.find(x), self.find(y)
        if fx != fy: #
            if self.cc[fx] <= self.cc[fy]: # path compression?
                self.f[fx] = fy
                self.cc[fx], self.cc[fy] = 0, self.cc[fx] + self.cc[fy]
            else:
                self.f[fy] = fx
                self.cc[fy], self.cc[fx] = 0, self.cc[fx] + self.cc[fy]
    
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        if not A:
            return 0
        n = len(A)
        uf = UF(n)
        
        '''
        def gcd(a, b):
            while b != 0:
                a, b = b, a % b
            return a
        
        for i in range(n):
            for j in range(n):
                if i == j:
                    continue
                if gcd(A[i], A[j]) > 1:
                    uf.union(i, j)
        '''
        def getPrimeSets(num, num2primes):
            if num2primes[num]:
                return num2primes[num]
            
            for i in range(2, int(math.sqrt(num)) + 1):
                if num % i == 0:
                    num2primes[num] = getPrimeSets(i, num2primes) | getPrimeSets(num // i, num2primes)
                    return num2primes[num]
                
            num2primes[num] = set([num]) # num is prime
            return num2primes[num]
            
        num2primes = collections.defaultdict(set)
        for num in sorted(A):
            getPrimeSets(num, num2primes)
        
        prime2numIdxs = collections.defaultdict(list)
        for idx, num in enumerate(A):
            ps = num2primes[num]
            for p in ps:
                prime2numIdxs[p].append(idx)
                
        for _, idxs in list(prime2numIdxs.items()):
            for i in range(len(idxs) - 1):
                uf.union(idxs[i], idxs[i+1])
            
        # print(uf.f)
        # print(uf.cc)
        res = 1
        for i in range(n):
            res = max(uf.cc[i], res)
        return res


from collections import defaultdict
from math import sqrt
class DSU(object):
    def __init__(self, n):
        self.ds = list(range(n))
    
    
    def find(self, v):
        if self.ds[v] != v:
            self.ds[v] = self.find(self.ds[v])
        return self.ds[v]

    def union(self, p1, p2):
        pp1, pp2 = self.find(p1), self.find(p2)
        self.ds[pp1] = pp2
    
class Solution(object):    
    def uniqPrime(self, n):
        l = []
        while n % 2 == 0:
            l.append(2)
            n = n//2
        
        for i in range(3, int(sqrt(n)) + 1, 2):
            while n % i == 0:
                l.append(i)
                n = n//i
        if n > 2:
            l.append(n)
        
        return list(set(l))
        
    def largestComponentSize(self, A):
        primes = defaultdict(list)
        n = len(A)
        for i in range(n):
            p = self.uniqPrime(A[i])
            for x in p:
                primes[x].append(i)
        
        #now we need to merge the disjoint sets and see which is the longest
        uf = DSU(n)
        for i in list(primes.items()):
            vals = i[1]
            for j in range(len(vals) - 1):
                uf.union(vals[j], vals[j+1])
        
        return max(Counter([uf.find(i) for i in range(n)]).values())
# class Dis_set_node:
#     def __init__(self):
#         self.parent = None
#         self.size = 1
        
# class Dis_set:
#     def __init__(self):
#         self.forest = {}
        
#     def addSet(self, node, key):
#         self.forest[key] = node
        
#     def find(self, p):
#         while self.forest[p].parent is not None:
#             self.forest[p].parent = self.forest[self.forest[p].parent].parent
#             p = self.forest[p].parent
        
#         return p
    
#     def union(self, x, y):
#         x = self.find(x)
#         y = self.find(y)
        
#         if x != y:
#             if self.forest[x].size < self.forest[y].size:
#                 x, y = y, x
            
#             self.forest[y].parent = x
#             self.forest[x].size += self.forest[y].size
            

# class Solution:
#     def largestComponentSize(self, A: List[int]) -> int:
#         prime_factors = {key:value for key, value in zip([n for n in A], [[] for _ in range(len(A))])}
        
#         up_to = max(A)
        
#         primes = set()
#         comps = set()
        
#         for i in range(2, up_to + 1):
#             if i not in comps:
#                 primes.add(i)
#                 comp = i * 2
                
#                 if i in prime_factors:
#                         prime_factors[i].append(i)
                
#                 while comp <= up_to:
#                     comps.add(comp)
                    
#                     if comp in prime_factors:
#                         prime_factors[comp].append(i)
                        
#                     comps.add(comp)
#                     comp += i 
        
#         djus = Dis_set()
        
#         for p in primes:
#             djus.addSet(Dis_set_node(), p)
            
#         for pf in prime_factors.values():
#             if not pf:
#                 continue
            
#             for p1, p2 in zip(pf, pf[1:]):
#                 djus.forest[djus.find(p1)].size += 1
#                 djus.union(p1, p2)
                
            
#         print([node.size for node in djus.forest.values()])
        
        
        
        # print(self.prime_factors)
        
#         groups = []
        
#         for n in A:
#             i = 0
#             to_merge = []
            
#             while i < len(groups):
#                 if groups[i][0] & (self.prime_factors[n]):
#                     to_merge.append(groups.pop(i))
#                 else:
#                     i += 1
                    
#             to_add = [self.prime_factors[n], 1]
            
            
#             for merge in to_merge:
#                 to_add = [merge[0] | to_add[0], merge[1] + to_add[1]]
                    
                
#             groups.append(to_add)
            

                

#         return max(groups, key=lambda x:x[1])[1]
        
        
                
#     def seive(self, up_to):
#         primes = set()
#         comps = set()
        
#         for i in range(2, up_to + 1):
#             if i not in comps:
#                 primes.add(i)
#                 comp = i * 2
                
#                 if i in self.prime_factors:
#                         self.prime_factors[i].add(i)
                
#                 while comp <= up_to:
#                     comps.add(comp)
                    
#                     if comp in self.prime_factors:
#                         self.prime_factors[comp].add(i)
                        
#                     comps.add(comp)
#                     comp += i
        
#         return primes
        


import math
from collections import defaultdict

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


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def prime_factorize(n):
            a = []
            while n % 2 == 0:
                a.append(2)
                n //= 2
            f = 3
            while f * f <= n:
                if n % f == 0:
                    a.append(f)
                    n //= f
                else:
                    f += 2
            if n != 1:
                a.append(n)
            return a

        uf = UnionFind(len(A))
        res = 0
        primes = defaultdict(list)
        
        for i, a in enumerate(A):
            for p in set(prime_factorize(a)):
                primes[p].append(i)

        for _, indices in primes.items():
            i0 = indices[0]
            for i1 in indices[1:]:
                uf.union(i0, i1)

        return -min(uf.parents)

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        n = len(A)
        cnt = dict([(num, 1) for num in A])
        par = dict([(num, num) for num in A])
 
        def find(num):
            nonlocal par
            if par[num] != num:
                par[num] = find(par[num])
            return par[num]
 
        def union(num, num2):
            root, root2 = find(num), find(num2)
            if root == root2:
                return
            if root > root2:
                root, root2 = root2, root
            par[root2] = root
            cnt[root] = cnt[root] + cnt[root2]
            cnt[root2] = 0
 
        primes = [2]
        i = 3
        maxA = max(A)
        while i*i <= 100000:
            is_prime = True
            for prime in primes:
                if i % prime == 0:
                    is_prime = False
                    break
            if is_prime:
                primes.append(i)
            i += 1
        A = sorted(A)
        prime_set = {}
        for num in A:
            prime_set[num] = set()
            tmp = num
            for prime in primes:
                can_div = False
                while tmp % prime == 0:
                    tmp /= prime
                    can_div = True
                if can_div:
                    prime_set[num].add(prime)
                if prime*prime > num:
                    break
            if tmp > 1:
                prime_set[num].add(tmp)
        prime_nums = {}
        for num in prime_set:
            for p in prime_set[num]:
                prime_nums.setdefault(p, [])
                prime_nums[p].append(num)

        for prime, nums in prime_nums.items():
            roots = set(find(num) for num in nums)
            if len(roots) <= 1: continue
            roots = sorted(list(roots))
            for root in roots[1:]:
                union(roots[0], root)
        return max(cnt.values())

class UF:
    def __init__(self, n):
        self.f = list(range(n))
        self.cc = [1] * n
        
    def find(self, x):
        while x != self.f[x]: # while, not if
            x = self.f[x]
        return x

    def union(self, x, y):
        fx, fy = self.find(x), self.find(y)
        if fx != fy: #
            if self.cc[fx] <= self.cc[fy]: # path compression?
                self.f[fx] = fy
                self.cc[fx], self.cc[fy] = 0, self.cc[fx] + self.cc[fy]
            else:
                self.f[fy] = fx
                self.cc[fy], self.cc[fx] = 0, self.cc[fx] + self.cc[fy]
    
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        if not A:
            return 0
        n = len(A)
        uf = UF(n)
        
        '''
        # TLE
        def gcd(a, b):
            while b != 0:
                a, b = b, a % b
            return a
        
        for i in range(n):
            for j in range(n):
                if i == j:
                    continue
                if gcd(A[i], A[j]) > 1:
                    uf.union(i, j)
        '''
        
        def getPrimeSets(num, num2primes):
            if num2primes[num]:
                return num2primes[num]
            
            for i in range(2, int(math.sqrt(num)) + 1):
                if num % i == 0:
                    num2primes[num] = getPrimeSets(i, num2primes) | getPrimeSets(num // i, num2primes)
                    return num2primes[num]
                
            num2primes[num] = set([num]) # num is prime
            return num2primes[num]
            
        num2primes = collections.defaultdict(set)
        for num in sorted(A):
            getPrimeSets(num, num2primes)
        
        prime2numIdxs = collections.defaultdict(list)
        for idx, num in enumerate(A):
            ps = num2primes[num]
            for p in ps:
                prime2numIdxs[p].append(idx)
                
        for _, idxs in list(prime2numIdxs.items()):
            for i in range(len(idxs) - 1):
                uf.union(idxs[i], idxs[i+1])
            
        # print(uf.f)
        # print(uf.cc)
        res = 1
        for i in range(n):
            res = max(uf.cc[i], res)
        return res


class DSU:
    def __init__(self,n):
        self.sets=list(range(n))
        self.sizes=[1]*n
    
    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x!=y:
            if self.sizes[x]<self.sizes[y]:
                x,y=y,x
            self.sets[y]=x
            self.sizes[x]+=self.sizes[y]
        
    def find(self,x):
        group = self.sets[x]
        
        while group!=self.sets[group]:
            group=self.sets[group]
        self.sets[x]=group
        return group

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        primes = []
        for x in range(2, int(max(A)**0.5)+1):
            for y in primes:
                if x % y == 0:
                    break
            else:
                primes.append(x)
    
       
        f={}
        for a in A:
            factors=[]
            _a = a
            for prime in primes:
                if prime*prime>a:
                    break
                if a%prime==0:
                    factors.append(prime)
                while a%prime==0:
                    a//=prime
            if a>1:
                factors.append(a)
                primes.append(a)
            f[_a]=factors
            
        # print(f)
        prime_lookup={p:i for i,p in enumerate(primes)}
        dsu = DSU(len(primes))
        for n,prime_factors in list(f.items()):
            if prime_factors:
                p0=prime_factors[0]
            for prime in prime_factors[1:]:
                dsu.union(prime_lookup[p0],prime_lookup[prime])
        counter = collections.Counter(dsu.find(prime_lookup[f[a][0]]) for a in A if f[a]) 
        return max(counter.values())
        
                    


import math
class UnionFind():
    def __init__(self, n):  
        self.uf = [i for i in range(n)] 
        self.size = [1] * n
         
    def find(self, x):     
        if self.uf[x] != x:
            self.uf[x] = self.find(self.uf[x])
        return self.uf[x]

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

        self.uf[x_root] = y_root
        self.size[y_root] += self.size[x_root]
        self.size[x_root] = 0
        
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        d = {}
        uf = UnionFind(len(A))
        
        for indx, num in enumerate(A):
            primes = self.primeFactors(num)
            for prime in primes:
                if prime in d:
                    uf.union(indx, d[prime])
                d[prime] = indx
        return max(uf.size)
    
    def primeFactors(self, n): 
        out = set()
        while n % 2 == 0: 
            out.add(2)
            n /= 2

        for i in range(3,int(math.sqrt(n))+1,2): 
            while n % i== 0: 
                out.add(i)
                n /= i 

        if n > 2: 
            out.add(n)
        return out


#
# @lc app=leetcode id=952 lang=python3
#
# [952] Largest Component Size by Common Factor
#

# @lc code=start
from collections import defaultdict


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        small_primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997]
        label = defaultdict(int)
       
        def findRoot(key):
            if label[key] > 0:
                label[key] = findRoot(label[key])
                return label[key]
            else:
                return key
        
        def mergeRoot(k1, k2):
            r1, r2 = findRoot(k1), findRoot(k2)  
            if r1 != r2:
                r1, r2 = min(r1, r2), max(r1, r2)
                label[r1] += label[r2]
                label[r2] = r1
            return r1

        for x in A:
            root_id = 0
            for p in small_primes:
                if p > sqrt(x) + 1:
                    break
                elif x % p == 0:
                    root_id = findRoot(p) if root_id == 0 else mergeRoot(root_id, p)
                    while x % p == 0:
                        x //= p
            if x != 1:
                root_id = findRoot(x) if root_id == 0 else mergeRoot(root_id, x)
            label[root_id] -= 1
        
        return -min(label.values())
# @lc code=end


class DSU:
  def __init__(self):
    self.N = 0
    self.map = {}
    self.parent = []
    self.count = []
  
  def __contains__(self, obj):
    return obj in self.map
  
  def add(self, obj):
    if obj in self:
      return
    i = self.N
    self.N += 1
    self.map[obj] = i
    self.parent.append(i)
    self.count.append(0)

  def find(self, obj):
    p = self.parent
    
    origI = self.map[obj]
    
    i = origI
    while p[i] != i:
      i = p[i]
    root = i
    
    i = origI
    while p[i] != i:
        p[i], i = root, p[i]
    
    return root

  def union(self, objA, objB):
    rObjA = self.find(objA)
    rObjB = self.find(objB)
    if rObjA == rObjB:
      return
    self.count[rObjA] += self.count[rObjB]
    self.parent[rObjB] = rObjA

  def incCount(self, obj):
    rObj = self.find(obj)
    self.count[rObj] += 1
    return self.count[rObj]

class Solution:
  def largestComponentSize(self, nums) -> int:
    UF = DSU()
    max_ = 1
    for num in nums:
      if num == 1:
        continue
      pDs = self.primeDivisors(num)
      pD0 = pDs[0]
      UF.add(pD0)
      for pD in pDs:
        UF.add(pD)
        UF.union(pD0, pD)
      count = UF.incCount(pD0)
      max_ = max(max_, count)
    return max_
    
  def primeDivisors(self, num: int):
      x = num
      
      pDs = []
      
      if x % 2 == 0:
          pDs.append(2)
          while x % 2 == 0:
              x >>= 1
          
      if x % 3 == 0:
          pDs.append(3)
          while x % 3 == 0:
              x //= 3
      
      div = 5
      d2 = True
      while x >= div*div:
          if x % div == 0:
              pDs.append(div)
              while x % div == 0:
                  x //= div
          div += 2 if d2 else 4
          d2 = not d2
      
      if x > 1:
        pDs.append(x)
      
      return pDs


class Solution:
    def primeFactors(self, n):
        pset = set()
        # While n is even, divide by two
        while n % 2 == 0:
            pset.add(2)
            n = n // 2
        
        # For every odd i between 3 and sqrt(n), check if it's a factor
        for i in range(3, int(math.sqrt(n))+1, 2):
            while n % i == 0:
                pset.add(i)
                n = n // i
        
        # If n is still greater than 2, it's a prime
        if n > 2:
            pset.add(n)
            
        return pset
    
    def largestComponentSize(self, A: List[int]) -> int:
        # Creates a disjoint set (union find) for the list A
        ds = DisjointSet(A)
        
        # Dict to keep the index of the disjoint set root for every prime divisor set found
        primeRoots = {}
        
        # Iterate over A and find it's prime divisors
        for i, a in enumerate(A):
            primes = self.primeFactors(a)
            # For every prime, set the index of a as it's root
            for p in primes:
                # If already have a set for this prime, join the current element to it
                if p in primeRoots:
                    ds.union(i, primeRoots[p])
                else:
                    primeRoots[p] = i

        return max(ds.sizes)
    

class DisjointSet:
    def __init__(self, elements):
        self.parents = [x for x in range(len(elements))]
        self.sizes = [1] * len(elements)
        
    # Path splitting find algorithm.
    def find(self, x):
        while x != self.parents[x]:
                x, self.parents[x] = self.parents[x], self.parents[self.parents[x]]
        return x
        
    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        
        if px == py:
            return px
        
        if self.sizes[px] > self.sizes[py]:
            py, px = px, py
            
        self.parents[px] = py
        self.sizes[py] += self.sizes[px]

class UnionFind:
    def __init__(self,A):
        self._arr = {v:-1 for v in A}
    
    def union(self,u,v):
        p1 = self.find(u)
        p2 = self.find(v)
        
        if p1 != p2:
            self._arr[p1] = p2
            return True
        return False
    def find(self,u):
        if self._arr.get(u,-1) == -1:
            return u
        self._arr[u] = self.find(self._arr[u])
        return self._arr[u]
    
class Solution:
    def factorsOf(self,n):
        factors = set()
        
        while n % 2 == 0:
            factors.add(2)
            n = n//2
        
        for i in range(3,int(sqrt(n))+1,2):
            while n % i == 0:
                factors.add(i)
                n = n // i
        
        if n > 2:
            factors.add(n)
            
        return factors
            
            
        
    def largestComponentSize(self, A: List[int]) -> int:
        dsu = UnionFind(A)
        
        for n in A:
            for factor in self.factorsOf(n):
                dsu.union(n,factor)
        
        cnt_map = collections.Counter()
        ans = 0
        
        for v in A:
            p = dsu.find(v)
            cnt_map[p]+=1
            ans = max(cnt_map[p],ans)
            
        return ans
                


class UF:
    def __init__(self,n):
        self.p=[i for i in range(n)]
        self.s=[1]*n
        
    def find(self,x):
        if self.p[x]!=x:
            self.p[x]=self.find(self.p[x])
        return self.p[x]

class Solution:
    sieve=[0]*100001
    for i in range(2,100001):
        if sieve[i]!=0:
            continue
        for j in range(1,100000//i+1):
            sieve[j*i]=i
        
    def largestComponentSize(self, A: List[int]) -> int:
        def add_prime(q,i,primes):
            if q not in primes:
                primes[q]=[i]
            else:
                primes[q].append(i)
        n=len(A)        
        g=UF(n)
        primes={}
        for i,k in enumerate(A):
            while k>1:
                q=self.sieve[k]
                add_prime(q,i,primes)
                while k%q==0:
                    k//=q
        # print(primes)
        for l in primes.values():
            j,r=l[0],g.find(l[0])
            for i in l[1:]:
                nd=g.find(i)
                if nd!=r:
                    g.p[nd]=r
                    g.s[r]+=g.s[nd]
        # print(g.p)
        # print(g.s)
        return max(g.s)

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        primes = []
        for x in range(2, int(max(A)**0.5)+1):
            for y in primes:
                if x % y == 0:
                    break
            else:
                primes.append(x)
    
        factors = collections.defaultdict(list)         # compute factors of each 'a'
        for a in A:
            x = a
            for p in primes:
                if p*p > x:
                    break
                if x % p == 0:
                    factors[a].append(p)
                    while x % p == 0:
                        x //= p
            if x > 1:                                   # a new prime found
                factors[a].append(x)
                primes.append(x)
                
        primes = list(set(primes))
        n = len(primes)
        p2i = {p: i for i,p in enumerate(primes)}       # prime to index
        
        parent = [i for i in range(n)]                  # union-find on primes
        
        def find(i):
            if i != parent[i]:
                parent[i] = find(parent[i])
            return parent[i]
        
        def union(i,j):
            pi, pj = find(i), find(j)
            if pi != pj:
                parent[pi] = pj

        for a in A:
            if factors[a]:
                p0 = factors[a][0]
                for p in factors[a][1:]:                # link two primes if they are factors of 'a'
                    union(p2i[p0], p2i[p])
        
        count = collections.Counter(find(p2i[factors[a][0]]) for a in A if factors[a])      # each 'a' corresponds to a prime index
        return max(count.values())


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        primes = []
        for x in range(2, int(max(A)**0.5)+1):
            for y in primes:
                if x % y == 0:
                    break
            else:
                primes.append(x)
    
        factors = collections.defaultdict(list)         # compute factors of each 'a'
        for a in A:
            x = a
            for p in primes:
                if p*p > x:
                    break
                if x % p == 0:
                    factors[a].append(p)
                    while x % p == 0:
                        x //= p
            if x > 1:                                   # a new prime found
                factors[a].append(x)
                primes.append(x)
                
        primes = list(set(primes))
        n = len(primes)
        p2i = {p: i for i,p in enumerate(primes)}       # prime to index
        
        parent = [i for i in range(n)]                  # union-find on primes
        
        def find(i):
            if i != parent[i]:
                parent[i] = find(parent[i])
            return parent[i]
        
        def union(i,j):
            pi, pj = find(i), find(j)
            if pi != pj:
                parent[pi] = pj

        for a in A:
            if factors[a]:
                p0 = factors[a][0]
                for p in factors[a][1:]:                # link two primes if they are factors of 'a'
                    union(p2i[p0], p2i[p])
        
        count = collections.Counter(find(p2i[factors[a][0]]) for a in A if factors[a])      # each 'a' corresponds to a prime index
        return max(count.values())
    #https://leetcode.com/problems/largest-component-size-by-common-factor/discuss/581394/Python-1032ms-beat-100-time-and-space


mxn=10**5 +5
pri=[1]*(mxn)
for i in range(2,mxn):
    if pri[i]==1:
        pri[i]=i
        j=2
        while(i*j<mxn):
            if pri[i*j]==1:
                pri[i*j]=i
            j+=1

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        dct=[0]*mxn
        res=0
        def root(i):
            while(i!=arr[i]):
                i=arr[i]
                arr[i]=arr[arr[i]]
            return i
        def update(i,j):
            r1=root(i)
            r2=root(j)
            arr[r1]=r2
            size[r2]+=size[r1]
        for num in A:
            dct[pri[num]]+=1
        
        arr=[i for i in range(mxn)]
        size=[dct[i] for i in range(mxn)]
        
        for num in A:
            ls=[]
            while(num!=1):
                ls.append(pri[num])
                num=num//pri[num]
            if len(ls)==1:continue
            for i in range(1,len(ls)):
                if root(ls[0])!=root(ls[i]):
                    update(ls[0],ls[i])
    
                    
            
        return max(size)


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def find(v):
            if parent[v] != v:
                parent[v] = find(parent[v])
            return parent[v]
        
        def union(v1, v2):
            p1 = find(v1)
            p2 = find(v2)
            if p1 not in rank:
                rank[p1] = 0
            if p2 not in rank:
                rank[p2] = 0
            if p1 != p2:
                if rank[p1] > rank[p2]:
                    parent[p2] = p1
                else:
                    parent[p1] = p2
                    if rank[p1] == rank[p2]:
                        rank[p2] += 1
        def sieve(n):
            primes = [True] * (n + 1)
            p = 2
            while p * p <= n:
                if primes[p]:
                    for i in range(p * 2, n + 1, p):
                        primes[i] = False
                p += 1
            return [element for element in range(2, n) if primes[element]]
        
        rank = {}
        primes = sieve(max(A) // 2 + 1)
        parent = {i: i for i in A + primes}
        for num in A:
            up = int(sqrt(num))
            t = num
            for p in primes:
                if p > up:
                    break
                if num % p == 0:
                    union(num, p)
                while t % p == 0:
                    t //= p
            if t > 1:
                union(num, t)
        return max(Counter([find(n) for n in A]).values())

class DS:
    def __init__(self, n):
        self.par = list(range(n))
        
    def find(self, x):
        if self.par[x] != x:
            self.par[x] = self.find(self.par[x])
        return self.par[x]
    
    def union(self, x, y):
        self.par[self.find(x)] = self.find(y)

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        @lru_cache(None)
        def find_prime_factors(num):
            if num == 1:
                return []
            
            if num <= 3:
                return [num]
            
            for prime in range(2, int(sqrt(num))+1):
                if num % prime == 0:
                    break
            else:
                prime = num
                    
            while num % prime == 0:
                num //= prime
            return [prime] + find_prime_factors(num)
        
        s = {}
        for i,num in enumerate(A):
            if num == 1:
                continue
            primes = find_prime_factors(num)
            for prime in primes:
                if prime not in s:
                    s[prime] = []
                s[prime] += [i]

        ds = DS(len(A))
        for prime in s:
            for i in range(len(s[prime])-1):
                ds.union(s[prime][i], s[prime][i+1])
            
        counter = Counter([ds.find(i) for i in range(len(A))])
        return max(counter.values() or [1])

class node:
    def __init__(self,val):
        self.val=val
        self.next=[]
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        # l=[node(i) for i in A]
        # for i in range(len(l)):
        #     for j in range(len(l)):
        #         if math.gcd(l[i].val,l[j].val)>1 and i!=j:
        #             l[j].next.append(i)
        # # for i in range(len(l)):
        # #     print(l[i].next)
        # # print(l)
        # # def bfs(n,m):
        # #     nonlocal l,vis
        # #     # print(n,m,vis)
        # #     vis[n]=True
        # #     m+=1
        # #     # k=m
        # #     for i in l[n].next:
        # #         if not vis[i]:
        # #             m=dfs(i,m)
        # #     return m
        # def bfs(n):
        #     nonlocal l,vis
        #     q=[n]
        #     # vis[n]=True
        #     m=0
        #     while q:
        #         # print(q,vis)
        #         k=[]
        #         for i in q:
        #             if not vis[i]:
        #                 vis[i]=True
        #                 k.extend(l[i].next)
        #                 m+=1
        #         q=k
        #     return m
        # mi=0
        # vis=[False for i in range(len(l))]
        # for i in range(len(l)):
        #     if not vis[i]:
        #         mi=max(mi,bfs(i))
        # return mi
        p=[2]
        for i in range(3,int(max(A)**0.5)+1,2):
            for y in p:
                if i%y==0:
                    break
            else:
                p.append(i)
        f=collections.defaultdict(list)
        for a in A:
            x=a
            for pp in p:
                if pp**2>x:
                    break
                if x%pp==0:
                    f[a].append(pp)
                    while x%pp==0:
                        x=x//pp
            if x>1:
                f[a].append(x)
                p.append(x)
        # print(p,f)
        p=list(set(p))
        n=len(p)
        p2i={pp:i for i,pp in enumerate(p)}
        par=[i for i in range(n)]
        def find(i):
            if i!=par[i]:
                par[i]=find(par[i])
            return par[i]
        def union(i,j):
            pi,pj=find(i),find(j)
            if pi!=pj:
                par[pi]=pj
        for a in A:
            if f[a]:
                p0=f[a][0]
                for pp in f[a][1:]:
                    union(p2i[p0],p2i[pp])
        # l=[find(p2i[f[a][0]]) for a in A]
        c=collections.Counter(find(p2i[f[a][0]]) for a in A if f[a])
        return max(c.values())
        
        
        
        
        
        
        
        
        
        
        


class DSU:
    def __init__(self, N):
        self.p = list(range(N))

    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr

class Solution:
    def primes_set(self,n):
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self.primes_set(n//i) | set([i])
        return set([n])

    def largestComponentSize(self, A):
        n = len(A)
        UF = DSU(n)
        primes = defaultdict(list)
        for i, num in enumerate(A):
            pr_set = self.primes_set(num)
            for q in pr_set: primes[q].append(i)

        for _, indexes in primes.items():
            for i in range(len(indexes)-1):
                UF.union(indexes[i], indexes[i+1])

        return max(Counter([UF.find(i) for i in range(n)]).values())

class UFS:
    def __init__(self, N):
        self._parent = list(range(N))

    def find(self, x):
        if self._parent[x] != x:
            self._parent[x] = self.find(self._parent[x])
        return self._parent[x]

    def union(self, x, y):
        xroot, yroot = self.find(x), self.find(y)
        if xroot != yroot:
            self._parent[xroot] = yroot
        
        
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        # from time import time
        # start_time = time()
        
        
        def primeFactors(k):  # Prime factor decomposition
            out = set()
            while k % 2 == 0: 
                out.add(2)
                k //= 2
            for i in range(3, int(math.sqrt(k))+1, 2): 
                while k % i== 0: 
                    out.add(i) 
                    k //= i 
            if k > 2: 
                out.add(k)
            return out
        
        
        n = len(A)
        maxa = max(A)
        # print(f\"{maxa=}, {len(A)=}\")
            
        ufs = UFS(maxa+1)
        
        for cur in A:
            factors = primeFactors(cur)
            # print(f\"{cur=}, {factors=}\")

            for f in factors:
                ufs.union(f, cur)
                
        # union_time = time() - start_time
        # print(f\"{union_time=}\")
        
        count = [0] * (maxa+1)
        for cur in A:
            count[ufs.find(cur)] += 1
        
        return max(count)

class Primes:
    def __init__(self, N):
        self.N = N
        self.primes = [0]*(N+1)
        self.get_primes()
    
    def get_primes(self):
        for i in range(2, self.N+1):
            if self.primes[i]==0:
                self.primes[i] = i
                upto = self.N//i
                for j in range(2, upto+1):
                    if self.primes[i*j] == 0:
                        self.primes[i*j] = i
    
    def __call__(self, n):
        # num = n
        if n<=2:
            return {n}
        p = []
        while n>=2:
            lp = self.primes[n]
            p.append(lp)
            n =  n//lp
        # print(num,\":\", p)
        return set(p)

class DisjointSet:
    def __init__(self, primes):
        self.primes = primes
        self.count = 1
        
    def union(self, setB):
        # print(\"org:\", self.primes)
        # print(\"union with:\", setB.primes)
        self.primes |= setB.primes
        self.count += setB.count
        # print(\"after union:\", self.primes)
        
        
    
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        disjoint_sets = []
        Factors = Primes(max(A))
        rank = [1]*(len(A)+1)
        parent = [-1]*(len(A)+1)
        m = dict()
        curr_count = 0
        
        def get_parent(x):
            if parent[x]==-1: return x
            parent[x] = get_parent(parent[x])
            # print(f\"parent of {x} is {parent[x]}\")
            return parent[x]
        
        def union(x, y):
            parx = get_parent(x)
            pary = get_parent(y)
            if parx==pary: return
            if rank[parx]>=rank[pary]:
                rank[parx] += rank[pary]
                parent[pary] = parx
            else:
                rank[pary] += rank[parx]
                parent[parx] = pary
            # print(x,\":\",\"parent\", paar)
        
            
        for i,val in enumerate(A):
            # union = []
            val_primes = Factors(val)
            # for i, ds in enumerate(disjoint_sets):
            #     diff_set = val_primes - ds.primes
            #     if len(diff_set) < len(val_primes):
            #         union.append(i)
            #         val_primes = diff_set
            # # if len(val_primes)>0:
            # #     new_set = DisjointSet(val_primes)
            # #     disjoint_sets.append(new_set)
            # #     union.append(-1)
            # temp_set = DisjointSet(val_primes)
            # for ds in union:
            #     temp_set.union(disjoint_sets[ds])
            #     # disjoint_sets[union[-1]].union(disjoint_sets[ds])
            #     # curr_count = max(curr_count, disjoint_sets[union[-1]].count)
            # for ds in reversed(union):
            #     disjoint_sets.pop(ds)
            # disjoint_sets.append(temp_set)
            
            for prime in val_primes:
                if prime in m:
                    union(m[prime],i)
                else:
                    m[prime]=i
                    # print(prime, \":\", i)
        curr_count = max(rank)
        return curr_count
                
                


class UF:
    def __init__(self,n):
        self.p=[i for i in range(n)]  # parent array
        self.s=[1]*n  # size array
        
    def find(self,x): # find the representative/root of x
        if self.p[x]!=x:
            self.p[x]=self.find(self.p[x])
        return self.p[x]
    
    def union(self,x,y):
        xr,yr=self.find(x),self.find(y)
        if xr!=yr:
            if self.s[x]<self.s[y]:
                xr,yr=yr,xr
            self.p[yr]=xr
            self.s[xr]+=self.s[yr]

class Solution:
    M=100000
    sieve=[0]*(M+1) # stores the largest prime divisor of integers up to M
    for i in range(2,M+1):
        if sieve[i]!=0:
            continue
        for j in range(1,M//i+1):
            sieve[j*i]=i
        
    def largestComponentSize(self, A: List[int]) -> int:   
        g=UF(len(A))
        primes=defaultdict(list) # {q:[nums]} list of integers that's divisible by prime q
        for i,num in enumerate(A):
            while num>1:
                q=self.sieve[num]
                primes[q].append(i) # add the ith element to be divisible by q
                while num%q==0:
                    num//=q
                    
        for l in primes.values():
            x=l[0]
            for y in l[1:]: 
                g.union(x,y)
        
        return max(g.s)

from typing import List, Set, Tuple

def prime_factors(n: int) -> Set[int]:
    f = set()
    i = 1
    while n % 2 == 0 and n:
        f.add(2)
        n //= 2
    while n % 3 == 0 and n:
        f.add(3)
        n //= 3
    root = int(n ** 0.5) + 1
    while True and n:
        a, b = 6 * i + 1, 6 * i - 1
        while n % a == 0:
            n //= a
            f.add(a)
        while n % b == 0:
            n //= b
            f.add(b)
        if a > root:
            break
        i += 1
    if n > 1:
        f.add(n)
    return f

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        A.sort(reverse=True)
        islands: List[Tuple[Set[int], int]] = []
        primes: Set[int] = set()
        for n in A:
            factors = prime_factors(n)
            first_merged = None
            to_delete: Set[int] = set()
            for i, (g, v) in enumerate(islands):
                if factors.isdisjoint(g):
                    continue
                if first_merged is None:
                    g.update(factors)
                    islands[i] = (g, v + 1)
                    first_merged = i
                else:
                    gf, vf = islands[first_merged]
                    gf.update(g)
                    islands[first_merged] = (gf, vf + v)
                    to_delete.add(i)
            primes_inside = factors & primes
            if primes_inside:
                if first_merged is None:
                    new_v = len(primes_inside) + 1
                    islands.append((factors, new_v))
                else:
                    gf, vf = islands[first_merged]
                    islands[first_merged] = (gf, vf + len(primes_inside))
                primes.difference_update(primes_inside)
            elif first_merged is None:
                if n in factors:
                    primes.add(n)
                else:
                    islands.append((factors, 1))
            islands = [g for i, g in enumerate(islands) if i not in to_delete]
        return max(v for g, v in islands)
            
            
            
        


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        max_p = int(2 + max(A) ** 0.5)
        primes = [2,3,5,7,11,13,17,19]
        
        for num in range(20, max_p):
            for p in primes:
                if p * p > num:
                    primes.append(num)
                    break
                if num % p == 0:
                    break
        
        
        prime_factors = collections.defaultdict(list)
        members = collections.defaultdict(list)
        
        for num in A:
            num0 = num 
            for prime in primes:
                if prime ** 2 > num:
                    if num > 1:
                        prime_factors[num0].append(num)
                        members[num].append(num0)
                    break
                if num % prime == 0:
                    prime_factors[num0].append(prime)
                    members[prime].append(num0)
                while num % prime == 0:
                    num //= prime
        
        # bipartite graph
        # print(prime_factors)
        # print(members)
         
        visited_primes = set()
        ans = 0
        for p in members.keys():
            if p in visited_primes:
                continue
            visited_members = set()
            
            q_prime = collections.deque([p])
            
            while q_prime:
                pp = q_prime.popleft()
                
                for m in members[pp]:
                    
                    if m in visited_members:
                        continue
                    visited_members.add(m)
                    
                    for ppp in prime_factors[m]:
                        
                        if ppp in visited_primes:
                            continue
                        visited_primes.add(ppp)
                        
                        q_prime.append(ppp)
                     
            
            ans = max(ans, len(visited_members))
        return ans

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def find(n):
            if n not in root:
                return n
            root[n] = find(root[n])
            return root[n]
        
        def union(n1, n2):
            root1, root2 = find(n1), find(n2)
            if root1 == root2:
                return
            rank1, rank2 = rank[root1], rank[root2]
            if rank1 > rank2:
                root[root2] = root1
                size[root1] += size[root2]
            elif rank1 < rank2:
                root[root1] = root2
                size[root2] += size[root1]
            else:
                root[root1] = root2
                size[root2] += size[root1]
                rank[root2] += 1
                
        def find_prime_factors(n):
            factors = set()
            while n % 2 == 0:
                factors.add(2)
                n //= 2
            for i in range(3, int(math.sqrt(n))+1, 2):
                while n % i == 0:
                    factors.add(i)
                    n //= i
            if n > 2:
                factors.add(n)
            return factors
        
        factor_to_num = collections.defaultdict(list)
        for n in A:
            for factor in find_prime_factors(n):
                factor_to_num[factor].append(n)
        
        root = {}
        rank = {n: 1 for n in A}
        size = {n: 1 for n in A}
        
        for factor in factor_to_num:
            first_root = find(factor_to_num[factor][0])
            for i in range(1, len(factor_to_num[factor])):
                union(first_root, factor_to_num[factor][i])

        return max(size.values())
        


class UnionFind(object):
    def uf(self, n):  
        self.uf = [i for i in range(n)]
        self.size = [1] * n
        
    def find(self, x):  
        while x != self.uf[x]:
            self.uf[x] = self.uf[self.uf[x]]
            x = self.uf[x]
        return self.uf[x]

    def union(self, x, y):  
        x_root = self.find(x)
        y_root = self.find(y)
        if x_root == y_root:
            return
        self.uf[x_root] = y_root
        self.size[y_root] += self.size[x_root]
        self.size[x_root] = 0

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def primeFactors(n):  # Prime factor decomposition
            out = set()
            while n % 2 == 0: 
                out.add(2)
                n //= 2
            for i in range(3, int(math.sqrt(n))+1, 2): 
                while n % i== 0: 
                    out.add(i) 
                    n //= i 
            if n > 2: 
                out.add(n)
            return out
        
        uf = UnionFind()
        uf.uf(len(A))
        
        primeToIndex = {} 
        for i,a in enumerate(A):
            primes = primeFactors(a)
            for p in primes:
                if p in primeToIndex:
                    uf.union(i, primeToIndex[p])
                primeToIndex[p] = i
        return max(uf.size)

class DSU:
    def __init__(self,n):
        self.parent = [i for i in range(n)]
        self.rank = [1 for i in range(n)]
    
    def find(self,x):
        if x!=self.parent[x]:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def union(self,x,y):
        px = self.find(x)
        py = self.find(y)
        if px == py:
            return
        if self.rank[px] > self.rank[py]:
            self.parent[py] = px
            self.rank[px]+=self.rank[py]
        else:
            self.parent[px] = py
            self.rank[py]+=self.rank[px]
            
            
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        n = len(A)
        dsu = DSU(n)
        
        primes = defaultdict(list)
        for i, num in enumerate(A):
            pr_set = self.primes_set(num)
            for q in pr_set: 
                primes[q].append(i)
        for _, indexes in list(primes.items()):
            for i in range(len(indexes)-1):
                dsu.union(indexes[i], indexes[i+1])

        
        # for i in range(n):
        #     for j in range(i+1,n):
        #         if A[i]!=A[j] and self.gcd(A[i],A[j]) > 1:
        #             dsu.union(i,j)
        return max(dsu.rank)
    
    def primes_set(self,n):
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self.primes_set(n//i) | set([i])
        return set([n])
    def gcd(self,x,y):
        return gcd(y,x%y) if y!=0 else 0
                
                
        
        


class UnionFind:
    def __init__(self, num: int):
        self.parents = [i for i in range(num)]
        self.size = [1] * num
        self.max = 1
    
    def find(self, number: int) -> int:
        if self.parents[number] != number:
            self.parents[number] = self.find(self.parents[number])
        return self.parents[number]
    
    def merge(self, x: int, other: int):
        parentX = self.find(x)
        parentOther = self.find(other)
        
        if parentX != parentOther:
            size_x, size_y = self.parents[parentX], self.parents[parentOther]

            self.parents[parentX] = parentOther
            self.size[parentOther] += self.size[parentX]

            if self.size[parentOther] > self.max:
                self.max = self.size[parentOther]
            

class Solution:
    def primesBefore(self, value: int) -> List[int]:
        candidates = [True] * (value + 1)
        primeList = []
        
        for i in range(2, value + 1):
            if not candidates[i]:
                continue
            primeList.append(i)
            for j in range(i, value + 1, i):
                candidates[j] = False
        
        return primeList
        
    def largestComponentSize(self, A: List[int]) -> int:
        union_find = UnionFind(len(A))
        cache = {}
        primes = self.primesBefore(max(A))
        primeset = set(primes)
        
        for index, value in enumerate(A):
            svalue = value
            primeIndex = 0
            
            while svalue not in primeset and primes[primeIndex] <= svalue:
                j = primes[primeIndex]
                if svalue % j != 0:
                    primeIndex += 1
                    continue

                if j not in cache:
                    cache[j] = index
                else:
                    union_find.merge(index, cache[j])
                if value // j not in cache:
                    cache[value // j] = index
                else:
                    union_find.merge(index, cache[value // j])
                
                while svalue % j == 0:
                    svalue //= j
                primeIndex += 1
            
            if svalue == 1:
                continue
            if svalue not in cache:
                cache[svalue] = index
            else:
                union_find.merge(index, cache[svalue])
        
        return union_find.max
        
        
        


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        if not A:
            return 0
        n = len(A)
        index = list(range(n))
        size = [1]*n
        
        def find(i):
            while index[i] != i:
                i = index[i]
            return i
        
        def setPrimes(i):
            for j in range(2, int(math.sqrt(i))+1):
                if i % j == 0:
                    return setPrimes(i // j) | set([j])
            return set([i])
        
        primes = defaultdict(list)
        for i in range(n):
            s = setPrimes(A[i])
            for prime in s:
                primes[prime].append(i)
        
        for _, indices in primes.items():
            for i in range(len(indices)-1):
                k, l = find(indices[i]), find(indices[i+1])
                if k == l:
                    continue
                if size[l] > size[k]:
                    k, l = l, k
                index[l] = k
                size[k] += size[l]
        return max(size)
        
    
    
        
        
        '''
        n = len(A)
        A.sort()
        adj = [[] for _ in range(n)]
        for i in range(n-1):
            for j in range(i+1,n):
                a, b = A[i], A[j]
                while b:
                    a, b = b, a%b
                if a > 1:
                    adj[i].append(j)
                    adj[j].append(i)
                    
        visited = [False]*n
        connected = [False]*n
        
        def dfs(i):
            if visited[i]:
                return 0
            visited[i] = True
            connected[i] = True
            s = 1
            for j in adj[i]:
                s += dfs(j)
            return s
        
        M = 0
        for i in range(n):
            if not connected[i]:
                M = max(M, dfs(i))
        return M
        '''

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def pfactorization(a):
            N = a
            if a >= 2 and a % 2 == 0:
                Gp[2].append(N)
                Gn[N].append(2)
                while a % 2 == 0:
                    a //= 2
            for d in range(3, math.floor(a**(1/2)) + 1, 2):
                if a % d == 0:
                    Gn[N].append(d)
                    Gp[d].append(N)
                    while a % d == 0:   a //= d
            if a > 1:
                Gp[a].append(N)
                Gn[N].append(a)
        def dfs(curr):
            if curr in seenNodes:   return 0
            seenNodes.add(curr)
            total = 1
            for p in Gn[curr]:
                if p in seenPrimes: continue
                seenPrimes.add(p)
                for owner in Gp[p]: total += dfs(owner)
            return total
        Gp = collections.defaultdict(list)
        Gn = collections.defaultdict(list)
        for a in A: pfactorization(a)   #build our graphs
        seenPrimes, seenNodes = set(), set()
        return max([dfs(a) for a in A])

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def pfactorization(a):
            N = a
            if a >= 2 and a % 2 == 0:   #treat 2 alone
                Gp[2].append(N)
                Gn[N].append(2)
                while a % 2 == 0:   a //= 2
            for d in range(3, math.floor(a**(1/2)) + 1, 2): #possible odd numbers
                if d > a:   break
                if a % d == 0:
                    Gn[N].append(d)
                    Gp[d].append(N)
                    while a % d == 0:   a //= d
            if a > 1:   #check if what remains is itself a prime
                Gp[a].append(N)
                Gn[N].append(a)
        def dfs(curr):
            if curr in seenNodes:   return 0
            seenNodes.add(curr)
            total = 1
            for p in Gn[curr]:
                if p in seenPrimes: continue
                seenPrimes.add(p)
                for owner in Gp[p]: total += dfs(owner)
            return total
        Gp = collections.defaultdict(list)
        Gn = collections.defaultdict(list)
        for a in A: pfactorization(a)   #build our graphs
        seenPrimes, seenNodes = set(), set()
        return max([dfs(a) for a in A])

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def pfactorization(a):
            N = a
            if a >= 2 and a % 2 == 0:   #treat 2 alone
                Gp[2].append(N)
                Gn[N].append(2)
                while a % 2 == 0:
                    a //= 2
            for d in range(3, math.floor(a**(1/2)) + 1, 2): #possible odd numbers
                if d > a:   break
                if a % d == 0:
                    Gn[N].append(d)
                    Gp[d].append(N)
                    while a % d == 0:
                        a //= d
            if a > 1:   #check if what remains is itself a prime
                Gp[a].append(N)
                Gn[N].append(a)
        #Find the prime factors of the current number using Gn,
        #For each prime factor, find all the numbers excluding self who have this prime factor
        #They should all be connected
        def dfs(curr):
            if curr in seenNodes:
                return 0
            seenNodes.add(curr)
            total = 1
            for p in Gn[curr]:
                if p in seenPrimes:
                    continue
                seenPrimes.add(p)
                for owner in Gp[p]:
                    total += dfs(owner)
            return total
        #This graph contains numbers in the list sharing the a prime factor, the key is that prime factor
        Gp = defaultdict(list)
        #This graph stores prime factors of each number in the list
        Gn = defaultdict(list)
        for a in A:
            pfactorization(a)
        seenPrimes, seenNodes = set(), set()
        return max([dfs(a) for a in A])
#Time Complexity : O(sqrt(max(A)*max(A))


class Solution:
    def largestComponentSize(self, A):
        n = len(A)
        primes = collections.defaultdict(list)
        parents = [i for i in range(n)]
        def find(x):
            if parents[x] != x:
                return find(parents[x])
            return parents[x]
        def union(x, y):
            xr, yr = find(x), find(y)
            if xr > yr:
                parents[xr] = yr
            else:
                parents[yr] = xr
        def primeSet(N):
            for i in range(2, int(math.sqrt(N))+1):
                if N%i == 0:
                    return {i} | primeSet(N//i)
            return {N}
        for i, num in enumerate(A):
            for q in primeSet(num):
                primes[q] += [i]
        for _, indexes in primes.items():
            for i in range(len(indexes)-1):
                union(indexes[i], indexes[i+1])
        return max(Counter([find(i) for i in range(n)]).values())

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def prime_factors(n):
            for i in range(2, int(math.sqrt(n))+1):
                if n % i == 0:
                    return prime_factors(n//i) | set([i])
            return set([n])
            # i = 2
            # while i ** 2 <= n:
            #     if n % i == 0:
            #         return prime_factors(n // i) | set([i])
            #     i += 1
            # return set([n])

        f = list(range(len(A)))

        def find(x):
            # if x not in f:
            #     f[x] = x
            if f[x] != x:
                f[x] = find(f[x])
            return f[x]

        def union(x, y):
            f[find(x)] = find(y)

        p2i = dict()
        for i, a in enumerate(A):
            primes = prime_factors(a)
            # print(i, primes)
            for p in primes:
                # if p not in p2i:
                #     p2i[p] = []
                # p2i[p].append(i)
                if p in p2i:
                    union(i, p2i[p])
                else:
                    p2i[p] = find(i)
        # for indexes in p2i.values():
        #     for i in range(len(indexes) - 1):
        #         union(indexes[i], indexes[i + 1])
        # print(p2i)
        # print(list(map(find, range(len(A)))))
        counts = Counter(map(find, range(len(A))))
        return counts.most_common(1)[0][1]

import math

class UnionFind:
    
    def __init__(self, n):
        self.data = list(range(n))
        self.size = [1] * n
        
    def find(self, x):
        if self.data[x] != x:
            self.data[x] = self.find(self.data[x])
        return self.data[x]
    
    def union(self, x, y):
        ix, iy = self.find(x), self.find(y)
        if ix != iy:
            self.data[ix] = iy
            self.size[iy] += self.size[ix]
            self.size[ix] = 0


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        def prime_set(num):
            res = set()
            while num % 2 == 0:
                res.add(2)
                num //= 2
            for i in range(3, int(math.sqrt(num)) + 1, 2):
                while num % i == 0:
                    res.add(i)
                    num //= i
            if num > 2:
                res.add(num)
            return res
        
        n = len(A)
        uf = UnionFind(n)
        primes_dict = collections.defaultdict(list)
        for i, num in enumerate(A):
            pr_set = prime_set(num)
            for p in pr_set:
                primes_dict[p].append(i)
        for indices in primes_dict.values():
            for j in range(1, len(indices)):
                uf.union(indices[j - 1], indices[j])
                
        return max(collections.Counter(uf.find(i) for i in range(n)).values())
        
        
    def gcd_with_bfs(self, A: List[int]) -> int:
        graph = collections.defaultdict(set)
        
        for i in range(len(A)):
            for j in range(i, len(A)):
                if math.gcd(A[i], A[j]) > 1:
                    graph[A[i]].add(A[j])
                    graph[A[j]].add(A[i])
        
        res = 0
        seen = set()
        for a in A:
            if a not in seen:
                node_count = 0
                q = collections.deque([a])
                seen.add(a)
                while q:
                    node = q.popleft()
                    node_count += 1
                    seen.add(node)
                    for child in graph[node]:
                        if child not in seen:
                            seen.add(child)
                            q.append(child)
                res = max(res, node_count)
        return res

class DSU:
    def __init__(self,n):
        self.parent = [i for i in range(n)]
        self.rank = [1 for i in range(n)]
    
    def find(self,x):
        if x!=self.parent[x]:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def union(self,x,y):
        px = self.find(x)
        py = self.find(y)
        if px == py:
            return
        if self.rank[px] > self.rank[py]:
            self.parent[py] = px
            self.rank[px]+=self.rank[py]
        else:
            self.parent[px] = py
            self.rank[py]+=self.rank[px]
            
            
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        n = len(A)
        dsu = DSU(n)
        primes = defaultdict(list)
        for i, num in enumerate(A):
            pr_set = self.primes_set(num)
            for q in pr_set: 
                primes[q].append(i)
        
        for _, indexes in list(primes.items()):
            for i in range(len(indexes)-1):
                dsu.union(indexes[i], indexes[i+1])

        
        # for i in range(n):
        #     for j in range(i+1,n):
        #         if self.gcd(A[i],A[j]) > 1:
        #             dsu.union(i,j)
        return max(dsu.rank)
    
    def primes_set(self,n):
        # 35
        # i in range(2,6) --> 2,3,4,5 return func(7) | {5}
        # 7
        # i in range(2,3) --> 3,3 , return {7}
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return set([i]).union(self.primes_set(n//i))
        return set([n])
    
    def gcd(self,x,y):
        return gcd(y,x%y) if y!=0 else 0
                
                
        
        


class DSU:
    def __init__(self,n):
        self.parent = [i for i in range(n)]
        self.rank = [1 for i in range(n)]
    
    def find(self,x):
        if x!=self.parent[x]:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def union(self,x,y):
        px = self.find(x)
        py = self.find(y)
        if px == py:
            return
        if self.rank[px] > self.rank[py]:
            self.parent[py] = px
            self.rank[px]+=self.rank[py]
        else:
            self.parent[px] = py
            self.rank[py]+=self.rank[px]
            
            
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        n = len(A)
        dsu = DSU(n)
        primes = defaultdict(list)
        for i, num in enumerate(A):
            pr_set = self.primes_set(num)
            for q in pr_set: 
                primes[q].append(i)
        
        for _, indexes in list(primes.items()):
            for i in range(len(indexes)-1):
                dsu.union(indexes[i], indexes[i+1])

        
        # for i in range(n):
        #     for j in range(i+1,n):
        #         if self.gcd(A[i],A[j]) > 1:
        #             dsu.union(i,j)
        return max(dsu.rank)
    
    def primes_set(self,n):
        # 35
        # i in range(2,6) --> 2,3,4,5 return func(7) | {5}
        # 7
        # i in range(2,3) --> 3,3 , return {7}
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return set([i]) | (self.primes_set(n//i))
        return set([n])
    
    def gcd(self,x,y):
        return gcd(y,x%y) if y!=0 else 0
                
                
        
        


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        primes = []
        for x in range(2, int(max(A)**0.5)+1):
            for y in primes:
                if x % y == 0:
                    break
            else:
                primes.append(x)
    
        factors = collections.defaultdict(list)
        for a in A:
            x = a
            for p in primes:
                if p*p > x:
                    break
                if x % p == 0:
                    factors[a].append(p)
                    while x % p == 0:
                        x //= p
            if x > 1:
                factors[a].append(x)
                primes.append(x)
                
        primes = list(set(primes))
        n = len(primes)
        p2i = {p: i for i,p in enumerate(primes)}
        
        parent = [i for i in range(n)]
        
        def find(i):
            if i != parent[i]:
                parent[i] = find(parent[i])
            return parent[i]
        
        def union(i,j):
            pi, pj = find(i), find(j)
            if pi != pj:
                parent[pi] = pj

        for a in A:
            if factors[a]:
                p0 = factors[a][0]
                for p in factors[a][1:]:
                    union(p2i[p0], p2i[p])
        
        count = collections.Counter(find(p2i[factors[a][0]]) for a in A if factors[a])
        return max(count.values())
                             



max_num = 100000
smallest_prime_factors = [None] * (max_num + 1)
smallest_prime_factors[1] = 1

for num in range(2, max_num+1):
    if smallest_prime_factors[num] is not None:
        continue
    smallest_prime_factors[num] = num
    for multiple in range(num*num, max_num+1, num):
        if smallest_prime_factors[multiple] is None:
            smallest_prime_factors[multiple] = num

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parents = {}
        
        def find(x):
            if x not in parents:
                parents[x] = x
            elif parents[x] != x:
                parents[x] = find(parents[x])
            return parents[x]
        
        def union(x, y):
            xx, yy = find(x), find(y)
            if xx != yy:
                parents[xx] = yy
        
        def decompose(num):
            if num == 1:
                return [1]
            prime_factor_set = set()
            while num != 1:
                prime_factor_set.add(smallest_prime_factors[num])
                num //= smallest_prime_factors[num]
            return list(prime_factor_set)
        
        factor = {}
        
        for num in A:
            prime_factors = decompose(num)
            factor[num] = prime_factors[0]
            for i in range(1, len(prime_factors)):
                union(prime_factors[i-1], prime_factors[i])
        
        counts = Counter(find(factor[num]) for num in A)
        return max(counts.values() or [0])

class Solution:
    def largestComponentSize(self, A):
        n = len(A)
        primes = collections.defaultdict(list)
        parents = [i for i in range(n)]
        def find(x):
            if parents[x] != x:
                return find(parents[x])
            return parents[x]
        def union(x, y):
            xr, yr = find(x), find(y)
            if xr > yr:
                parents[xr] = yr
            else:
                parents[yr] = xr
        def primeSet(N):
            for i in range(2, int(math.sqrt(N))+1):
                if N%i == 0:
                    return {i} | primeSet(N//i)
            return {N}
        for i, num in enumerate(A):
            for q in primeSet(num):
                primes[q] += [i]
        for group in primes.values():
            for i in range(len(group)-1):
                union(group[i], group[i+1])
        return max(Counter([find(i) for i in range(n)]).values())

class DSU:
    def __init__(self, N):
        self.parent = list(range(N))
        
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def union(self, x, y):
        px = self.find(x)
        py = self.find(y)
        self.parent[py] = px

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        def primeSet(n):
            for i in range(2, int(sqrt(n))+1):
                if n % i == 0:
                    return primeSet(n//i) | {i}
            return {n}
        
        table = collections.defaultdict(list)
        
        for i, num in enumerate(A):
            primes = primeSet(num)
            for p in primes:
                table[p].append(i)
        
        N = len(A)
        dsu = DSU(N)
        
        for _, indexes in list(table.items()):
            for i in range(len(indexes)-1):
                dsu.union(indexes[i], indexes[i+1])
        
        return max(Counter([dsu.find(x) for x in range(N)]).values())
                



from collections import defaultdict
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        def getFactors(n):
            if n==1:
                return [1]
            factor_set=[]
            if n%2==0:
                factor_set.append(2)
                while n%2==0:
                    n=n//2
            if n>1:
                for i in range(3,math.floor(math.sqrt(n))+1,2):
                    if n%i==0:
                        factor_set.append(i)
                        while n%i==0:
                            n=n//i
                    if n==1:
                        break
            if n>2:
                factor_set.append(n)
            return factor_set
                    
        
        def find(parent,n):
            result=parent[n]
            if result!=n:
                parent[n]=find(parent,result)
            return parent[n]
        
        def union(parent,n1,n2):
            r1=rank[n1]
            r2=rank[n2]
            x1=find(parent,n1)
            x2=find(parent,n2)
            if x1!=x2:
                if r1>=r2:
                    parent[x2]=parent[x1]
                    rank[x1]+=1
                else:
                    parent[x1]=parent[x2]
                    rank[x2]+=1
            
        # print(\"--------------\")
 
        max_elem=max(A)
        parent=[i for i in range(max_elem+1)]
        rank=[0]*(max_elem+1)
        
        for item in A:
            factor_set=getFactors(item)
            # print(item,factor_set)
            v1=find(parent,item)
            if v1==item:
                union(parent,factor_set[0],v1)
                for factor in factor_set[1:]:
                    union(parent,factor_set[0],factor)
        count=defaultdict(int)
        for item in A:
            count[find(parent,item)]+=1
        # print(count)
        # print(parent)
        return max(count.values())
                
                


class DSU:
    def __init__(self, N):
        self.p = list(range(N))
        self.sz = [1] * N
        self.max_sz = 1

    def find(self, x):
        while self.p[x] != x:
            self.p[x] = self.p[self.p[x]]
            x = self.p[x]
        return self.p[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        if xr == yr: 
            return
        if self.sz[xr] < self.sz[yr]:
            x, y, xr, yr = y, x, yr, xr
        self.p[yr] = xr
        self.sz[xr] += self.sz[yr]
        self.max_sz = max(self.max_sz, self.sz[xr])

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def factorize(n):
            result = set()
            if n % 2 == 0:
                result.add(2)
                while n % 2 == 0: n //= 2
            for i in range(3, int(sqrt(n)) + 1, 2):
                if n % i == 0:
                    result.add(i)
                    while n % i == 0: n //= i
            if n > 1:
                result.add(n)
            return result

        if not A:
            return 0
        dsu = DSU(len(A))
        primes = dict()
        for i, a in enumerate(A):
            for prime in factorize(a):
                primes.setdefault(prime,[]).append(i)

        for indices in primes.values():
            for i in range(len(indices)-1):
                dsu.union(indices[i], indices[i+1])
        return dsu.max_sz


def get_prime_factors(num,):
    for i in range(2, int(math.sqrt(num)) + 1):
        if num % i == 0:
            return list(set(get_prime_factors(num // i) + [i]))
                
            
    return [num]


class DisjointSet:
    def __init__(self):        
        self.prime_parents = {}
        self.parent_to_count = {}
        
    def get_parent(self, prime):
        if prime not in self.prime_parents:
            self.prime_parents[prime] = -1
            return prime
        
        current = prime
        while self.prime_parents[current] > 0:
            current = self.prime_parents[current]
            
        return current
    
    def join(self, left, right):
        left_parent = self.get_parent(left)
        right_parent = self.get_parent(right)

        if left_parent == right_parent:
            return
        
        if self.prime_parents[left_parent] < self.prime_parents[right_parent]:
            larger = left_parent
            smaller = right_parent
        else:
            larger = right_parent
            smaller = left_parent
            
        self.prime_parents[larger] += self.prime_parents[smaller]
        self.parent_to_count[larger] = self.parent_to_count.get(larger, 0) + self.parent_to_count.get(smaller, 0)
        self.prime_parents[smaller] = larger
            
    
    def add(self, val):
        prime_factors = get_prime_factors(val)
        for l, r in zip(prime_factors, prime_factors[1:]):
            self.join(l, r)
            
        parent = self.get_parent(prime_factors[0])
        self.parent_to_count[parent] = self.parent_to_count.get(parent, 0) + 1
           

    
    def get_largest_set_size(self):
        return max(self.parent_to_count.values())
    

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        dj_set = DisjointSet()
        for val in A:
            dj_set.add(val)
            
        return dj_set.get_largest_set_size()

def get_primes(max_num):
    return []
#     primes = []
#     possible_primes = [True for _ in range(max_num + 1)]
#     value = 2
#     while value <= max_num:
#         if possible_primes[value]:
#             primes.append(value)
#             for multiplier in range(2, max_num // value + 1):
#                 possible_primes[multiplier * value] = False
                
#         value += 1
        
#     return primes


def get_prime_factors(num, primes):
    for i in range(2, int(math.sqrt(num)) + 1):
        if num % i == 0:
            return list(set(get_prime_factors(num // i, primes) + [i]))
                
            
    return [num]
#     if num == 1:
#         return [1]
    
#     prime_factors = set()
    
#     for prime in primes:
#         if num < prime:
#             break
#         while num % prime == 0:
#             num = num // prime
#             prime_factors.add(prime)
            
#     return list(prime_factors)


class DisjointSet:
    def __init__(self, primes):
        self.primes = primes
        self.prime_parents = {}
        self.parent_to_count = {}
        
    def get_parent(self, prime):
        if prime not in self.prime_parents:
            self.prime_parents[prime] = -1
            return prime
        
        current = prime
        while self.prime_parents[current] > 0:
            current = self.prime_parents[current]
            
        return current
    
    def join(self, left, right):
        left_parent = self.get_parent(left)
        right_parent = self.get_parent(right)

        if left_parent == right_parent:
            return
        
        if self.prime_parents[left_parent] < self.prime_parents[right_parent]:
            larger = left_parent
            smaller = right_parent
        else:
            larger = right_parent
            smaller = left_parent
            
        self.prime_parents[larger] += self.prime_parents[smaller]
        self.parent_to_count[larger] = self.parent_to_count.get(larger, 0) + self.parent_to_count.get(smaller, 0)
        self.prime_parents[smaller] = larger
            
    
    def add(self, val):
        prime_factors = get_prime_factors(val, self.primes)
        for l, r in zip(prime_factors, prime_factors[1:]):
            self.join(l, r)
            
        parent = self.get_parent(prime_factors[0])
        self.parent_to_count[parent] = self.parent_to_count.get(parent, 0) + 1
           

    
    def get_largest_set_size(self):
        return max(self.parent_to_count.values())
    

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        max_val = max(A)
        primes = get_primes(max_val)
        
        dj_set = DisjointSet(primes)
        for val in A:
            dj_set.add(val)
            
        return dj_set.get_largest_set_size()

from collections import defaultdict
from math import sqrt
class DSU(object):
    def __init__(self, n):
        self.ds = list(range(n))
    
    
    def find(self, v):
        if self.ds[v] != v:
            self.ds[v] = self.find(self.ds[v])
        return self.ds[v]

    def union(self, p1, p2):
        pp1, pp2 = self.find(p1), self.find(p2)
        self.ds[pp1] = pp2
    
class Solution(object):    
    def uniqPrime(self, n):
        l = []
        while n % 2 == 0:
            l.append(2)
            n = n//2
        
        for i in range(3, int(sqrt(n)) + 1, 2):
            while n % i == 0:
                l.append(i)
                n = n//i
        if n > 2:
            l.append(n)
        
        return list(set(l))
        
    def largestComponentSize(self, A):
        primes = defaultdict(list)
        n = len(A)
        for i in range(n):
            p = self.uniqPrime(A[i])
            for x in p:
                primes[x].append(i)
        
        #now we need to merge the disjoint sets and see which is the longest
        uf = DSU(n)
        for i in primes.items():
            vals = i[1]
            for j in range(len(vals) - 1):
                uf.union(vals[j], vals[j+1])
        
        return max(Counter([uf.find(i) for i in range(n)]).values())

import math
from collections import deque

class UnionFind:
    def __init__(self, n):
        self.parent = [-1]*n
        
    def find(self, a):
        if self.parent[a] < 0:
            return a
        self.parent[a] = self.find(self.parent[a])
        return self.parent[a]
    
    def union(self, a, b):
        root_a = self.find(a)
        root_b = self.find(b)
        if root_a != root_b:
            if self.parent[root_a] <= self.parent[root_b]:
                self.parent[root_a] += self.parent[root_b]
                self.parent[root_b] = root_a
            else:
                self.parent[root_b] += self.parent[root_a]
                self.parent[root_a] = root_b
                
########################## Solution inspired by discussion O(n sqrt(max(A))) ################
# The main idea of this is to use prime factorization for each number in A which takes O(n sqrt(max(A))) and build a dictionary with the key of prime number and value of list of indices of A that have that prime factor. Then connect the indices in each list with union find.

import math
from collections import defaultdict
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        def prime_factors(num):
            for i in range(2, int(math.sqrt(num))+1):
                if num%i == 0:
                    return set([i]) | prime_factors(num//i)
            return set([num])
        
        uf = UnionFind(len(A))
        d = defaultdict(list)
        for i, a in enumerate(A):
            for p in prime_factors(a):
                d[p].append(i)
        
        for p, idx_list in list(d.items()):
            for i in range(len(idx_list)-1):
                uf.union(idx_list[i], idx_list[i+1])
        return -min(uf.parent)
        
    
                
                
                

                
                
########################### My O(n^2) solution which is TLE #############################         
# class Solution:
    # def largestComponentSize(self, A: List[int]) -> int:
    #     uf = UnionFind(len(A))
    #     for i in range(len(A)-1):
    #         for j in range(i+1, len(A)):
    #             p1 = uf.find(i)
    #             p2 = uf.find(j)
    #             if p1 != p2 and math.gcd(A[i], A[j]) > 1:
    #                 uf.union(i, j)
    #     return -min(uf.parent)
    
    
            
########################### My simple bfs solution which is O(n^2) ##############################
# class Solution:
#     def largestComponentSize(self, A: List[int]) -> int:
#         max_so_far = 0
#         seen = [0]*len(A)
#         first_unseen = 0
#         while first_unseen is not None:
#             tmp = 0
#             seen[first_unseen] = 1
#             q = deque([(first_unseen, A[first_unseen])])
#             first_unseen = None
#             while q:
#                 idx, num1 = q.popleft()
#                 tmp += 1
#                 for i, a in enumerate(A):
#                     if not seen[i]:
#                         if math.gcd(a, num1) > 1:
#                             seen[i] = 1
#                             q.append((i, a))
#                         else:
#                             first_unseen = i
#             max_so_far = max(max_so_far, tmp)
#         return max_so_far


class UnionFind:
    def __init__(self, val):
        self.val = val
        self.parent = self
        
    def union(self, uf):
        uf.find().parent = self.find()
        
    def find(self):
        if self.parent == self:
            return self
        self.parent = self.parent.find()
        return self.parent
    
class Solution:
    def primeSet(self, n, cache):
        if n in cache:
            return cache[n]
        for i in range(2, int(sqrt(n)) + 1):
            if n % i == 0:
                cache[n] = self.primeSet(n // i, cache) | set([i])
                return cache[n]
        cache[n] = set([n])
        return cache[n]
    
    def largestComponentSize(self, A: List[int]) -> int:
        unionFinds = {x: UnionFind(x) for x in A}
        cache = {}
        numbersThatThisPrimeIsAFactor = defaultdict(list)
        for x in A:
            primes = self.primeSet(x, cache)
            for p in primes:
                numbersThatThisPrimeIsAFactor[p].append(x)
        
        for _, p in numbersThatThisPrimeIsAFactor.items():
            for i in range(len(p) - 1):
                unionFinds[p[i]].union(unionFinds[p[i + 1]])
        
        return max(Counter([unionFinds[x].find().val for x in A]).values())

from collections import defaultdict, Counter

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        primes = []
        for x in range(2, int(max(A)**0.5)+1):
            for y in primes:
                if x % y == 0:
                    break
            else:
                primes.append(x)
    
        factors = defaultdict(list)         # compute factors of each 'a'
        for a in A:
            x = a
            for p in primes:
                if p*p > x:
                    break
                if x % p == 0:
                    factors[a].append(p)
                    while x % p == 0:
                        x //= p
            if x > 1:                                   # a new prime found
                factors[a].append(x)
                primes.append(x)
                
        primes = list(set(primes))
        parent = list(range(len(primes)))
        p2i = {p:i for i,p in enumerate(primes)}
        
        def find(i):
            if i != parent[i]:
                parent[i] = find(parent[i])
            return parent[i]
        
        def union(i,j):
            pi, pj = find(i), find(j)
            if pi != pj:
                parent[pi] = pj
            
        for a in A:
            if factors[a]:
                pf0 = factors[a][0]
                for pf in factors[a][1:]:
                    union(p2i[pf0], p2i[pf])
                
        count = Counter(find(p2i[factors[a][0]]) for a in A if factors[a])
        return max(count.values())

class UnionFind(object):
    def uf(self, n):
        self.root = [i for i in range(n)]
        self.size = [1] * n
        
    def find(self, x):
        while x != self.root[x]:
            self.root[x] = self.root[self.root[x]]
            x = self.root[x]
        return x

    def union(self, x, y):  
        x_root = self.find(x)
        y_root = self.find(y)
        if x_root == y_root:
            return
        self.root[x_root] = y_root
        self.size[y_root] += self.size[x_root]
        self.size[x_root] = 0

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def primeFactors(n):
            primes = set()
            while n % 2 == 0:
                primes.add(2)
                n //= 2
            for i in range(3, int(math.sqrt(n)+1), 2):
                while n % i == 0:
                    primes.add(i)
                    n //= i
            if n > 2: #incase 3
                primes.add(n)
            return primes
        uf = UnionFind()
        uf.uf(len(A))
        pF = {}
        for i, num in enumerate(A):
            primes = primeFactors(num)
            for p in primes:
                if p in pF:
                    uf.union(i, pF[p])
                pF[p] = i
        return max(uf.size)

class UnionFind(object):
    def uf(self, n):  
        self.uf = [i for i in range(n)]
        self.size = [1] * n
        
    def find(self, x):  
        while x != self.uf[x]:
            self.uf[x] = self.uf[self.uf[x]]
            x = self.uf[x]
        return x

    def union(self, x, y):  
        x_root = self.find(x)
        y_root = self.find(y)
        if x_root == y_root:
            return
        self.uf[x_root] = y_root
        self.size[y_root] += self.size[x_root]
        self.size[x_root] = 0

def primeFactors(n):  # Prime factor decomposition
    out = set()
    while n % 2 == 0: 
        out.add(2)
        n //= 2
    for i in range(3, int(math.sqrt(n))+1, 2): 
        while n % i== 0: 
            out.add(i) 
            n //= i 
    if n > 2: 
        out.add(n)
    return out

class Solution(object):
    def largestComponentSize(self, A: List[int]) -> int:
        uf = UnionFind()
        uf.uf(len(A))
        
        primeToIndex = {} 
        for i,a in enumerate(A):
            primes = primeFactors(a)
            for p in primes:
                if p in primeToIndex:
                    uf.union(i, primeToIndex[p])
                primeToIndex[p] = i
        return max(uf.size)

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent = [i for i in range(len(A))]
        rank = [0 for i in range(len(A))]
        
        def prime_factors(n):
            for i in range(2, int(math.sqrt(n))+1):
                if n % i == 0:
                    return prime_factors(n//i) | set([i])
            return set([n])
            # primes = set()
            # d = 2
            # while d <= sqrt(n):
                # if n % d == 0:
                    # primes.add(d)
                    # n //= d
                # else:    
                    # d += 1
            # if n > 1:
                # primes.add(n)
            # return primes        
                    
        def find(n):    
            p = parent[n]
            if p == n:
                return p
            parent[n] = find(parent[n])
            return parent[n]

        def merge(n1, n2):
            r1 = find(n1)
            r2 = find(n2)
            
            if r1 == r2:
                return
            
            if rank[r1] < rank[r2]:
                parent[r1] = r2
            elif rank[r1] > rank[r2]:
                parent[r2] = r1
            else:    
                parent[r1] = r2
                rank[r2] += 1
                
        prime_indeces = defaultdict(list)
        for i, n in enumerate(A):
            primes = prime_factors(n)
            for p in primes:
                prime_indeces[p].append(i)
            
        print(prime_indeces)    
        # print(parent)
        for p, indeces in list(prime_indeces.items()):
            for i in range(len(indeces)-1):
                # print('merging', A[indeces[i]], A[indeces[i+1]])
                merge(indeces[i], indeces[i+1])
                # print(parent)        
                
                
        count_map = dict()
        best = 0        
        
        for i in parent:
            i = find(i)
            if i in count_map:
                count_map[i] += 1
            else:
                count_map[i] = 1
                
            best = max(best, count_map[i])
        # print(count_map)    
            
        return best


import numpy as np
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        # second attempt, going factor-wise using disjoint set structure
        # A = np.array(A)
        # start with parent pointing to themselves
        parents = np.arange(len(A))
        
        # count of each node starting at 1 (itself)
        counts = np.ones_like(parents)
        
        def find(i):
            if parents[i] == i:
                return i
            else:
                return find(parents[i])
        
        def combine(i, j):
            pi = find(i)
            pj = find(j)
            
            # only do something if not already linked
            if pi != pj:
                # merge under the biggest root
                if counts[pi] > counts[pj]:
                    parents[pj] = pi
                    counts[pi] += counts[pj]
                else:
                    parents[pi] = pj
                    counts[pj] += counts[pi]
        
        max_prime = int(np.floor(np.sqrt(max(A))))+1
        # max_prime = max(A)
        
#         def get_primes(value: int) -> List[int]:
#             ret = []
#             sieve = [True]*(value+1)
#             for p in range(2, value+1):
#                 if sieve[p]:
#                     ret.append(p)
#                     for k in range(p, value+1, p):
#                         sieve[k] = False
#             return ret
        
#         primes = get_primes(max_prime)
        
#         for prime in primes:
#             match = -1
#             for i in range(len(A)):
#                 if A[i] % prime == 0:
#                     while A[i] % prime == 0:
#                         A[i] = A[i] // prime  # keep factoring out
#                     if match != -1:
#                         # do the merge
#                         combine(match, i)
#                     else:
#                         match = i # first one found, merge from now on
        
        
        sieve = [True]*(max_prime+1)
        for prime in range(2, max_prime+1):
            if sieve[prime]:
                match = -1
                for i in range(len(A)):
                    if A[i] % prime == 0:
                        while A[i] % prime == 0:
                            A[i] = A[i] // prime  # keep factoring out
                        if match != -1:
                            # do the merge
                            combine(match, i)
                        else:
                            match = i # first one found, merge from now on
                for k in range(prime, max_prime+1, prime):
                    sieve[k] = False
        
        # leftover values of A are now higher primes (or 1)
        # if any match, they need to be merged
        inds = np.argsort(A)
        
        # print(A)
        # print(inds)
        # print(A[inds])
        for i in range(1,len(A)):
            if (A[inds[i]] != 1) and (A[inds[i-1]] == A[inds[i]]):
                combine(inds[i-1], inds[i])
        
        return np.max(counts)
        
        # first attempt
        # TLE at 78/100
#         # note: a value of 1 cannot be connected to anything
#         # can clump things together based on factors
        
#         def get_factors(value: int) -> List[int]:
#             if value == 1:
#                 return set()
#             # ret = [value]
#             ret = set([value])
            
#             # if value % 2 == 0:
#             #     ret.append(2)
#             #     ret.append(value // 2)
            
#             for i in range(2, int(np.floor(np.sqrt(value)))+1):
#                 if value % i == 0:
#                     ret.add(i)
#                     ret.add(value // i)
#                     # ret.append(i)
#                     # ret.append(value // i)
            
#             return ret
#             # return set(ret)
        
        
#         # def get_primes(value: int) -> List[int]:
#         #     ret = []
#         #     sieve = [True]*(value+1)
#         #     for p in range(2, value+1):
#         #         if sieve[p]:
#         #             ret.append(p)
#         #             for k in range(p, value+1, p):
#         #                 sieve[k] = False
#         #     return ret
        
#         # trying more efficient get_primes implementation
#         # def get_primes(n: int) -> List[int]:
#         #     # modified from
#         #     # https://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
#         #     sieve = np.ones(n//3 + (n%6==2), dtype=np.bool)
#         #     sieve[0] = False
#         #     for i in range(int(n**0.5)//3+1):
#         #         if sieve[i]:
#         #             k=3*i+1|1
#         #             sieve[      ((k*k)//3)      ::2*k] = False
#         #             sieve[(k*k+4*k-2*k*(i&1))//3::2*k] = False
#         #     return np.r_[2,3,((3*np.nonzero(sieve)[0]+1)|1)]
        
#         def get_primes(n: int) -> List[int]:
#             sieve = [True] * n
#             for i in range(3,int(n**0.5)+1,2):
#                 if sieve[i]:
#                     sieve[i*i::2*i]=[False]*((n-i*i-1)//(2*i)+1)
#             return [2] + [i for i in range(3,n,2) if sieve[i]]
        
#         primes = get_primes(int(np.floor(np.sqrt(max(A))))+1)
#         # primes = get_primes(max(A))
        
#         def get_factors(value: int) -> List[int]:
#             ret = set([value])
#             for prime in primes:
#                 if prime > value:
#                     return ret
#                 else:
#                     if value % prime == 0:
#                         ret.add(prime)
#                         while value % prime == 0:
#                             value /= prime
                        
#                         # ret.add(value//prime)
#                         # value /= prime  # factor out prime for efficiency
#                         # while value % prime == 0:
#                         #     ret.add(value//prime)
#                         #     value /= prime
                        
#                         # if value // prime in primes:
#                         # ret.add(value//prime)
#                         # value /= prime  # factor out prime for efficiency
#                         # if value > 1:
#                         #     ret.add(value)
#                         # else:
#                         #     break
#                         # while value % prime == 0:
#                         #     # if value // prime in primes:
#                         #     # ret.add(value//prime)
#                         #     value /= prime
#                         #     if value > 1:
#                         #         ret.add(value)
#                         #     else:
#                         #         break
#             if value > 1:
#                 ret.add(value)
#             return ret
        
#         clusters = []
#         sizes = []
        
#         for value in A:
#             factors = get_factors(value)
#             # check cluster matches, all that get matched get merged
#             matches = []
#             for j, cluster in enumerate(clusters):
#                 if not cluster.isdisjoint(factors):
#                     matches.append(j)
#             # if not in any cluster, make a new cluster
#             if len(matches) == 0:
#                 clusters.append(factors)
#                 sizes.append(1)
#             elif len(matches) == 1:
#                 clusters[matches[0]].update(factors)
#                 sizes[matches[0]] += 1
#             else:
#                 base = matches[0]
#                 # iterate backwards so they can be deleted safely
#                 for match in matches[-1:0:-1]:
#                     clusters[base].update(clusters[match])
#                     sizes[base] += sizes[match]
#                     del clusters[match]
#                     del sizes[match]
                
#                 # add the new factors
#                 clusters[base].update(factors)
#                 sizes[base] += 1      

#         return max(sizes)
            
        


class UFS: 
    def __init__(self, n):
        self.p = list(range(n))
    
    def find(self, x):
        if self.p[x] != x: 
            self.p[x] = self.find(self.p[x])
        return self.p[x]
    
    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr 

class Solution:
    def prime_sets(self, n):
        for i in range(2, int(math.sqrt(n)) + 1):
            if n % i == 0:
                return self.prime_sets(n // i) | set([i])
        return set([n])
    
    def largestComponentSize(self, A: List[int]) -> int:
        UF = UFS(len(A))
        primes = collections.defaultdict(list) 
        
        for i, n in enumerate(A):
            prime_set = self.prime_sets(n) 
            for q in prime_set: primes[q].append(i) 
                
        for _, items in primes.items():
            for i in range(len(items) - 1):
                UF.union(items[i], items[i + 1])
        
        return max(Counter([UF.find(i) for i in range(len(A))]).values())

'''
Idea: 1. Prime factorize the given numbers
      2. Map the factors to the indices in which they take part
      3. Perform union operations on the list of indices belonging to same factor
      4. Perform union operation to find the largest component

Time complexity: O(n * sqrt(m)) where prime factorization 'sqrt(m)' is applied n times 
Space complexity: O(n * log(m)) to keep all prime factors and maintain DSU
'''

import collections, math

class DSU:
    def __init__(self, n):
        self.parent = list(range(n))
        self.sizeOf = [1] * n  
    

    def find(self, p):
        # Find parent of given node
        root = p
        while self.parent[root] != root:
            root = self.parent[root]

        # Path compression
        while p != root:
            next_node = self.parent[root]    
            self.parent[p] = root
            p = next_node
        
        return root 

    
    def union(self, x, y):
        r1, r2 = self.find(x), self.find(y)

        if r1 == r2:
            return 
        if self.sizeOf[r1] > self.sizeOf[r2]:
            self.sizeOf[r1] += self.sizeOf[r2]
            self.parent[r2] = r1 
        else:
            self.sizeOf[r2] += self.sizeOf[r1]
            self.parent[r1] = r2


class Solution:
    def largestComponentSize(self, A):

        def primeFactorization(n):
            for i in range(2, int(math.sqrt(n))+1):
                if n % i == 0:
                    return primeFactorization(n//i) | set([i]) 
            return set([n])


        n = len(A)
        dsu = DSU(n)
        primes = collections.defaultdict(list)

        for i in range(n):
            prime_factors = primeFactorization(A[i])
            for factor in prime_factors:
                primes[factor] += i, 
        
        for factor in primes:
            indices = primes[factor]
            size = len(indices)
            for i in range(size-1):
                dsu.union(indices[i], indices[i+1]) 
        
        components = collections.defaultdict(int)
        
        for index in range(n):
            components[dsu.find(index)] += 1
        
        return max(components.values())

        


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        # https://leetcode.com/problems/largest-component-size-by-common-factor/discuss/819919/Python-Union-find-solution-explained
        # This question feels like union find but u cannot link together
        # First, find the primes factor of each number
        # And then group together same prime factore
        # The largest group is the largest component
        # But the way to find primes set is a little confusing 
        # It loop from small to large and find the first factor and the other (larger factor)
        # If two numbers share the same prime factor, they belong to the same group
        # Then use union find to grouo together
        n = len(A)
        record = [-1]*n
        primes = collections.defaultdict(list)
        def get_primes(i):
            for j in range(2,int(math.sqrt(i)+1)):
                if i%j == 0:
                    return get_primes(i//j) | set([j])
            return set([i])
                
            return res
        def find(a):
            if record[a] < 0:return a
            record[a] = find(record[a])
            return record[a]
        
        
        # U have been wrong on this several times
        # When merge, it is the record[i] == root index, not root val
        def union(i,j):
            a,b = find(i),find(j)
            if a!=b:
                if a<b:
                    record[a] = b
                else:
                    record[b] = a
                
            
        for i, v in enumerate(A):
            primes_set = get_primes(v)
            for j in primes_set:
                primes[j].append(i)
            
        for _,indexes in list(primes.items()):
            for i in range(len(indexes)):
                union(indexes[0],indexes[i])
        
        res = 0
        mapping = collections.defaultdict(set)
        for i in range(n):
            root = find(i)
            mapping[root].add(i)
            if len(mapping[root]) > res:res = len(mapping[root])
        return res


class Solution:  # Sieve + BFS 
    
    def largestComponentSize(self, A: List[int]) -> int:
        
        def sieve():
            i = 2
            while i < len(spf):
                spf[i] = 2
                i += 2
            i = 3
            while i * i < len(spf):
                if spf[i] == i:
                    j = i
                    while j < len(spf):
                        if spf[j] == j:
                            spf[j] = i
                        j += i
                i += 2
        
        spf, di, factors, visited_nums, visited_factors, ans = [i for i in range(max(A) + 1)], defaultdict(set), defaultdict(set), set(), set(), 1
        
        sieve()  # 1
        
        for num in A:
            x = num
            while x != 1:
                di[spf[x]].add(num)
                factors[num].add(spf[x])
                x //= spf[x]
        
        for num in A:  # 2
            if num in visited_nums:
                continue
                
            visited_nums.add(num)
            cur, queue = 1, deque([])
            for factor in factors[num]:
                queue.append(factor)
                
            while queue: 
                factor = queue.popleft()
                visited_factors.add(factor)
                for next_num in di[factor]:  # 3
                    if next_num in visited_nums:
                        continue
                        
                    visited_nums.add(next_num)
                    cur += 1
                    for next_factor in factors[next_num]:
                        if next_factor in visited_factors:
                            continue
                        
                        visited_factors.add(next_factor)
                        queue.append(next_factor)
                
            ans = max(ans, cur)
        
        return ans

class UnionFind:
    def __init__(self, n):
        self.reps = [i for i in range(n)]
        self.size = [1]*n
    def find(self, x):
        while self.reps[x] != x:
            self.reps[x] = self.reps[self.reps[x]]
            x = self.reps[x]
        return x
    def union(self, x, y):
        x_root = self.find(x)
        y_root = self.find(y)
        if x_root == y_root:
            return
        self.reps[x_root] = y_root
        self.size[y_root] += self.size[x_root]
        self.size[x_root] = 0
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def get_prime_factor(n):
            factors = set()
            while n % 2 == 0:
                n //= 2
                factors.add(2)
            while n % 3 == 0:
                n //= 3
                factors.add(3)
            for i in range(5, int(sqrt(n))+1):
                while n % i == 0:
                    factors.add(i)
                    n //= i
            if n > 1:
                factors.add(n)
            return factors
        
        factor2idx = collections.defaultdict(list)    
        for i in range(len(A)):
            for factor in get_prime_factor(A[i]):
                factor2idx[factor].append(i)
        
        uf = UnionFind(len(A))
        for factor, indices in list(factor2idx.items()):
            for idx in indices[1:]:
                uf.union(indices[0], idx)
                

            
        return max(uf.size)
        
        
            


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        # https://leetcode.com/problems/largest-component-size-by-common-factor/discuss/819919/Python-Union-find-solution-explained
        # This question feels like union find but u cannot link together
        # First, find the primes factor of each number
        # And then group together same prime factore
        # The largest group is the largest component
        # But the way to find primes set is a little confusing 
        # It loop from small to large and find the first factor and the primes set for the larger factor
        # If two numbers share the same prime factor, they belong to the same group
        # Then use union find to grouo together
        n = len(A)
        record = [-1]*n
        primes = collections.defaultdict(list)
        def get_primes(i):
            for j in range(2,int(math.sqrt(i))+1):
                if i%j == 0:
                    # And find the primes set for the larger factor
                    return get_primes(i//j) | set([j])
            return set([i])
                
            return res
        def find(a):
            if record[a] < 0:return a
            record[a] = find(record[a])
            return record[a]
        
        
        # U have been wrong on this several times
        # When merge, it is the record[i] == root index, not root val
        def union(i,j):
            a,b = find(i),find(j)
            if a!=b:
                if a<b:
                    record[a] = b
                else:
                    record[b] = a
                
            
        for i, v in enumerate(A):
            primes_set = get_primes(v)
            for j in primes_set:
                primes[j].append(i)
            
        for _,indexes in list(primes.items()):
            for i in range(len(indexes)):
                union(indexes[0],indexes[i])
        
        res = 0
        mapping = collections.defaultdict(set)
        for i in range(n):
            root = find(i)
            mapping[root].add(i)
            if len(mapping[root]) > res:res = len(mapping[root])
        return res


class UnionFind:
    def __init__(self, N):
        self.p = list(range(N))

    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr

class Solution:
    def primes_set(self,n):
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self.primes_set(n//i) | set([i])
        return set([n])

    def largestComponentSize(self, A):
        n = len(A)
        UF = UnionFind(n)
        primes = defaultdict(list)
        for i, num in enumerate(A):
            pr_set = self.primes_set(num)
            for q in pr_set: primes[q].append(i)

        for _, indexes in primes.items():
            for i in range(len(indexes)-1):
                UF.union(indexes[i], indexes[i+1])

        return max(Counter([UF.find(i) for i in range(n)]).values())

class DSU:
    def __init__(self, size):
        self.indexes = {i:i for i in range(size)}
        self.sizes = {i:1 for i in range(size)}
    
    def root(self, i):
        node = i
        while i!=self.indexes[i]:
            i = self.indexes[i]
        
        while node!=i:
            nnode = self.indexes[node]
            self.indexes[node] = i
            node = nnode
        return i
    
    def unite(self, i, j):
        ri, rj = self.root(i), self.root(j)
        if ri==rj:
            return
        else:
            self.indexes[rj] = ri
            self.sizes[ri]+=self.sizes[rj]
        

class Solution:
    def primeSet(self, n):
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self.primeSet(n//i) | set([i])
        return set([n])
        
    def largestComponentSize(self, A: List[int]) -> int:
        
        # Note, that if two numbers has common factor more than 1, it means that they have prime common factor.
        d = collections.defaultdict(list)  # primeNum -> [indexes of A]
        for i in range(len(A)):
            s = self.primeSet(A[i])
            for v in s:
                d[v].append(i)
        
        dsu = DSU(len(A))
        for k in d:
            for ind in d[k][1:]:
                dsu.unite(d[k][0], ind)
        
        ans = 1
        for i in range(len(A)):
            ans = max(ans, dsu.sizes[i])
        
        return ans
    
            
        
        
        


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        fa = [i for i in range(len(A))]
        sz = [1]*len(A)
        def find(x):
            if fa[x] != x:
                fa[x] = find(fa[x])
            return fa[x]
        factor = defaultdict(list)
        for i in range(len(A)):
            x = A[i]
            for y in range(2, int(math.sqrt(x))+1):
                if not x%y:
                    factor[y].append(i)
                    while not x%y:
                        x //= y
            if x>1:
                factor[x].append(i)
        for k,v in list(factor.items()):
            for j in range(1, len(v)):
                x, y = v[0], v[j]
                fx, fy = find(x), find(y)
                if fx != fy:
                    if sz[fx] > sz[fy]:
                        sz[fy] += sz[fx]
                        fa[fx] = fy
                    else:
                        sz[fx] += sz[fy]
                        fa[fy] = fx
        ans = 0        
        for i in range(len(fa)):
            if i == fa[i]:
                ans = max(ans, sz[i])
        return ans


class UnionFind:
    def __init__(self, N):
        self.p = list(range(N))

    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr

class Solution:
    def primes_set(self,n):
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self.primes_set(n//i) | set([i])
        return set([n])

    def largestComponentSize(self, A):
        n = len(A)
        UF = UnionFind(n)
        primes = defaultdict(list)
        for i, num in enumerate(A):
            pr_set = self.primes_set(num)
            for q in pr_set: 
                primes[q].append(i)

        for _, indexes in primes.items():
            for i in range(len(indexes)-1):
                UF.union(indexes[i], indexes[i+1])

        return max(Counter([UF.find(i) for i in range(n)]).values())

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        # [99,68,70,77,35,52,53,25,62]
        n = len(A)
        dsu = DSU(n)
        prime_dict = defaultdict(list)
        for i, num in enumerate(A):
            primes = self.find_p(num)
            for p in primes:
                prime_dict[p].append(i)
        for _, p_list in list(prime_dict.items()):
            for j in range(len(p_list)):
                dsu.union(p_list[0], p_list[j])
        return max(Counter(dsu.find(x) for x in range(n)).values())
    
    def find_p(self, x):
        for i in range(2, int(math.sqrt(x))+1):
            if x % i == 0:
                return self.find_p(x // i) | set([i])
        return set([x])
    
    


class DSU:
    def __init__(self, n):
        self.sets = list(range(n))
        
    def find(self, x):
        if self.sets[x] != x:
            root = self.find(self.sets[x])
            self.sets[x] = root
            return root
        return x
    
    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.sets[yr] = xr
        
        
                
            
        
            
        
   
    

   


class UFD: 
    def __init__(self, n):
        self.p = list(range(n))
    
    def find(self, x):
        if self.p[x] != x: 
            self.p[x] = self.find(self.p[x])
        return self.p[x]
    
    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr 

class Solution:
    def prime_sets(self, n):
        for i in range(2, int(math.sqrt(n)) + 1):
            if n % i == 0:
                return self.prime_sets(n // i) | set([i])
        return set([n])
    
    def largestComponentSize(self, A: List[int]) -> int:
        UF = UFD(len(A))
        primes = collections.defaultdict(list)
        
        for i, n in enumerate(A):
            p = self.prime_sets(n)
            for q in p: primes[q].append(i)
                
        for _, items in list(primes.items()):
            for i in range(len(items) - 1):
                UF.union(items[i], items[i + 1])
        
        return max(Counter([UF.find(i) for i in range(len(A))]).values())


class Solution:
    # O(n x sqrt(max)) time, O(n x sqrt(max)) space
    def largestComponentSize(self, A: List[int]) -> int:
        
        # def find_prime_factors(num):
        #     result = set()
        #     candidate = 2
        #     cur_num = num
        #     while candidate <= min(cur_num, int(math.sqrt(num))):
        #         while cur_num % candidate == 0:
        #             result.add(candidate)
        #             cur_num //= candidate
        #         candidate += 1
        #     if cur_num != 1:
        #         result.add(cur_num)
        #     return result
        
        def find_prime_factors(num):
            for i in range(2, int(math.sqrt(num))+1):
                if num % i == 0:
                    return find_prime_factors(num//i) | set([i])
            return set([num])
        
        def find_root(x):
            if root[x] != x:
                root[x] = find_root(root[x])
            return root[x]
        
        def union(x, y):
            root[find_root(x)] = root[find_root(y)]
        
        root = [i for i in range(len(A))]
        prime_factor_to_index = defaultdict(list)
        # O(n x sqrt(max))
        for i, num in enumerate(A):
            prime_factors = find_prime_factors(num)
            for factor in prime_factors:
                prime_factor_to_index[factor].append(i)
        
        # O(n x sqrt(max))
        for indices in list(prime_factor_to_index.values()):
            for i in range(1, len(indices)):
                union(indices[i - 1], indices[i])
        
        # O(n)
        root_count = Counter(find_root(i) for i in range(len(A)))
        return max(root_count.values())
        



class DSU:
    def __init__(self, nums):
        # self.idx = {v:i for i, v in enumerate(nums)}
        self.nums = [i for i in range(len(nums))]
        self.cnt = [1] * len(nums)
    
    def find(self, idx):
        # idx = self.idx[x]
        if self.nums[idx] == idx:
            return idx
        pidx = self.find(self.nums[idx])
        self.nums[idx] = pidx
        return pidx
    
    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        if px != py:
            self.nums[px] = self.nums[py]
            self.cnt[py] += self.cnt[px]
        return self.cnt[py]
        
        
class Solution:
    def primes_set(self, x):
        for i in range(2, int(x**0.5)+1):
            if x % i == 0:
                return self.primes_set(x//i) | set([i])
        return set([x])
        
    def largestComponentSize(self, A: List[int]) -> int:
        dsu = DSU(A)
        primes = {}
        for i, x in enumerate(A):
            for prime in self.primes_set(x):
                if prime not in primes:
                    primes[prime] = []
                primes[prime].append(i)
        ans = 0
        for _, idxs in list(primes.items()):
            for i in range(len(idxs)-1):
                ans = max(ans, dsu.union(idxs[i], idxs[i+1]))
        return ans
                


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        uf = {}
        rank = {i: 1 for i in range(len(A))}
        
        def find(x):
            uf.setdefault(x, x)
            if uf[x] != x:
                uf[x] = find(uf[x])
            return uf[x]
        
        def union(x, y):
            px, py = find(x), find(y)
            if px != py:
                if rank[px] > rank[py]:
                    px, py = py, px
                rank[py] += rank[px]
                uf[px] = py
            
        def primeFactor(x):
            ans = set()
            if not x % 2:
                ans.add(2)
                while not x % 2: x //= 2
            for k in range(3, int(sqrt(x)) + 1, 2):
                if not x % k: ans.add(k)
                while not x % k: x //= k
                if x == 1: break
            if x > 1: ans.add(x)
            return ans
                
        dic = {}
        for i in range(len(A)):
            for k in primeFactor(A[i]):
                dic.setdefault(k, i)
                union(i, dic[k])
        return max(Counter([find(i) for i in range(len(A))]).values())

class Solution:
       def largestComponentSize(self, A):
           def getUniqueDivisors(x:int)->set():
              result = set()
              while x % 2 == 0:
                 result .add(2)
                 x >>= 1
              i = 3
              while i * i <= x:
                 while x % i == 0:
                    result.add(i)
                    x //= i
                 i += 2
              if x > 1:
                 result.add(x)
       
              if x > 1:
                 result.add(x)
              return result
           def findParent(parents:List[int],x:int)->int:
              if parents[x] != x:
                 parents[x]=findParent(parents,parents[x])
              return parents[x]
           n = len(A)
           parents = [i for i in range(n)]
           parentByDivisor = {}
           for i in range(n):
             divisors = getUniqueDivisors(A[i])
             for div in divisors:
                if div in parentByDivisor:
                   root = findParent(parents,parentByDivisor[div])
                   parents[root] = i
                parentByDivisor[div] = i
           counter = [0 for i in range(n)]
           for i in range(n):
              root = findParent(parents,i)
              counter[root] += 1
           return max(counter)
                
           


class DisjointSet:
    def __init__(self, num):
        self.forest = list(range(num))

    def find(self, x):
        if self.forest[x] != x:
            self.forest[x] = self.find(self.forest[x])
        return self.forest[x]

    def union(self, x, y):
        self.forest[self.find(x)] = self.find(y)


class Solution:
    def largestComponentSize(self, arr):
        n = len(arr)
        ds = DisjointSet(n)
        primesDict = defaultdict(list)
        for i, num in enumerate(arr):
            primes = self.getPrimes(num)
            for p in primes:
                primesDict[p].append(i)

        for li in primesDict.values():
            for i in range(len(li)-1):
                ds.union(li[i], li[i+1])

        return max(Counter([ds.find(i) for i in range(n)]).values())

    def getPrimes(self, num):
        for i in range(2, int(math.sqrt(num)) + 1):
            if num % i == 0:
                return self.getPrimes(num // i) | {i}
        return {num}

from math import sqrt
import collections
class Solution:
    def primes(self,n):
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self.primes(n//i) | set([i])
        return set([n])
    
    def find(self, i):
        if self.root[i]==i: return i 
        self.root[i]=self.find(self.root[i])
        return self.root[i]
    
    def union(self, i, j): 
        ri=self.find(i)
        rj=self.find(j)
        if ri==rj: return 
        if self.rank[ri]>self.rank[rj]:
            self.root[rj]=ri
        else:
            self.root[ri]=rj
            if self.rank[ri]==self.rank[rj]:
                self.rank[rj]+=1
        return 
            
   
    
    def largestComponentSize(self, A: List[int]) -> int:
        self.root={i:i for i in range(len(A))}
        self.rank={i:0 for i in range(len(A))}
        d=collections.defaultdict(set)
        for i in range(len(A)):
            for key in self.primes(A[i]):
                d[key].add(i)
        for key in d:
            temp=list(d[key])
            for x in temp:
                self.union(temp[0],x)
        return max([val for key, val in list(collections.Counter([self.find(i) for i in range(len(A))]).items())])
            
        
       


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        uf = {}
        rank = {a: 1 for a in A}
        
        def find(x):
            uf.setdefault(x, x)
            if uf[x] != x:
                uf[x] = find(uf[x])
            return uf[x]
        
        def union(x, y):
            px, py = find(x), find(y)
            if px != py:
                if rank[px] > rank[py]:
                    px, py = py, px
                rank[py] += rank[px]
                uf[px] = py
            
        def primeFactor(x):
            ans = set()
            if not x % 2:
                ans.add(2)
                while not x % 2:
                    x //= 2
            for k in range(3, int(sqrt(x)) + 1, 2):
                if not x % k:
                    ans.add(k)
                while not x % k:
                    x //= k
                if x == 1:
                    break
            if x > 1:
                ans.add(x)
            return ans
                
        dic = {}
        for a in A:
            for k in primeFactor(a):
                dic.setdefault(k, a)
                union(a, dic[k])
        return max(Counter([find(a) for a in A]).values())

class DFS:
    def __init__(self, n):
        self.p = list(range(n))
        
    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr 

class Solution:
    def prime_sets(self, n):
        for i in range(2, int(math.sqrt(n)) + 1):
            if n % i == 0:
                return self.prime_sets(n // i) | set([i])
        return set([n])
    
    def largestComponentSize(self, A: List[int]) -> int:
        UF = DFS(len(A))
        primes = collections.defaultdict(list)
        
        for i, n in enumerate(A):
            prime_sets = self.prime_sets(n) 
            for q in prime_sets: primes[q].append(i) 
        
        for _, items in primes.items():
            for i in range(len(items) - 1):
                UF.union(items[i], items[i + 1])
        
        return max(Counter([UF.find(i) for i in range(len(A))]).values())

class UnionFind:
    def __init__(self, N):
        self.indices = list(range(N)) # each elem belongs to diff index
        
    def find(self, x):
        if x == self.indices[x]:
            return x
        
        # Was unioned with a diff number, find that number's index
        # Set ans to elem, makes subsequent queries faster
        self.indices[x] = self.find(self.indices[x]) 
            
        return self.indices[x]

    def union(self, x, y):
        x_i,y_i = self.find(x), self.find(y)
        
        # Set x's index to y's index, unions both number's sets
        self.indices[x_i] = y_i
    
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        n = len(A)
        UF = UnionFind(n)
        
        primes_set = defaultdict(list)
        
        def get_primes(num):
            for i in range(2, int(math.sqrt(num))+1):
                if num % i == 0:
                    return get_primes(num // i) | set([i])
            return set([num])
                    
        
        for i,num in enumerate(A):
            for factor in get_primes(num):
                primes_set[factor].append(i)
                
        for vals in primes_set.values():
            for i in range(len(vals) - 1):
                UF.union(vals[i], vals[i+1])
        
        return max(Counter([UF.find(i) for i in range(n)]).values())

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        mp={} # for union find
        ans=0
        
        def find(a):
            if a not in mp: mp[a]=a
            if mp[a]!=a:
                mp[a]=find(mp[a])
            return mp[a]
            
        def union(a,b): # b is smaller
            pa=find(a)
            pb=find(b)
            if pa!=pb:
                mp[pa]=pb
            
        for a in A:
            for factor in self.primes_set(a):
                union(a,factor)
        return collections.Counter([find(a) for a in A]).most_common(1)[0][1]
    
    def primes_set(self,n): # much fast using this primes set
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self.primes_set(n//i) | set([i])
        return set([n])                

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        import math
        n = len(A)
        G = collections.defaultdict(set)
        def get_prime_list(target):
            dest = int(math.sqrt(target))
            target_list = list(range(2, target + 1))
            prime_list = []

            while True:
                num_min = min(target_list)
                if num_min >= dest:
                    prime_list.extend(target_list)
                    break
                prime_list.append(num_min)


                i = 0

                while True:
                    if i >= len(target_list):
                        break
                    elif target_list[i] % num_min == 0:
                        target_list.pop(i)
                    i += 1

            return prime_list
        def primes_set(n):
            for i in range(2, int(math.sqrt(n))+1):
                if n % i == 0:
                    return primes_set(n//i) | set([i])
            return set([n])
        #primes = get_prime_list(min(100000,max(A)))
        #primes = primes_set
        def find(x):
            if p[x] != x:
                p[x] = find(p[x])
            return p[x]
        def union(x,y):
            x = find(x)
            y = find(y)
            p[y] = x
            
        for a in A:
            G[a] = set()
        pdic = collections.defaultdict(set)
        p = list(range(len(A)))
        for idx,i in enumerate(A):
            for j in primes_set(i):
                    pdic[j].add(idx)
        for k,v in  list(pdic.items()):
            n = len(v)
            tmp = list(v)
            for i in range(n-1):
                union(tmp[i],tmp[i+1])  
        tmp = []
        for i in range(len(A)):
            tmp.append(find(i))
        c = Counter(tmp)
        return max(c.values())
                    


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        f = {}
        
        def find(x):
            f.setdefault(x,x)
            if x != f[x]:
                f[x] = find(f[x])
            
            return f[x]
        
        def union(x,y):
            px, py = find(x), find(y)
            if px != py:
                f[px] = py
        
        #we can break down any number into prime divisors mutiplication
        
        def get_primes(n):
            for i in range(2, int(sqrt(n))+1):
                if n % i == 0:
                    return get_primes(n//i) | {i}
            
            return {n}
        
        primes_dict = collections.defaultdict(list)
        
        for i,a in enumerate(A):
            primes = get_primes(a)
            
            for p in primes:
                primes_dict[p].append(i)
        
        for k,indexes in list(primes_dict.items()):
            for j in range(len(indexes)-1):
                union(indexes[j],indexes[j+1])
        
        return max(collections.Counter(find(i) for i in range(len(A))).values())
        
        
            


        
class DSU:
    def __init__(self, N):
        self.p = list(range(N))
        
    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]
    
    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr
        
        
class Solution:
    def findPrime(self, n):
        for i in range(2, int(math.sqrt(n)) + 1):
            if n % i == 0:
                return self.findPrime(n//i) | set([i])
        return set([n])
    
    
    def largestComponentSize(self, A: List[int]) -> int:
        n = len(A)
        uf = DSU(n)
        primes = defaultdict(list)
        for i, num in enumerate(A):
            pset = self.findPrime(num)
            for q in pset:
                primes[q].append(i)
        
        for _, indexes in list(primes.items()):
            for i in range(len(indexes) - 1):
                uf.union(indexes[i], indexes[i+1])
        return max(Counter([uf.find(i) for i in range(n)]).values())
        
        

        


class DSU:
    def __init__(self, N):
        self.p = list(range(N))
        
    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]
    
    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr

class Solution:
    def primes_set(self, d):
        for i in range(2, int(math.sqrt(d)) + 1):
            if d % i == 0:
                return self.primes_set(d // i) | set([i])
        return set([d])
    
    def largestComponentSize(self, A: List[int]) -> int:
        n = len(A)
        UF = DSU(n)
        primes = defaultdict(list)
        for i, num in enumerate(A):
            pr_set = self.primes_set(num)
            for q in pr_set: primes[q].append(i)
            
        for _, indexes in primes.items():
            for i in range(len(indexes) - 1):
                UF.union(indexes[i], indexes[i + 1])
        
        return max(Counter([UF.find(i) for i in range(n)]).values())

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        uf = {}
        # rank
        
        def find(x):
            uf.setdefault(x, x)
            if uf[x] != x:
                uf[x] = find(uf[x])
            return uf[x]
        
        def union(x, y):
            uf[find(x)] = find(y)
            
        def primeFactor(x):
            ans = set()
            if not x % 2:
                ans.add(2)
                while not x % 2:
                    x //= 2
            for k in range(3, int(sqrt(x)) + 1, 2):
                if not x % k:
                    ans.add(k)
                while not x % k:
                    x //= k
                if x == 1:
                    break
            if x > 1:
                ans.add(x)
            return ans
                
        # dic = {}
        for a in A:
            for k in primeFactor(a):
                # dic.setdefault(k, a)
                union(a, k)
        return max(Counter([find(a) for a in A]).values())

class DSU:
    def __init__(self, n):
        self.parent = list(range(n))

    def find(self, target):
        if self.parent[target] != target:
            self.parent[target] = self.find(self.parent[target])
        return self.parent[target]

    def union(self, c, p):
        self.parent[self.find(c)] = self.find(p)

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        dsu = DSU(len(A))
        
        def prime_factorize(n):
            for i in range(2, int(sqrt(n))+1):
                if n%i == 0:
                    return [i] + prime_factorize(n//i)
            return [n]
        
        prime2indices = defaultdict(list)
        
        for i, n in enumerate(A):
            for p in prime_factorize(n):
                prime2indices[p].append(i)
        
        for arr in list(prime2indices.values()):
            for i in range(1, len(arr)):
                dsu.union(arr[0], arr[i])
        
        aggregate = defaultdict(int)
        
        for i in range(len(A)):
            aggregate[dsu.find(i)] += 1
        
        return max(aggregate.values())


import collections as clc
import math
import time


class UnionFind:
    
    def __init__(self, n: int):
        self.repr = list(range(n))
    
    def find(self, num: int) -> int:
        if num != self.repr[num]:
            self.repr[num] = self.find(self.repr[num])
        return self.repr[num]
    
    def union(self, num1: int, num2: int) -> bool:
        r1 = self.find(num1)
        r2 = self.find(num2)
        if r1 == r2:
            return False
        self.repr[r2] = r1
        return True


class Solution:
    
    def decompose(self, n: int) -> List[int]:
        ans = []
        max_prime = int(math.sqrt(n))
        if n % 2 == 0:
            ans.append(2)
            while n % 2 == 0:
                n //= 2
        prime = 3
        while prime <= max_prime:
            if n % prime == 0:
                ans.append(prime)
                while n % prime == 0:
                    n //= prime
            prime += 2
        if n != 1:
            ans.append(n)
        return ans
    
    def largestComponentSize(self, A: List[int]) -> int:
        n = len(A)
        M = max(A)
        node_lists = clc.defaultdict(list)
        for idx, a in enumerate(A):
            for prime in self.decompose(a):
                node_lists[prime].append(idx)
        uf = UnionFind(n)
        for nodes in node_lists.values():
            if len(nodes) <= 1:
                continue
            idx1 = nodes[0]
            for idx2 in nodes[1:]:
                uf.union(idx1, idx2)
        return max(clc.Counter([uf.find(idx) for idx in range(n)]).values())

class DFU: 
    def __init__(self, n):
        self.p = list(range(n))
    
    def find(self, x):
        if self.p[x] != x: 
            self.p[x] = self.find(self.p[x])
        return self.p[x]
    
    def union(self, x, y): 
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr

class Solution:
    def prime_sets(self, n): 
        for i in range(2, int(math.sqrt(n)) + 1):
            if n % i == 0:
                return self.prime_sets(n // i) | set([i])
        return set([n]) 
    
    def largestComponentSize(self, A: List[int]) -> int:
        UF = DFU(len(A))
        primes = collections.defaultdict(list) 
        
        for i, n in enumerate(A):
            prime_set = self.prime_sets(n) 
            for q in prime_set: primes[q].append(i) 
        
        for _, items in primes.items():
            for i in range(len(items) - 1):
                UF.union(items[i], items[i + 1])
        
        return max(Counter([UF.find(i) for i in range(len(A))]).values())

class DSU:
    def __init__(self, n):
        self.p = list(range(n))
        
    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]
    
    def union(self, x, y):
        x1, y2 = self.find(x), self.find(y)
        self.p[x1] = y2       

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def get_factor_primes(n):
            for i in range(2, int(n**(1/2))+1):
                if n%i == 0:
                    return set([i]).union(get_factor_primes(n//i))
            return set([n])
        
        #hash index to prim numbers
        prime = defaultdict(list)
        
        for i, n in enumerate(A):
            primeset = get_factor_primes(n)
            for p in primeset:
                prime[p].append(i)
                
        #create DSU for all common prime sets
        N = len(A)
        dsu = DSU(N)
        
        for _, indexes in list(prime.items()):
            for i in range(len(indexes)-1):
                dsu.union(indexes[i], indexes[i+1])
                
        #return max count
        return max(Counter([dsu.find(i) for i in range(N)]).values())
                
                


class Solution:

    def largestComponentSize(self, A: List[int]) -> int:
        parent = {}
        size = defaultdict(lambda: 1)

        def ds(a):
            while a in parent:
                a = parent[a]
            return a

        def union(a, b):
            if (a := ds(a)) != (b := ds(b)):
                if size[a] < size[b]:
                    a, b = b, a
                parent[b] = a
                size[a] += size[b]
            return a

        for a in A:
            for d in factors(a):
                union(-d, a)

        return Counter(ds(a) for a in A).most_common(1)[0][1]


primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
          73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
          157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233,
          239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317]
FS = {n: {n} for n in primes}
FS[1] = {}


def factors(f):
    if (n := f) not in FS:
        if n & 1:
            FS[f] = factors3(f)
        else:
            n >>= 1
            while n & 1 == 0:
                n >>= 1
            if n == 1:
                FS[f] = {2}
            else:
                FS[f] = {2} | factors3(n)

    return FS.get(f, set())


def factors3(f, start=3):
    if (n := f) not in FS:
        for i in range(start, int(sqrt(n)) + 1, 2):
            if n % i == 0:
                n = n // i
                while n % i == 0:
                    n = n // i
                if n == 1:
                    FS[f] = {i}
                else:
                    FS[f] = {i} | factors3(n, i + 2)
                break
        else:
            FS[f] = {f}

    return FS[f]


class DisjointSet:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [0 for i in range(n)]
        
    def GetParent(self, i):
        if self.parent[i] != i:
            self.parent[i] = self.GetParent(self.parent[i])
            
        return self.parent[i]
    
    def Union(self, i, j):
        i_idx = self.GetParent(i)
        j_idx = self.GetParent(j)
        
        if j_idx == i_idx:
            return
        
        if self.rank[i_idx] > self.rank[j_idx]:
            self.parent[j_idx] = i_idx
        else:
            if self.rank[i_idx] == self.rank[j_idx]:
                self.rank[j_idx] += 1
            
            self.parent[i_idx] = j_idx
        

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def prime_set(n):
            for i in range(2, math.floor(math.sqrt(n)) + 1):
                if n % i == 0:
                    return prime_set(n // i) | set([i])
                    
            return set([n])
        
        ds = DisjointSet(len(A))
        
        primes = {}    
        
        for i in range(len(A)):
            curr_prime_set = prime_set(A[i])
            
            for prime in curr_prime_set:
                primes.setdefault(prime, [])
                primes[prime].append(i)
                
        for key in primes:
            for i in range(len(primes[key]) - 1):
                ds.Union(primes[key][i], primes[key][i + 1])
                
        set_counter = {}
        
        for i in range(len(A)):
            set_counter.setdefault(ds.GetParent(i), 0)
            set_counter[ds.GetParent(i)] += 1
            
        # print(set_counter)
        return max(set_counter.values())
        
        
#     def largestComponentSize(self, A: List[int]) -> int:
#         def gcd(a, b):
#             nonlocal gcd_hash
#             if (a, b) in gcd_hash:
#                 return gcd_hash[(a, b)]
            
#             if b == 0:
#                 return a
            
#             if a >= b:
#                 return gcd(b, a % b)
#             else:
#                 return gcd(a, b % a)
            
            
#         def Explore(u, adj_list, visited):
#             visited[u] = 1
            
#             for v in adj_list[u]:
#                 if not visited[v]:
#                     nonlocal cc_length
#                     cc_length += 1
#                     Explore(v, adj_list, visited)
                 
                
#         gcd_hash = {}
#         V = len(A)
#         adj_list = [[] for _ in range(V)]
        
#         for i in range(len(A)):
#             for j in range(i + 1, V):
#                 curr_gcd = gcd(A[i], A[j])
#                 gcd_hash[(A[i], A[j])] = curr_gcd
#                 gcd_hash[(A[j], A[i])] = curr_gcd
                
#                 if curr_gcd > 1:
#                     adj_list[i].append(j)
#                     adj_list[j].append(i)
        
#         # print(adj_list)
        
#         visited = [0 for _ in range(V)]
#         max_cc_length = 0
#         cc_num = 0
#         cc_length = 1
        
#         for i in range(V):
#             if not visited[i]:
#                 Explore(i, adj_list, visited)
#                 cc_num += 1
                
#                 if cc_length > max_cc_length:
#                     max_cc_length = cc_length
                
#                 cc_length = 1
                
#         # print(cc_num)
#         # print(max_cc_length)
        
#         return max_cc_length
                
                
                
        


class DSU:
    def __init__(self, N):
        self.p = list(range(N))
        self.r = [0] * N

    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        if self.r[xr] < self.r[yr]:
            self.p[xr] = yr
        else:
            self.p[yr] = xr
            self.r[xr] += self.r[yr]

class Solution:
    def primes_set(self,n):
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self.primes_set(n//i) | set([i])
        return set([n])

    def largestComponentSize(self, A):
        n = len(A)
        UF = DSU(n)
        primes = defaultdict(list)
        for i, num in enumerate(A):
            pr_set = self.primes_set(num)
            for q in pr_set: primes[q].append(i)

        for _, indexes in primes.items():
            for i in range(len(indexes)-1):
                UF.union(indexes[i], indexes[i+1])

        return max(Counter([UF.find(i) for i in range(n)]).values())

class DFU:
    def __init__(self, n):
        self.p = list(range(n))
        
    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]
    
    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr 

class Solution:
    def prime_sets(self, n):
        for i in range(2, int(math.sqrt(n)) + 1):
            if n % i == 0: 
                return self.prime_sets(n // i) | set([i])
        return set([n])
    
    def largestComponentSize(self, A: List[int]) -> int:
        UF = DFU(len(A))
        primes = collections.defaultdict(list)
        for i, n in enumerate(A): 
            prime_set = self.prime_sets(n)
            for q in prime_set: 
                primes[q].append(i) 
                
        for _, items in list(primes.items()): 
            for i in range(len(items) - 1):
                UF.union(items[i], items[i + 1])
                
        return max(Counter([UF.find(i) for i in range(len(A))]).values())


class Solution:

    def largestComponentSize(self, A: List[int]) -> int:
        parent = {}
        size = defaultdict(lambda: 1)

        def ds(a):
            while a in parent:
                a = parent[a]
            return a

        def union(a, b):
            if (a := ds(a)) != (b := ds(b)):
                if size[a] < size[b]:
                    a, b = b, a
                parent[b] = a
                size[a] += size[b]

        for a in A:
            for d in factors(a):
                union(-d, a)

        return Counter(ds(a) for a in A).most_common(1)[0][1]


primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
          73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
          157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233,
          239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317]
FS = {n: {n} for n in primes}


def factors(f):
    if (n := f) not in FS:
        if n & 1:
            FS[f] = factors3(f)
        else:
            n >>= 1
            while n & 1 == 0: n >>= 1
            FS[f] = {2} | factors3(n) if n > 1 else {2}
    return FS[f]


def factors3(f, start=3):
    if (n := f) not in FS:
        for i in range(start, int(sqrt(n)) + 1, 2):
            if n % i == 0:
                n = n // i
                while n % i == 0: n = n // i
                FS[f] = {i} | factors3(n, i + 2) if n > 1 else {i}
                break
        else:
            FS[f] = {f}
    return FS[f]


from collections import defaultdict
from collections import Counter

class DSU:
    def __init__(self, N):
        self.p = list(range(N))
        
    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]
    
    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr
        
class Solution:
    def primes_set(self, n):
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self.primes_set(n//i) | set([i])
        
        return set([n])
    
    def largestComponentSize(self, A):
        n = len(A)
        UF = DSU(n)
        
        primes = defaultdict(list)
        for i, num in enumerate(A):
            pr_set = self.primes_set(num)
            for q in pr_set: primes[q].append(i)
                
        for _, indexes in list(primes.items()):
            for i in range(len(indexes) -1 ):
                UF.union(indexes[i], indexes[i+1])
        
        return max(Counter([UF.find(i) for i in range(n)]).values())
            
            


class Solution1:
    def largestComponentSize(self, A):
        if not A: return 0
        def findAndCompact(l, i): # require i >= 0
            if l[i] == i: return i
            p = l[i]
            if p >= 0 and l[p] == p: return p
            while p >= 0 and l[p] != p:
                p = l[p]
            root = p
            
            # compact
            p = i
            while p >= 0 and l[p] != p:
                t = l[p]
                l[p] = root
                p = t
            return root
        
        slist = [-1] * len(A)
        d = {} # record prime->(root of union-find set)
        for i in range(len(A)):
            n = A[i]
            has_factor = False
            for j in range(2, int(sqrt(n)) + 1):
                if n % j == 0:
                    has_factor = True
                    k = n // j
                    #print(n, j, k)
                    ri = -1 if slist[i] < 0 else findAndCompact(slist, slist[i])
                    rj = -1 if j not in d else findAndCompact(slist, d[j])
                    rk = -1 if k not in d else findAndCompact(slist, d[k])
                    if ri < 0 and rj < 0 and rk < 0:
                        slist[i] = d[j] = d[k] = i
                    else:
                        mm = min([item for item in (ri, rj, rk) if item >= 0])
                        if slist[i] >= 0: slist[ri] = mm
                        if j in d: slist[rj] = mm
                        if k in d: slist[rk] = mm
                        slist[i] = d[j] = d[k] = mm
            if not has_factor: #prime
                if A[i] not in d: slist[i] = d[A[i]] = i
                else: slist[i] = d[A[i]]
            #print(slist, d)
        
        for i in range(len(A)): findAndCompact(slist, i)
        #print('### ', slist)
        cc = Counter(slist)
        m = cc.most_common(2)
        return m[0][1] if m[0][0] != -1 else m[1][1]
    
class DSU:
    def __init__(self, N):
        self.p = list(range(N))

    def find(self, x):
        n = self.p[x]
        while n >= 0 and self.p[n] != n:
            n = self.p[n]
        root = n
        # compact
        n = x
        while n >= 0 and self.p[n] != n:
            t = self.p[n]
            self.p[n] = root
            n= t
        return root

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr

class Solution:
    def primes_set(self,n):
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self.primes_set(n//i) | set([i])
        return set([n])

    def largestComponentSize(self, A):
        n = len(A)
        UF = DSU(n)
        primes = defaultdict(list)
        for i, num in enumerate(A):
            pr_set = self.primes_set(num)
            for q in pr_set: primes[q].append(i)

        for _, indexes in primes.items():
            for i in range(len(indexes)-1):
                UF.union(indexes[i], indexes[i+1])

        return max(Counter([UF.find(i) for i in range(n)]).values())

from collections import defaultdict


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        small_primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997]
        label = defaultdict(int)
       
        def findRoot(key):
            if label[key] > 0:
                label[key] = findRoot(label[key])
                return label[key]
            else:
                return key
        
        def mergeRoot(k1, k2):
            r1, r2 = findRoot(k1), findRoot(k2)
            if r1 != r2:
                r1, r2 = min(r1, r2), max(r1, r2)
                label[r1] += label[r2]
                label[r2] = r1
            return r1

        for x in A:
            root_id = 0
            for p in small_primes:
                if p >= x:
                    break
                if x % p == 0:
                    root_id = findRoot(p) if root_id == 0 else mergeRoot(root_id, p)
                    while x % p == 0:
                        x //= p
            if x != 1:
                root_id = findRoot(x) if root_id == 0 else mergeRoot(root_id, x)
            label[root_id] -= 1
        
        return -min(label.values())

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        uf = {}
        
        def find(x):
            uf.setdefault(x, x)
            if uf[x] != x:
                uf[x] = find(uf[x])
            return uf[x]
        
        def union(x, y):
            uf[find(x)] = find(y)
            
        for i, a in enumerate(A):
            if not a % 2:
                union(A[i], 2)
            while not a % 2:
                a //= 2
            for k in range(3, int(sqrt(A[i])) + 1, 2):
                if not a % k:
                    union(A[i], k)
                while not a % k:
                    a //= k
                if a == 1:
                    break
            if a > 1:
                union(A[i], a)
        return max(Counter([find(a) for a in A]).values())

class DSU:
    def __init__(self, N):
        self.p = list(range(N))

    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr

class Solution:
    def primes_set(self,n):
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self.primes_set(n//i) | set([i])
        return set([n])

    def largestComponentSize(self, A):
        n = len(A)
        UF = DSU(n)
        primes = defaultdict(list)
        for i, num in enumerate(A):
            pr_set = self.primes_set(num)
            for q in pr_set: primes[q].append(i)

        for _, indexes in list(primes.items()):
            for i in range(len(indexes)-1):
                UF.union(indexes[i], indexes[i+1])

        return max(Counter([UF.find(i) for i in range(n)]).values())


class DUSNode:
    def __init__(self, parent):
        self.parent = parent
        self.size = 0

class DisjointUnionSet:
    def __init__(self):
        self.forest = {}
        
    def addSet(self, node, key):
        self.forest[key] = node
        
    def find(self, p):
        while self.forest[p].parent != p:
            self.forest[p].parent = self.forest[self.forest[p].parent].parent
            p = self.forest[p].parent
            
        return p
    
    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)
        
        if x != y:
            if self.forest[x].size < self.forest[y].size:
                x, y = y, x
                
            self.forest[y].parent = x
            self.forest[x].size += self.forest[y].size
            

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        composites = set()
        primes = []
        prime_factors = {k:v for k, v in zip(A, [[] for _ in range(len(A))])}
        maxA = max(A)
        for n in range(2, maxA + 1):
            if n not in composites:
                primes.append(n)
                m = n
                while m <= maxA:
                    composites.add(m)
                    if m in prime_factors:
                        prime_factors[m].append(n)
                        
                    m += n
                    
        djus = DisjointUnionSet()            
        for p in primes:
            djus.addSet(DUSNode(p), p)
        
        for pf in list(prime_factors.values()):
            if pf:
                djus.forest[djus.find(pf[0])].size += 1
                
            for p1, p2 in zip(pf, pf[1:]):
                djus.union(p1, p2)
                    
        return max([node.size for node in list(djus.forest.values())])


from math import sqrt
from collections import defaultdict, Counter

def get_prime_factors(n):
    for i in range(2, int(sqrt(n) + 1)):
        if n % i == 0:
            return {i} | get_prime_factors(n // i)
    return {n}


class Solution:
    def largestComponentSize(self, A):
        prime_multiples_map = defaultdict(list)
        for v in A:
            for factor in get_prime_factors(v):
                prime_multiples_map[factor].append(v)

        dsu = DSU(A)

        for vertices in list(prime_multiples_map.values()):
            last = vertices[0]
            for v in vertices:
                dsu.union(last, v)
            
        parents = [dsu.find(v) for v in A]

        counter = Counter(parents)
        return counter.most_common(1)[0][1]

class DSU:
    def __init__(self, nums):
        self.p = { n : n for n in nums }

    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]

    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        if px != py:
            self.p[px] = py


class DFU:
    def __init__(self, n):
        self.p = list(range(n))
        
    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]
    
    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr

class Solution:
    def prime_sets(self, n):
        for i in range(2, int(math.sqrt(n)) + 1):
            if n % i == 0:
                return self.prime_sets(n // i) | set([i])
        return set([n])
    
    def largestComponentSize(self, A: List[int]) -> int:
        UF = DFU(len(A))
        primes = collections.defaultdict(list)
        
        for i, n in enumerate(A):
            prime_set = self.prime_sets(n)
            for q in prime_set: primes[q].append(i)
                
        for _, items in primes.items():
            for i in range(len(items) - 1):
                UF.union(items[i], items[i + 1])
                
        return max(Counter([UF.find(i) for i in range(len(A))]).values())

class DisjSet:
    def __init__(self, n ):
        self.disj_set = [-1] * n
        
    def find(self, x):
        while self.disj_set[x] >= 0:
            x = self.disj_set[x]
        return x
    
    def union(self, x, y):
        i = self.find(x)
        j = self.find(y)
        if i == j:
            return
        if self.disj_set[i] < self.disj_set[j]:
            self.disj_set[i] += self.disj_set[j]
            self.disj_set[j] = i
        else:
            self.disj_set[j] += self.disj_set[i]
            self.disj_set[i] = j
    
    def maxset(self):
        return -min(self.disj_set)
    
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def gen_primes(n):
            candidates = [1] * n
            for i in range(2, int(math.sqrt(n)) + 1):
                if candidates[i]:
                    for j in range(i ** 2, n, i):
                        candidates[j] = 0
            return [i for i in range(2, n) if candidates[i]]
        primes = gen_primes(int(math.sqrt(max(A))) + 1)
        def factor(n):
            result = []
            for i in primes:
                if i * i > n:
                    break
                if n % i == 0:
                    result.append(i)
                    while n % i == 0:
                        n //= i
            result.append(n)
            return result
        n = len(A)
        disj = DisjSet(n)
        g = {}
        for i, a in enumerate(A):
            factors = factor(a)
            for f in factors:
                if f == 1:
                    continue
                if f not in g:
                    g[f] = i
                else:
                    disj.union(i, g[f])
        return disj.maxset()

import math

class UnionFind:
    
    def __init__(self, n):
        self.data = list(range(n))
        self.size = [1] * n
        
    def find(self, x):
        if self.data[x] != x:
            self.data[x] = self.find(self.data[x])
        return self.data[x]
    
    def union(self, x, y):
        ix, iy = self.find(x), self.find(y)
        if ix != iy:
            self.data[ix] = iy
            self.size[iy] += self.size[ix]
            self.size[ix] = 0


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        def prime_set(num):
            res = set()
            while num % 2 == 0:
                res.add(2)
                num //= 2
            for i in range(3, int(math.sqrt(num)) + 1, 2):
                while num % i == 0:
                    res.add(i)
                    num //= i
            if num > 2:
                res.add(num)
            return res
        
        n = len(A)
        uf = UnionFind(n)
        primes_dict = collections.defaultdict(list)
        for i, num in enumerate(A):
            pr_set = prime_set(num)
            for p in pr_set:
                primes_dict[p].append(i)
        for indices in primes_dict.values():
            for j in range(1, len(indices)):
                uf.union(indices[j - 1], indices[j])
                
        return max(uf.size)
        
        
    def gcd_with_bfs(self, A: List[int]) -> int:
        graph = collections.defaultdict(set)
        
        for i in range(len(A)):
            for j in range(i, len(A)):
                if math.gcd(A[i], A[j]) > 1:
                    graph[A[i]].add(A[j])
                    graph[A[j]].add(A[i])
        
        res = 0
        seen = set()
        for a in A:
            if a not in seen:
                node_count = 0
                q = collections.deque([a])
                seen.add(a)
                while q:
                    node = q.popleft()
                    node_count += 1
                    seen.add(node)
                    for child in graph[node]:
                        if child not in seen:
                            seen.add(child)
                            q.append(child)
                res = max(res, node_count)
        return res

from collections import defaultdict
small_primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997]

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        label = defaultdict(int)
        def findRoot(key):
            if label[key] > 0:
                label[key] = findRoot(label[key])
                return label[key]
            else:
                return key
        
        def mergeRoot(k1, k2):
            r1, r2 = findRoot(k1), findRoot(k2)  
            if r1 != r2:
                r1, r2 = min(r1, r2), max(r1, r2)
                label[r1] += label[r2]
                label[r2] = r1
            return r1

        for x in A:
            root_id = 0
            for p in small_primes:
                if x % p == 0:
                    root_id = findRoot(p) if root_id == 0 else mergeRoot(root_id, p)
                    while x % p == 0:
                        x //= p
            if x != 1:
                root_id = findRoot(x) if root_id == 0 else mergeRoot(root_id, x)
            label[root_id] -= 1
        
        return -min(label.values())
    


class DUS(object):
    
    def __init__(self, n):
        self.p = [ *list(range(n)) ]
        self.size = [1] * n
        
    def Find(self, x):
        if self.p[x] == x:
            return x
        tmp = []
        while self.p[x] != x:
            tmp.append(x)
            x = self.p[x]
        for t in tmp:
            self.p[t] = x
        return x
    
    def Union(self, x, y):
        xr = self.Find(x)
        yr = self.Find(y)
        if xr != yr:
            self.p[yr] = xr
            self.size[xr] += self.size[yr]
            self.size[yr] = 0
        return 
    

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        def PFD(num):
            ret = set()
            if num % 2 == 0:
                ret.add(2)
                while num % 2 == 0:
                    num //= 2
            for i in range(3, int(num ** 0.5)+1 , 2 ):
                if num % i == 0:
                    ret.add(i)
                    while num % i == 0:
                        num //= i
            if num > 2:
                ret.add(num)
            return ret
        
        dic = {}
        dus = DUS(len(A))
        for idx, a in enumerate(A):
            for p in PFD(a):
                if p in dic:
                    dus.Union(dic[p], idx)
                dic[p] = idx
        
        return max(dus.size)
        
        


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        N = len(A)
        p = [i for i in range(N)]
        def uf(i):
            if i == p[i]: return i
            p[i] = uf(p[i])
            return p[i]
        
        dt = collections.defaultdict(set)
        def prime_factor(index):
            i = A[index]
            while i % 2 == 0: 
                dt[2].add(index)
                i //= 2
            for j in range(3, int(A[index]**0.5) + 1, 2):
                while i % j == 0:
                    dt[j].add(index)
                    i //= j
            if i > 2: dt[i].add(index)
                
        cnt = collections.defaultdict(int)
        
        for i in range(N): 
            prime_factor(i)
        
        for _, v in list(dt.items()):
            pi = uf(v.pop())
            while v:
                pj = uf(v.pop())
                p[pj] = pi
                
        res = 1
        for i in range(N):
            pi = uf(i)
            cnt[pi] += 1
            res = max(res, cnt[pi])
        return res


import sys

class Solution:
    def largestComponentSize(self, a: List[int]) -> int:
        sys.setrecursionlimit(9000000);
        
        def unify(x: int, y: int):
            f1 = getfa(x);
            f2 = getfa(y);
            if f1 != f2:
                if fa[f1] < fa[f2]:
                    fa[f1] += fa[f2];
                    fa[f2] = f1;
                else:
                    fa[f2] += fa[f1];
                    fa[f1] = f2;
                
        def getfa(x: int) -> int:
            i = x;
            while fa[i] >= 0:
                i = fa[i];
            
            j = i;
            i = x;
            while fa[i] >= 0:
                fa[i], i = j, fa[i];
                
            return j;
        
        n = len(a);
        flag = dict();
        fa = [-1] * n;
        ans = 1;
        
        for i in range(0, n):
            v = a[i];
            if v % 2 == 0:
                if 2 not in flag:
                    flag[2] = i;
                else:
                    unify(flag[2], i);
                while v % 2 == 0:
                    v >>= 1;
                
            j = 3
            lim = int(sqrt(v))+1;
            
            while j <= lim and j <= v:
                if v % j:
                    j += 2;
                    continue;
                
                if j not in flag:
                    flag[j] = i;
                else:
                    unify(flag[j], i);
                    
                while v % j == 0:
                    v //= j;
                j += 2;
            
            if v > 1:
                if v not in flag:
                    flag[v] = i;
                else:
                    unify(flag[v], i);
                
        for i in range(0, n):
            if fa[i] < 0:
                ans = max(ans, -fa[i]);

        return ans;


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        par = [-1] * 100001
        def _find(x):
            if par[x] == -1:
                return x
            
            par[x] = _find(par[x])
            return par[x]
        
        def _union(x,y):
            xp = _find(x)
            yp = _find(y)
            if xp != yp:
                par[yp] = xp
                
        for x in A:
            for i in range(2, int(sqrt(x)) + 1):
                if x%i == 0:
                    _union(i,x)
                    _union(x, x//i)
                    
        count = 0;
        cache = {}
        for x in A:
            xp = _find(x)
            count = max(count, 1+cache.get(xp,0))
            cache[xp] = 1 + cache.get(xp,0)
        return count


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def get_factors(n):
            factors = set()
            while n % 2 == 0:
                factors.add(2)
                n //= 2
            for i in range(3, int(math.sqrt(n)) + 1, 2):
                while n % i == 0:
                    factors.add(i)
                    n //= i
            if n > 2:
                factors.add(n)
            return factors
        
        roots = [i for i in range(len(A))]
        
        def find_root(i):
            while i != roots[i]:
                roots[i] = roots[roots[i]]
                i = roots[i]
            return i
        
        primes = defaultdict(list)
        
        for i in range(len(A)):
            factors = get_factors(A[i])
            for n in factors:
                primes[n].append(i)
        
        for values in list(primes.values()):
            for i in range(len(values) - 1):
                roots[find_root(values[i + 1])] = roots[find_root(values[i])]
                
        ans = 0
        counter = defaultdict(int)
        
        for i in range(len(roots)):
            counter[find_root(i)] += 1
            ans = max(ans, counter[find_root(i)])
        
        return ans


class DisjSet:
    def __init__(self, n ):
        self.disj_set = [-1] * n
        self.sizes = [1] * n
        
    def find(self, x):
        while self.disj_set[x] >= 0:
            x = self.disj_set[x]
        return x
    
    def union(self, x, y):
        i = self.find(x)
        j = self.find(y)
        if i == j:
            return
        if self.disj_set[i] < self.disj_set[j]:
            self.disj_set[j] = i
            self.sizes[i] += self.sizes[j]
            self.sizes[j] = 0
        else:
            if self.disj_set[i] == self.disj_set[j]:
                self.disj_set[j] -= 1
            self.disj_set[i] = j
            self.sizes[j] += self.sizes[i]
            self.sizes[i] = 0
    
    def maxset(self):
        return max(self.sizes)
    
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def gen_primes(n):
            candidates = [1] * n
            for i in range(2, int(math.sqrt(n)) + 1):
                if candidates[i]:
                    for j in range(i ** 2, n, i):
                        candidates[j] = 0
            return [i for i in range(2, n) if candidates[i]]
        primes = gen_primes(int(math.sqrt(max(A))) + 1)
        def factor(n):
            result = []
            for i in primes:
                if i * i > n:
                    break
                if n % i == 0:
                    result.append(i)
                    while n % i == 0:
                        n //= i
            result.append(n)
            return result
        n = len(A)
        disj = DisjSet(n)
        g = {}
        for i, a in enumerate(A):
            factors = factor(a)
            for f in factors:
                if f == 1:
                    continue
                if f not in g:
                    g[f] = i
                else:
                    disj.union(i, g[f])
        return disj.maxset()

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        if not A: return 0
        root = list(range(max(A) + 1))
        def find(i):
            while not root[i] == i:
                root[i] = root[root[i]] # path compress to reduce test time, since we need to do dfs to get the root, so we can find the current root and set previous to this one, repeat it till get the final root we wanted
                i = root[i]
            return i
        def union(a, i):
            root[find(a)] = root[find(i)]
        
        for a in A:
            for i in range(2, int(math.sqrt(a)) + 1):
                if not a % i:
                    union(a, i)
                    union(a, a // i)
                    
        # for a in A:
        #     dic[find(a)] += 1
        #     res = max(res, dic[find(a)])
        # return res
        return Counter([find(a) for a in A]).most_common(1)[0][1]


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def factors(x):
            sq = int(x**0.5)
            f = set()
            for i in range(2,sq+1):
                while x%i == 0:
                    x //= i 
                    f.add(i)
            if x > 1:
                f.add(x)
            return f 

        n = len(A)
        parent = [i for i in range(n)]
        sz = [1]*n 
        mp = {}
        def find(x):
            if parent[x] != x:
                parent[x] = find(parent[x])
            return parent[x]
        def union(x,y):
            rx, ry = find(x), find(y)
            if rx != ry:
                parent[rx] = ry
                sz[ry] += sz[rx]
        for i, a in enumerate(A):
            fs = factors(a)
            # print(a,fs,mp)
            for f in fs:
                if f in mp:
                    j = mp[f]
                    union(j,i)
                mp[f] = i 
        # print(parent,mp)
        return max(sz)


class Solution:

    def largestComponentSize(self, A: List[int]) -> int:
        x = defaultdict(list)

        def _locate(n):
            if not x[n]:
                return n
            x[n] = _locate(x[n])
            return x[n]

        def _isCommon(n, m):
            np = _locate(n)
            mp = _locate(m)
            if np != mp:
                x[mp] = np

        for n in A:
            for i in range(2, int(sqrt(n)) + 1):
                if not n % i:
                    _isCommon(i, n)
                    _isCommon(n, n // i)
        c = 0
        cache = {}
        for n in A:
            np = _locate(n)
            c = max(c, 1 + cache.get(np, 0))
            cache[np] = 1 + cache.get(np, 0)
        return c


class FU:
        def __init__(self, n):
            self.p = [i for i in range(n)]
            
        def find(self, x):
            if self.p[x] != x:
                self.p[x] = self.find(self.p[x])
            return self.p[x]
        
        def union(self, x, y):
            px, py = self.find(x), self.find(y)
            self.p[py] = px
        
class Solution:
    def primeFactors(self,n):
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self.primeFactors(n//i) | set([i])
        return set([n])
    
    def largestComponentSize(self, A: List[int]) -> int:
        fu = FU(len(A))
        primes = defaultdict(list)
        for i in range(len(A)):
            prime = self.primeFactors(A[i])
            # print(A[i])
            # print(prime)
            for pr in prime:
                primes[pr].append(i)
        # print(primes)
        for k, v in list(primes.items()):
            for i in range(len(v)-1):
                fu.union(v[i], v[i+1])
        c = Counter([fu.find(i) for i in range(len(A))])
        # print(c)
        return max(c.values())
        


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        L = max(A) + 5
        spf = [i for i in range(L)]
        for p in range(2, L):
            if spf[p] != p:
                continue
            for i in range(p * p, L, p):
                spf[i] = min(spf[i], p)
        def primes(n):
            while n > 1:
                yield spf[n]
                n //= spf[n]
        rep = [i for i in range(L)]
        sz = [0] * L
        def find(x):
            if rep[x] != x:
                rep[x] = find(rep[x])
            return rep[x]
        def union(x, y):
            rx = find(x)
            ry = find(y)
            if rx == ry:
                return
            rep[rx] = ry
            sz[ry] += sz[rx]
        for x in A:
            if x < 2:
                continue
            ps = list(primes(x))
            sz[find(ps[0])] += 1
            for i in range(len(ps) - 1):
                union(ps[i], ps[i + 1])
                #print(\"union between %d,%d\" % (ps[i], ps[i+1]))
                #print(\"new size: \", sz[find(ps[i])])
        #rint(rep)
        #print(sz)
        return max(sz)

class DisjSet:
    def __init__(self, n ):
        self.disj_set = [-1] * n
        
    def find(self, x):
        while self.disj_set[x] >= 0:
            x = self.disj_set[x]
        return x
    
    def union(self, x, y):
        i = self.find(x)
        j = self.find(y)
        if i == j:
            return
        if self.disj_set[i] < self.disj_set[j]:
            self.disj_set[i] += self.disj_set[j]
            self.disj_set[j] = i
        else:
            self.disj_set[j] += self.disj_set[i]
            self.disj_set[i] = j
    
    def maxset(self):
        return -min(self.disj_set)

def gen_primes(n):
    candidates = [1] * n
    for i in range(2, int(math.sqrt(n)) + 1):
        if candidates[i]:
            for j in range(i ** 2, n, i):
                candidates[j] = 0
    return [i for i in range(2, n) if candidates[i]]
primes = gen_primes(320)

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def factor(n):
            result = set()
            for i in primes:
                if i * i > n:
                    break
                if n % i == 0:
                    result.add(i)
                    while n % i == 0:
                        n //= i
            result.add(n)
            return result
        n = len(A)
        disj = DisjSet(n)
        g = {}
        for i, a in enumerate(A):
            for f in factor(a):
                if f == 1:
                    continue
                if f not in g:
                    g[f] = i
                else:
                    disj.union(i, g[f])
        return disj.maxset()

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        #GOOGLE - Union Find Alg
        #For graph approach (DFS) it will work for a small input. In worst case we will have 20K elem
        #and we will need to do 20K^2=20*20*10^6 coparison if two num has a common factor. 
        #Time limit will exceed. Therefore use Union Find here.
        parent = [-1] * 100001
        
        def find(x):
            if parent[x] == -1:
                return x
            parent[x] = find(parent[x])
            return parent[x]
    
        def union(x,y):
            xp=find(x)
            yp=find(y)
            if xp != yp:
                parent[yp] = xp
        
        for x in A:
            for i in range(2, int(sqrt(x))+1):
                if x % i == 0:
                    union(i,x)
                    union(x, x//i)
        
        count = 0
        hashmap = {}
        for x in A:
            xp = find(x)
            count = max(count, 1 + hashmap.get(xp, 0))
            hashmap[xp] = 1 + hashmap.get(xp, 0)
        return count
                    
        
        


class Solution:
    def find(self, i, parent):
        if parent[i] == -1:
            return i
        parent[i] = self.find(parent[i], parent)
        return parent[i]

    def union(self, i, j, parent):
        rooti = self.find(i, parent)
        rootj = self.find(j, parent)
        if rooti != rootj:
            parent[rooti] = rootj
            
    def largestComponentSize(self, A: List[int]) -> int:
        hm = defaultdict(int)
        parent = [-1] * (100001)
        for i in A:
            for j in range(2, int(sqrt(i)) +1):
                if i % j == 0:
                    self.union(i,j, parent)
                    self.union(i//j, i, parent)
        for i in A:
            parenti = self.find(i,parent)
            hm[parenti] += 1
        return max(hm.values())

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent=[-1]*100001
        def find(x):
            if parent[x] == -1:
                return x
            parent[x] = find(parent[x])
            return parent[x]
        def union(x,y):
            xp = find(x)
            yp = find(y)
            if xp != yp:
                parent[yp] = xp
                
            
        for x in A:
            for i in range(2,int(sqrt(x))+1):
                if x%i == 0:
                    union(i,x)
                    union(x,x//i)
                    
        count=0
        cache={}
        for x in A:
            xp = find(x)
            count = max(count, 1+cache.get(xp,0))
            cache[xp] = 1+cache.get(xp,0)
        return count


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        n = len(A)
        dic = defaultdict(list)
        
        def primefactor(x):
            s = []
            y = x
            if x % 2 == 0:
                s.append(2)
            while x%2 == 0:
                x //= 2
            for i in range(3,floor(sqrt(y))+1,2):
                if x % i == 0:
                    s.append(i)
                while x % i == 0:
                    x //= i
            if x > sqrt(y):
                s.append(x)
            return s
        
        for i in range(n):
            primes = primefactor(A[i])
            for d in primes:
                dic[d].append(i)
        a = list(range(n))
        sz = [1] * n
        
        def root(i):
            while(i != a[i]):
                a[i] = a[a[i]]
                i = a[i]
            return i
        
        def find(i,j):
            return root(i) == root(j)
            
        def union(i,j):
            root_i = root(i)
            root_j = root(j)
            if sz[root_i] > sz[root_j]:
                a[root_j] = root_i
                sz[root_i] += sz[root_j]
                sz[root_j] = 0
            else:
                a[root_i] = root_j
                sz[root_j] += sz[root_i]
                sz[root_i] = 0
            
        for v in dic.values():
            for i in range(len(v)-1):
                if find(v[i],v[i+1]) == False:
                    union(v[i],v[i+1])
        return max(sz)

from math import sqrt
from functools import reduce
from collections import defaultdict

class Disjoint():
    def __init__(self, N):
        self.parent = list(range(N))
        self.size = [1] * N

    def find(self, node):
        if self.parent[node] != node:
            self.parent[node] = self.find(self.parent[node])
        return self.parent[node]

    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        if px != py:
            sx, sy = self.size[px], self.size[py]
            if sx > sy:
                self.parent[py] = px
                self.size[px] += sy
            else:
                self.parent[px] = py
                self.size[py] += sx
                
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        if not A:   return 0
        
        
        fac_to_ind = defaultdict(int)
        un = Disjoint(len(A))
        for ind, num in enumerate(A):
            for fac in range(2, int(math.sqrt(num) + 1)):
                if num % fac:   continue
                for f in [fac, num // fac]:
                    if f not in fac_to_ind:
                        fac_to_ind[f] = ind
                    else:
                        un.union(ind, fac_to_ind[f])
            if num not in fac_to_ind:
                fac_to_ind[num] = ind
            else:
                un.union(ind, fac_to_ind[num])
        return max(un.size)

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313]
        unions = collections.defaultdict(set)
        for i, n in enumerate(A):
            for p in primes:
                if p * p > n:
                    break
                while not n % p:
                    n //= p
                    unions[p].add(i)
            if n > 1:
                unions[n].add(i)
        ids = list(range(len(A)))
        def find(i):
            if ids[i] != i:
                ids[i] = find(ids[i])
            return ids[i]
        def union(l):
            s = set(find(i) for i in l)
            i = s.pop()
            while s:
                j = s.pop()
                ids[j] = i
        for l in list(unions.values()):
            union(l)
        c = collections.Counter(find(i) for i in range(len(A)))
        return max(c.values())


from math import ceil, sqrt
from typing import List


class Solution:
    MAXN = 100001
    spf = [0 for i in range(MAXN)]

    def largestComponentSize(self, A: List[int]) -> int:
        spf = self.spf
        MAXN = self.MAXN

        def sieve():
            spf[1] = 1
            for i in range(2, MAXN):
                spf[i] = i
            for i in range(4, MAXN, 2):
                spf[i] = 2

            for i in range(3, ceil(sqrt(MAXN))):
                if spf[i] == i:
                    for j in range(i * i, MAXN, i):
                        if spf[j] == j:
                            spf[j] = i

        def getFactorization(x):
            ret = []
            while x != 1:
                if not ret or spf[x] != ret[-1]:
                    ret.append(spf[x])
                x = x // spf[x]

            return ret

        sieve()
        parents = {0: [0, 0]}

        def find(curr):
            if curr == parents[curr][0]:
                return curr
            return find(parents[curr][0])

        for i in range(len(A)):
            factors = getFactorization(A[i])
            parent = 0
            for f in factors:
                parents.setdefault(f, [f, 0])
                p = find(f)
                if parent != 0 and p != parent:
                    parents[parent][1] += parents[p][1]
                    parents[p][0] = parent
                    parents[p][1] = 0
                else:
                    parent = p

            parents[parent][1] += 1
        return max(list(parents.values()), key=lambda x: x[1])[1]



class Solution1:
    def largestComponentSize(self, A):
        if not A: return 0
        def findAndCompact(l, i): # require i >= 0
            if l[i] == i: return i
            p = l[i]
            if p >= 0 and l[p] == p: return p
            while p >= 0 and l[p] != p:
                p = l[p]
            root = p
            
            # compact
            p = i
            while p >= 0 and l[p] != p:
                t = l[p]
                l[p] = root
                p = t
            return root
        
        slist = [-1] * len(A)
        d = {} # record prime->(root of union-find set)
        for i in range(len(A)):
            n = A[i]
            has_factor = False
            for j in range(2, int(sqrt(n)) + 1):
                if n % j == 0:
                    has_factor = True
                    k = n // j
                    #print(n, j, k)
                    ri = -1 if slist[i] < 0 else findAndCompact(slist, slist[i])
                    rj = -1 if j not in d else findAndCompact(slist, d[j])
                    rk = -1 if k not in d else findAndCompact(slist, d[k])
                    if ri < 0 and rj < 0 and rk < 0:
                        slist[i] = d[j] = d[k] = i
                    else:
                        mm = min([item for item in (ri, rj, rk) if item >= 0])
                        if slist[i] >= 0: slist[ri] = mm
                        if j in d: slist[rj] = mm
                        if k in d: slist[rk] = mm
                        slist[i] = d[j] = d[k] = mm
            if not has_factor: #prime
                if A[i] not in d: slist[i] = d[A[i]] = i
                else: slist[i] = d[A[i]]
            #print(slist, d)
        
        for i in range(len(A)): findAndCompact(slist, i)
        #print('### ', slist)
        cc = Counter(slist)
        m = cc.most_common(2)
        return m[0][1] if m[0][0] != -1 else m[1][1]
    
class DSU:
    def __init__(self, N):
        self.p = list(range(N))

    def find(self, x):
        n = self.p[x]
        while n >= 0 and self.p[n] != n:
            n = self.p[n]
        root = n
        # compact
        n = x
        while n >= 0 and self.p[n] != n:
            t = self.p[n]
            self.p[n] = root
            n= t
        return root

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr

class Solution:
    def primes_set(self,n):
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self.primes_set(n//i) | set([i])
        return set([n])

    def largestComponentSize(self, A):
        n = len(A)
        UF = DSU(n)
        primes = defaultdict(list)
        for i, num in enumerate(A):
            pr_set = self.primes_set(num)
            for q in pr_set: primes[q].append(i)

        for _, indexes in primes.items():
            for i in range(len(indexes)-1):
                UF.union(UF.find(indexes[i]), UF.find(indexes[i+1]))

        return max(Counter([UF.find(i) for i in range(n)]).values())

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        amax = max(A)
        plist = [2]
        for k in range(3, int(sqrt(amax)) + 2, 2):
            for p in plist:
                if p * p > k:
                    plist.append(k)
                    break
                if k % p == 0: break
            else:
                plist.append(k)
        pset = set(plist)
        amax //= 2
        n = n1 = n2 = len(A)
        k = 0
        while k < n1:
            x = A[k]
            if x in pset:
                n1 -= 1
                n2 -= 1
                A[k] = A[n1]
                A[n2] = x
                continue
            if x < plist[-1]:
                k += 1
                continue
            prime = True
            for p in plist:
                if p * p > x: break
                if x % p == 0:
                    prime = False
                    break
            if not prime:
                k += 1
            else:
                n1 -= 1
                A[k] = A[n1]
                if x <= amax:
                    n2 -= 1
                    A[n2] = x
        ans = 1
        left = n - n2 + n1
        while left > ans and n1 > 0:
            n1 -= 1
            x = A[n1]
            found = False
            k = 0
            while k < n1:
                y = A[k]
                p = math.gcd(x, y)
                if p > 1:
                    found = True
                    n1 -= 1
                    A[k] = A[n1]
                    while p > 1:
                        y //= p
                        p = math.gcd(y, p)
                    x *= y
                else:
                    k += 1
                if k == n1 and found:
                    found = False
                    k = 0
            k = n - 1
            while k >= n2:
                if x % A[k] == 0:
                    A[k] = A[n2]
                    n2 += 1
                else:
                    k -= 1
            k = n - n2 + n1
            ans = max(ans, left - k)
            left = k
        return ans

import math

class DiscreteSet:
    def __init__(self, N):
        self.parent = [i for i in range(N)]
    
    def findP(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.findP(self.parent[x])
        return self.parent[x]
    
    def union(self, x, y):
        xp, yp = self.findP(x), self.findP(y)
        self.parent[xp] = yp

class Solution:
    def primesSet(self, n):
        for i in range(2, math.floor(math.sqrt(n))+1):
            if n % i == 0:
                return self.primesSet(n//i) | set([i])
        return set([n])
    
    def largestComponentSize(self, A: List[int]) -> int:
        dset = DiscreteSet(len(A))
        primes = defaultdict(list)
        
        for i, num in enumerate(A):
            prSet = self.primesSet(num)
            print((i,num,prSet))
            for pr in prSet: primes[pr].append(i)
        
        for indices in list(primes.values()):
            for i in range(len(indices)-1):
                dset.union(indices[i], indices[i+1])

        cnt = Counter()
        for i in range(len(A)):
            cnt[dset.findP(i)] += 1
        return max(cnt.values())


class DSU:
    def __init__(self, N):
        self.p = list(range(N))

    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr

class Solution:
    def primes_set(self,n):
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self.primes_set(n//i) | set([i])
        return set([n])

    def largestComponentSize(self, A):
        n = len(A)
        UF = DSU(n)
        primes = defaultdict(list)
        for i, num in enumerate(A):
            pr_set = self.primes_set(num)
            for q in pr_set: primes[q].append(i)

        for _, indexes in list(primes.items()):
            for i in range(len(indexes)-1):
                UF.union(indexes[i], indexes[i+1])

        return max(Counter([UF.find(i) for i in range(n)]).values())

# class Solution:
#     def largestComponentSize(self, A: List[int]) -> int:
#         graph = {}
#         for i in range(0, len(A)):
#             for j in range(i+1, len(A)):
#                 if self.check(A[i], A[j]):
#                     if A[i] not in graph:
#                         graph[A[i]] = [A[j]]
#                     else:
#                         graph[A[i]].append(A[j])
#                     if A[j] not in graph:
#                         graph[A[j]] = [A[i]]
#                     else:
#                         graph[A[j]].append(A[i])
#         self.visited = set()
#         self.total = 0
#         for node in graph:
#             self.visited.add(node)
#             self.traverse(node, graph, 0)
#         return self.total
    
#     def traverse(self, root, graph, count):
#         # if root in self.visited:
#         #     self.total = max(self.total, count)
#         #     return
#         # self.visited.add(root)
#         # for neigh in graph[root]:
#         #     self.traverse(neigh, graph, count + 1)
#         queue = [root]
#         while queue:
#             current = queue.pop(0)
#             count += 1
#             for neigh in graph[current]:
#                 if neigh not in self.visited:
#                     self.visited.add(neigh)
#                     queue.append(neigh)
#         self.total = max(self.total, count)
#         return
        
        
        
#     def check(self, num1, num2):
#         i = 2
#         while i <= num1:
#             if num2 % i == 0 and num1 % i == 0:
#                 return True
#             i += 1
#         return False


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent = [-1]* 100001;
        def _find(x):
            if parent[x] == -1:
                return x;
            parent[x] = _find(parent[x]);
            return parent[x];
        
        def _union(x,y):
            xp = _find(x);
            yp = _find(y);
            if xp != yp:
                parent[yp] = xp;
        for x in A:
            for i in range(2,int(sqrt(x))+1):
                if(x%i == 0):
                    _union(i,x);
                    _union(x, x//i);
        count = 0;
        cache = {};
        for x in A:
            xp  = _find(x);
            count = max(count, 1+cache.get(xp,0));
            cache[xp] = 1+cache.get(xp,0);
        return count;

class UnionFind(object):
    def __init__(self, n):  
        self.uf = [i for i in range(n)]
        self.size = [1] * n
        
    def find(self, x):  
        while self.uf[self.uf[x]] != self.uf[x]:
            self.uf[x] = self.uf[self.uf[x]]
        return self.uf[x]

    def union(self, x, y):  
        x_root = self.find(x)
        y_root = self.find(y)
        if x_root == y_root: return
        self.uf[x_root] = y_root
        self.size[y_root] += self.size[x_root]
        self.size[x_root] = 0


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def factors(n):
            ff = set()
            while n % 2 == 0: ff.add(2); n //= 2
            for i in range(3,int(math.sqrt(n))+1,2): 
                while n % i == 0: ff.add(i); n //= i
            if n > 2: ff.add(n)
            return ff
        
        uf = UnionFind(len(A))
        pti = {}
        for i, el in enumerate(A):
            primes = factors(el)
            for p in primes:
                if p in pti: uf.union(i, pti[p])
                pti[p] = i
        return max(uf.size)


class DisjSet:
    def __init__(self, n ):
        self.disj_set = [-1] * n
        
    def find(self, x):
        while self.disj_set[x] >= 0:
            x = self.disj_set[x]
        return x
    
    def union(self, x, y):
        i = self.find(x)
        j = self.find(y)
        if i == j:
            return
        if self.disj_set[i] < self.disj_set[j]:
            self.disj_set[i] += self.disj_set[j]
            self.disj_set[j] = i
        else:
            self.disj_set[j] += self.disj_set[i]
            self.disj_set[i] = j
    
    def maxset(self):
        return -min(self.disj_set)
    
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def gen_primes(n):
            candidates = [1] * n
            for i in range(2, int(math.sqrt(n)) + 1):
                if candidates[i]:
                    for j in range(i ** 2, n, i):
                        candidates[j] = 0
            return [i for i in range(2, n) if candidates[i]]
        primes = gen_primes(int(math.sqrt(max(A))) + 2)
        def factor(n):
            result = set()
            while n > 1:
                s = int(math.sqrt(n))
                f = True
                for i in primes:
                    if i > s:
                        break
                    if n % i == 0:
                        result.add(i)
                        while n % i == 0:
                            n //= i
                        f = False
                        break
                if f:
                    result.add(n)
                    break
            return result
        n = len(A)
        disj = DisjSet(n)
        g = {}
        for i, a in enumerate(A):
            factors = factor(a)
            for f in factors:
                if f == 1:
                    continue
                if f not in g:
                    g[f] = i
                else:
                    disj.union(i, g[f])
        return disj.maxset()

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        p = list(range(max(A) + 1))
       
        def find(x):
            while p[x] != x:
                p[x] = p[p[x]]
                x = p[x]
            return p[x]
    
        def union(x, y):
            p[find(x)] = p[find(y)]      
      
        for a in A:     
            for k in range(2, int(math.sqrt(a) + 1)):        
                if a % k == 0:
                    union(a, k)
                    union(a, a // k)
    
        return collections.Counter([find(a) for a in A]).most_common(1)[0][1]

from math import sqrt
from collections import Counter
class UnionFind:

    def __init__(self, length):
        self.array = [i for i in range(length)]

    def union(self, x, y):
        xLoc = self.find(x)
        yLoc = self.find(y)
        self.array[xLoc] = yLoc
    
    def find(self, x):
        if x != self.array[x]:
            self.array[x] = self.find(self.array[x])
        return self.array[x]

    def most(self):
        for i in range(len(self.array)):
            self.find(i)
        count = Counter(self.array)
        return max(count.values())


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        uf = UnionFind(len(A))
        
        def gcf(a,b):
            while b:
                a,b = b, a%b
            return a
        
        def primes(x):
            if x == 2:
                return {2}
            if x%2 == 0:
                return primes(x//2) | {2}
            for i in range(3, int(sqrt(x)) + 1,2):
                if x%i == 0:
                    return primes(x//i) | {i}
            return {x}
        facts = {}
        for i in range(len(A)):
            for prime in primes(A[i]):
                if prime not in facts:
                    facts[prime] = []
                facts[prime].append(i)
        for prime in facts:
            
            for i in range(len(facts[prime])-1):
                uf.union(facts[prime][i], facts[prime][i+1])
        return uf.most()

class Find:
    def __init__(self, A):
        self.l = list(range(len(A)))
        
    def find(self, e):
        if self.l[e] != e:
            self.l[e] = self.find(self.l[e])
        return self.l[e]
    
    def union(self, x, y):
        a = self.find(x)
        b = self.find(y)
        
        self.l[a] = b
        
    def primes(self, n):
        for i in range(int(math.sqrt(n)) - 1):
            if n % (i + 2) == 0:
                return self.primes(n // (i+2)) | set([i + 2])
        
        return set([n])

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        factors = defaultdict(list)
        find = Find(A)
        
        for i in range(len(A)):
            c = find.primes(A[i])
            for j in c:
                factors[j].append(i)
                
        for x, i in list(factors.items()):
            for k in range(len(i) - 1):
                find.union(i[k], i[k+1])
                
        counts = list(Counter([find.find(i) for i in range(len(A))]).values())
        
        return max(counts)
        


import math
import time
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        links = {}
        original_nums = set(A)
        
        def get_factors(n):
            out = []
            for i in range(2,int(math.sqrt(n))+1):
                if n % i == 0:
                    out.append(i)
                    out.append(n//i)
            return out
        
        # start_time = time.time()
        
        for num in A:
            factors = get_factors(num)
            if num not in links:
                links[num] = [num]
            for x in factors:
                # if num not in links:
                #     links[num] = [x]
                # else:
                links[num].append(x)
                if x not in links:
                    links[x] = [num]
                else:
                    links[x].append(num)
        
        # print(time.time()-start_time)
        
        def search(start):
            if start in seen:
                return 1
            stack = [start]
            size = 0
            while(stack):
                cur = stack.pop()
                # print(cur)
                seen.add(cur)
                if cur in original_nums:
                    size += 1
                # print(cur)
                for node in links[cur]:
                    if node not in seen:
                        stack.append(node)
                        seen.add(node)
            
            return size
                
            
        largest = 0
        seen = set()
        # print(original_nums)
        # print(links)
        for num in A:
            res = search(num)
            largest = max(largest, res)
        
        # print(time.time()-start_time)
        return largest
            
        
        
        


class Solution:
    def largestComponentSize(self, A):
        if not A: return 0
        def findAndCompact(l, i): # require i >= 0
            if l[i] == i: return i
            p = l[i]
            if p >= 0 and l[p] == p: return p
            while p >= 0 and l[p] != p:
                p = l[p]
            root = p
            
            # compact
            p = i
            while p >= 0 and l[p] != p:
                t = l[p]
                l[p] = root
                p = t
            return root
        
        slist = [-1] * len(A)
        d = {} # record prime->(root of union-find set)
        for i in range(len(A)):
            n = A[i]
            has_factor = False
            for j in range(2, int(sqrt(n)) + 1):
                if n % j == 0:
                    has_factor = True
                    k = n // j
                    #print(n, j, k)
                    ri = -1 if slist[i] < 0 else findAndCompact(slist, slist[i])
                    rj = -1 if j not in d else findAndCompact(slist, d[j])
                    rk = -1 if k not in d else findAndCompact(slist, d[k])
                    if ri < 0 and rj < 0 and rk < 0:
                        slist[i] = d[j] = d[k] = i
                    else:
                        mm = min([item for item in (ri, rj, rk) if item >= 0])
                        if slist[i] >= 0: slist[ri] = mm
                        if j in d: slist[rj] = mm
                        if k in d: slist[rk] = mm
                        slist[i] = d[j] = d[k] = mm
            if not has_factor: #prime
                if A[i] not in d: slist[i] = d[A[i]] = i
                else: slist[i] = d[A[i]]
            #print(slist, d)
        
        for i in range(len(A)): findAndCompact(slist, i)
        #print('### ', slist)
        cc = Counter(slist)
        m = cc.most_common(1)
        return m[0][1]

class DSU:
    def __init__(self, N):
        self.p = list(range(N))
        
    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr
        
class Solution:
    def primes_set(self, n):
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self.primes_set(n // i) | set ([i])
        return set([n])
    
    def largestComponentSize(self, A: List[int]) -> int:
        n = len(A)
        UF = DSU(n)
        primes = defaultdict(list)
        for i, num in enumerate(A):
            pr_set = self.primes_set(num)
            for q in pr_set: primes[q].append(i)

        for _, indexes in primes.items():
            for i in range(len(indexes)-1):
                UF.union(indexes[i], indexes[i+1])

        return max(Counter([UF.find(i) for i in range(n)]).values())        

# class Solution:
#     def largestComponentSize(self, A: List[int]) -> int:
        
        
        
#     def find_prime(self, num):
#         ans = []
#         for i in range(2, int(math.sqrt(num)) + 1):
#             if num % i == 0:
#                 ans.append(i)
#         return ans
class DSU:
    def __init__(self, N):
        self.p = list(range(N))

    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr

class Solution:
    def primes_set(self,n):
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self.primes_set(n//i) | set([i])
        return set([n])

    def largestComponentSize(self, A):
        n = len(A)
        UF = DSU(n)
        primes = defaultdict(list)
        for i, num in enumerate(A):
            pr_set = self.primes_set(num)
            for q in pr_set: primes[q].append(i)

        for _, indexes in list(primes.items()):
            for i in range(len(indexes)-1):
                UF.union(indexes[i], indexes[i+1])

        return max(Counter([UF.find(i) for i in range(n)]).values())            


class UnionFind():
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.size = [0] * n
    
    def find(self, i):
        if self.parent[i] != i:
            self.parent[i] = self.find(self.parent[i])
        return self.parent[i]
    
    def union(self, i, j):
        pi = self.find(i)
        pj = self.find(j)
        
        if pi != pj:
            self.parent[max(pi, pj)] = min(pi, pj)
            self.size[min(pi, pj)] += self.size[max(pi, pj)]
            self.size[max(pi, pj)] = 0 
            
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def decompose(num):
            if num == 1:
                return []
            res = []
            remain = num
            for factor in range(2, int(math.sqrt(num))+1):
                if remain % factor == 0:
                    while remain % factor == 0:
                        remain //= factor
                    res.append(factor)
            if remain > 1 and num % remain == 0:
                res.append(remain)
            return res
        
       
        unions = UnionFind(len(A))
        factor_index = collections.defaultdict(int)
        for idx, num in enumerate(A):
            factors = decompose(num)
            # print(\"factors\", factors)
            unions.size[idx] += 1
            for factor in factors:
                if factor not in factor_index:
                    factor_index[factor] = idx
                unions.union(factor_index[factor], idx)
                # print(\"factor\", factor, \"unions\", unions.parent, unions.size )
        return max(unions.size)
        
            
            


class UnionFind:
    def __init__(self, n):
        self.uf = list(range(n))
        self.size = defaultdict(lambda: 1)

    def find(self, i):
        if self.uf[i] != i:
            self.uf[i] = self.find(self.uf[i])
        return self.uf[i]

    def union(self, a, b):
        x, y = self.find(a), self.find(b)
        if x == y:
            return
        self.uf[x] = self.uf[y]
        self.size[y] += self.size[x]
        del self.size[x]

        
def factors(n):
    if n % 2 == 0:
        yield 2
    while n % 2 == 0:
        n //= 2
    for i in range(3, int(n**0.5)+2, 2):
        if i > n:
            break
        if n % i == 0:
            yield i
        while n % i == 0:
            n //= i
    if n > 2:
        yield n

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        if not A:
            return 0
        u = UnionFind(len(A))
        x = {}
        for i, a in enumerate(A):
            for f in factors(a):
                if f in x:
                    u.union(i, x[f])
                x[f] = i
        return max(u.size.values())


class DSU:
    def __init__(self, N):
        self.p = list(range(N))

    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr

class Solution:
    def primes_set(self,n):
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self.primes_set(n//i) | set([i])
        return set([n])

    def largestComponentSize(self, A):
        n = len(A)
        UF = DSU(n)
        primes = defaultdict(list)
        for i, num in enumerate(A):
            pr_set = self.primes_set(num)
            for q in pr_set: primes[q].append(i)

        for _, indexes in list(primes.items()):
            for i in range(len(indexes)-1):
                UF.union(indexes[i], indexes[i+1])

        return max(Counter([UF.find(i) for i in range(n)]).values())


class Solution:
    def __init__(self):
        self.prime = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317]

    def largestComponentSize(self, A: List[int]) -> int:
        n = len(A)
        factors_2_nodes = dict()
        B = [[] for i in range(0, n)]
        for i in range(0, n):
            num = A[i]
            found_factor = True
            while num > 1 and found_factor:
                found_factor = False
                limit = int(sqrt(num + 1))
                for f in self.prime:
                    if f > limit:
                        break
                    if num % f == 0:
                        if f not in B[i]:
                            B[i].append(f)
                            if f in factors_2_nodes:
                                factors_2_nodes[f].append(i)
                            else:
                                factors_2_nodes[f] = [i]
                        num //= f
                        found_factor = True
                        break
                if not found_factor and num not in B[i]:
                    B[i].append(num)
                    if num in factors_2_nodes:
                        factors_2_nodes[num].append(i)
                    else:
                        factors_2_nodes[num] = [i]
        v = [False] * n
        m = 0
        for i in range(0, n):
            if v[i]: continue
            queue = [i]
            c = 0
            while queue:
                q = queue.pop()
                if v[q]: continue
                v[q] = True
                c += 1
                for f in B[q]:
                    for node in factors_2_nodes[f]:
                        if not v[node]:
                            queue.append(node)
                    factors_2_nodes[f] = []
            if c > m:
                m = c
        return m

from math import sqrt
from collections import Counter
class UnionFind:

    def __init__(self, length):
        self.array = [i for i in range(length)]

    def union(self, x, y):
        xLoc = self.find(x)
        yLoc = self.find(y)
        self.array[xLoc] = yLoc
    
    def find(self, x):
        if x != self.array[x]:
            self.array[x] = self.find(self.array[x])
        return self.array[x]

    def most(self):
        for i in range(len(self.array)):
            self.find(i)
        count = Counter(self.array)
        return max(count.values())


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        uf = UnionFind(len(A))
        
        def gcf(a,b):
            while b:
                a,b = b, a%b
            return a
        
        def primes(x):
            if x == 2:
                return {2}
            if x%2 == 0:
                return primes(x//2) | {2}
            for i in range(3, int(sqrt(x)) + 1,2):
                if x%i == 0:
                    return primes(x//i) | {i}
            return {x}
        facts = {}
        for i in range(len(A)):
            for prime in primes(A[i]):
                if prime not in facts:
                    facts[prime] = []
                facts[prime].append(i)
        print(facts)
        for prime in facts:
            
            for i in range(len(facts[prime])-1):
                uf.union(facts[prime][i], facts[prime][i+1])
        return uf.most()

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        self.ret=0
        record={}
        disjoint=[-1]*len(A)
        def find(x):
            idx=x
            while disjoint[idx]>=0:
                idx=disjoint[idx]
            while disjoint[x]>=0:
                tmp=disjoint[x]
                disjoint[x]=idx
                x=tmp
            return idx
        def union(a,b):
            if a==b:
                return
            a_idx=find(a)
            b_idx=find(b)
            if a_idx==b_idx:
                return
            disjoint[a_idx]+=disjoint[b_idx]
            disjoint[b_idx]=a_idx
            self.ret=min(self.ret,disjoint[a_idx])
        def factor(x,idx):
            if x<3:
                union(record.get(x,idx),idx)
                record[x]=idx
                return
            if x%2==0:
                union(record.get(2,idx),idx)
                record[2]=idx
                while x%2==0:
                    x=x//2
            i=3
            while i*i<=x:
                if x%i==0:
                    union(record.get(i,idx),idx)
                    record[i]=idx
                while x%i==0:
                    x=x//i
                i+=2
            if x>1:
                union(record.get(x,idx),idx)
                record[x]=idx
        factors=[factor(A[i],i) for i in range(len(A))]
        return -self.ret

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        uf = {}
        
        def find(x):
            uf.setdefault(x, x)
            if uf[x] != x:
                uf[x] = find(uf[x])
            return uf[x]
        
        def union(x, y):
            uf[find(x)] = find(y)
            
        for i, a in enumerate(A):
            if not a % 2:
                union(A[i], 2)
                if a // 2 > 1:
                    union(A[i], a // 2)
            while not a % 2:
                a //= 2
            for k in range(3, int(sqrt(A[i])) + 1, 2):
                if not a % k:
                    union(A[i], k)
                    if a // k > 1:
                        union(A[i], a // k)
                while not a % k:
                    a //= k
                if a == 1:
                    break
            if a > 1:
                union(A[i], a)
        return max(Counter([find(a) for a in A]).values())

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        n = max(A)

        ans = 0
        uf = UF(n)
        count = collections.Counter()

        for a in A:
            for num in range(2, int(sqrt(a) + 1)):
                if a % num == 0:
                    uf.union(a, num)
                    uf.union(a, a // num)

        for a in A:
            pa = uf.find(a)
            count[pa] += 1
            ans = max(ans, count[pa])

        return ans


class UF:
    def __init__(self, n: int):
        self.rank = [0] * (n + 1)
        self.parent = [i for i in range(n + 1)]

    def union(self, u: int, v: int) -> None:
        pu = self.parent[u]
        pv = self.parent[v]
        if pu == pv:
            return

        if self.rank[pu] < self.rank[pv]:
            self.parent[pu] = pv
        elif self.rank[pv] < self.rank[pu]:
            self.parent[pv] = pu
        else:
            self.parent[pu] = pv
            self.rank[pv] += 1

    def find(self, u: int) -> int:
        while u != self.parent[u]:
            self.parent[u] = self.parent[self.parent[u]]
            u = self.parent[u]

        return u

class UnionFind(object):
    def __init__(self,n):
        self.uf=[i for i in range(n)]
        self.size=[1]*n
    
    def find(self,node):
        if node!=self.uf[node]:
            return self.find(self.uf[node])
        else:
            return node
        
    def union(self,x,y):
        x_r=self.find(x)
        y_r=self.find(y)
        if x_r==y_r:
            return
        self.uf[y_r]=x_r
        self.size[x_r]+=self.size[y_r]
        self.size[y_r]=0
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        def prime(n):
            cur=set()
            while n%2==0:
                cur.add(2)
                n//=2
            for i in range(3,int(math.sqrt(n))+1,2):
                while n%i==0:
                    cur.add(i)
                    n//=i
            if n>2:
                cur.add(n)
            return cur
        
        index={A[i]:i for i in range(len(A))}
        uf=UnionFind(len(A))
        res=collections.defaultdict(list)
        for i in A:
            for j in prime(i):
                res[j].append(i)
        for i,e in list(res.items()):
            if e:
                root=e[0]
                for j in e[1:]:
                    uf.union(index[root],index[j])
        return max(uf.size)


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent = [-1] * 100001

        def _find(x):
            if parent[x] == -1:
                return x

            parent[x] = _find(parent[x])
            return parent[x]

        def _union(x, y):
            xp = _find(x)
            yp = _find(y)

            if xp != yp:
                parent[yp] = xp

        for x in A:
            for i in range(2, int(sqrt(x)) + 1):
                if x % i == 0:
                    _union(i, x)
                    _union(x, x // i)

        count = 0
        cache = {}

        for x in A:
            xp = _find(x)
            count = max(count, 1 + cache.get(xp, 0))
            cache[xp] = 1 + cache.get(xp, 0)

        return count


class DSU():
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [0 for _ in range(n)]
        self.size = n
    def find(self, x):
        if x != self.parent[x]:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def union(self, x, y):
        xp, yp = self.find(x), self.find(y)
        
        if xp == yp:
            return False
        if self.rank[xp] < self.rank[yp]:
            self.parent[xp] = yp
        elif self.rank[xp] > self.rank[yp]:
            self.parent[yp] = xp
        else:
            self.parent[xp] = yp
            self.rank[yp] += 1
        self.size -= 1
        return True
    def getSize(self):
        return self.size
    
class Solution:
    # refer submission. https://www.cnblogs.com/grandyang/p/13253468.html
    def largestComponentSize(self, A: List[int]) -> int:
        def getFactors(n):
            res = set()
            for i in range(2, int(sqrt(n)) + 2):
                if not n % i:
                    # don't count 1 in factor. e.g. [1,2,3,4,5,6,7,8,9]
                    for j in [i, n // i]:
                        if j != 1:
                            res.add(j)
            # prime number.
            if not res:
                return {n}
            return res
        
        # buld dsu based on index of A. union index.
        dsu = DSU(len(A) + 1)
        factor2Index = {}
        for i, n in enumerate(A):
            for factor in getFactors(n):
                if factor in factor2Index:
                    dsu.union(i, factor2Index[factor])
                factor2Index[factor] = i
        groupSize = collections.defaultdict(int)
        for i in range(len(A)):
            groupSize[dsu.find(i)] += 1
        return max(groupSize.values())
        


class Solution:

    def largestComponentSize(self, A: List[int]) -> int:
        parent = {}
        size = defaultdict(lambda: 1)

        def ds(a):
            while a in parent:
                a = parent[a]
            return a

        def union(a, b):
            if (a := ds(a)) != (b := ds(b)):
                if size[a] < size[b]:
                    a, b = b, a
                parent[b] = a
                size[a] += size[b]

        for a in A:
            for d in factors(a):
                union(-d, a)

        return Counter(ds(a) for a in A).most_common(1)[0][1]


FS = {}


def factors(f):
    if (n := f) not in FS:
        if n & 1:
            FS[f] = factors3(f)
        else:
            n >>= 1
            while n & 1 == 0:
                n >>= 1
            if n > 1:
                FS[f] = factors3(n) + [2]
            else:
                FS[f] = [2]
    return FS[f]


def factors3(f, start=3):
    if (n := f) not in FS:
        for i in range(start, int(sqrt(n)) + 1, 2):
            if n % i == 0:
                n = n // i
                while n % i == 0:
                    n = n // i
                if n > 1:
                    FS[f] = factors3(n, i + 2) + [i]
                else:
                    FS[f] = [i]
                break
        else:
            FS[f] = [f]
    return FS[f]

class UnionFind:
    def __init__(self, n):
        self.uf = list(range(n))
        self.size = defaultdict(lambda: 1)

    def find(self, i):
        if self.uf[i] != i:
            self.uf[i] = self.find(self.uf[i])
        return self.uf[i]

    def union(self, a, b):
        x, y = self.find(a), self.find(b)
        if x == y:
            return
        self.uf[x] = self.uf[y]
        self.size[y] += self.size[x]
        del self.size[x]

        
def factors(n):
    if n % 2 == 0:
        yield 2
    while n % 2 == 0:
        n //= 2
    for i in range(3, int(n**0.5)+2, 2):
        if i > n:
            break
        if n % i == 0:
            yield i
        while n % i == 0:
            n //= i
    if n > 2:
        yield n

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        if not A:
            return 0
        u = UnionFind(len(A))
        x = {}
        for i, a in enumerate(A):
            for f in factors(a):
                if f in x:
                    u.union(i, x[f])
                else:
                    x[f] = i
        return max(u.size.values())


from collections import defaultdict


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        small_primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997]
        label = defaultdict(int)
       
        def findRoot(key):
            if label[key] > 0:
                label[key] = findRoot(label[key])
                return label[key]
            else:
                return key
        
        def mergeRoot(k1, k2):
            r1, r2 = findRoot(k1), findRoot(k2)  
            if r1 != r2:
                r1, r2 = min(r1, r2), max(r1, r2)
                label[r1] += label[r2]
                label[r2] = r1
            return r1

        for x in A:
            root_id = 0
            for p in small_primes:
                if x % p == 0:
                    root_id = findRoot(p) if root_id == 0 else mergeRoot(root_id, p)
                    while x % p == 0:
                        x //= p
            if x != 1:
                root_id = findRoot(x) if root_id == 0 else mergeRoot(root_id, x)
            label[root_id] -= 1
        
        return -min(label.values())

class DSU():
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [0 for _ in range(n)]
        self.size = n
    def find(self, x):
        # print('x = {0}, parent = {1}, self.parent[x] = {2}, cond = {3}'.format(x, self.parent, self.parent[x], x != self.parent[x]))
        if x != self.parent[x]:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def union(self, x, y):
        xp, yp = self.find(x), self.find(y)
        
        if xp == yp:
            return False
        # print('union, xp = {0}, yp = {1}'.format(xp, yp))
        if self.rank[xp] < self.rank[yp]:
            self.parent[xp] = yp
        elif self.rank[xp] > self.rank[yp]:
            self.parent[yp] = xp
        else:
            self.parent[xp] = yp
            self.rank[yp] += 1
        self.size -= 1
        return True
    def getSize(self):
        return self.size
    
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def getFactors(n):
            res = set()
            for i in range(2, int(sqrt(n)) + 2):
                if not n % i:
                    # don't count 1 in factor. e.g. [1,2,3,4,5,6,7,8,9]
                    for j in [i, n // i]:
                        if j != 1:
                            res.add(j)
                    # res.add(n // i)
            # prime number.
            if not res:
                return {n}
            return res
        
        dsu = DSU(len(A) + 1)
        factor2Index = {}
        for i, n in enumerate(A):
            # print('factor2Index = {0}, n = {1}, factors = {2}'.format(factor2Index, n, getFactors(n)))
            for factor in getFactors(n):
                if factor in factor2Index:
                    # print('factor = {0}, i = {1}, other = {2}'.format(factor, i, factor2Index[factor]))
                    dsu.union(i, factor2Index[factor])
                factor2Index[factor] = i
        groupSize = collections.defaultdict(int)
        for i in range(len(A)):
            groupSize[dsu.find(i)] += 1
        return max(groupSize.values())
        


class UnionFind:
    def __init__(self, n):
        self.uf = list(range(n))
        self.size = defaultdict(lambda: 1)

    def find(self, i):
        if self.uf[i] != i:
            self.uf[i] = self.find(self.uf[i])
        return self.uf[i]

    def union(self, a, b):
        x, y = self.find(a), self.find(b)
        if x == y:
            return
        self.uf[x] = self.uf[y]
        self.size[y] += self.size[x]
        self.size[x] = 0
        
PS = []

def factors(n):
    if n % 2 == 0:
        yield 2
    while n % 2 == 0:
        n //= 2
    for i in range(3, int(n**0.5)+2, 2):
        if i > n:
            break
        if n % i == 0:
            yield i
        while n % i == 0:
            n //= i
    if n > 2:
        yield n

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        if not A:
            return 0
        u = UnionFind(len(A))
        x = {}
        for i, a in enumerate(A):
            for f in factors(a):
                if f in x:
                    u.union(i, x[f])
                x[f] = i
        return max(u.size.values())


class UnionFind:
    def __init__(self, n):
        self.uf = list(range(n))
        self.size = defaultdict(lambda: 1)

    def find(self, i):
        if self.uf[i] != i:
            self.uf[i] = self.find(self.uf[i])
        return self.uf[i]

    def union(self, a, b):
        x, y = self.find(a), self.find(b)
        if x == y:
            return
        self.uf[x] = self.uf[y]
        self.size[y] += self.size[x]
        # self.size[x] = 0


def factors(n):
    if n % 2 == 0:
        yield 2
    while n % 2 == 0:
        n //= 2
    for i in range(3, int(n**0.5)+2, 2):
        if i > n:
            break
        if n % i == 0:
            yield i
        while n % i == 0:
            n //= i
    if n > 2:
        yield n

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        if not A:
            return 0
        u = UnionFind(len(A))
        x = {}
        for i, a in enumerate(A):
            for f in factors(a):
                if f in x:
                    u.union(i, x[f])
                x[f] = i
        return max(u.size.values())


def sieve(n):
    if n < 3:
        return
    yield 2
    p = set(range(5, n, 2))
    i = 3
    while i < n:
        yield i
        p.difference_update(list(range(i*i, n, i*2)))
        for i in range(i+2, n, 2):
            if i in p:
                p.remove(i)
                break
        else:
            return
    
    
class UnionFind:
    def __init__(self, n):
        self.uf = list(range(n))
        self.size = defaultdict(lambda: 1)

    def find(self, i):
        if self.uf[i] != i:
            self.uf[i] = self.find(self.uf[i])
        return self.uf[i]

    def union(self, a, b):
        x, y = self.find(a), self.find(b)
        if x == y:
            return
        self.uf[x] = self.uf[y]
        self.size[y] += self.size[x]
        self.size[x] = 0
        
PS = []

def factors(n):
    if n % 2 == 0:
        yield 2
    while n % 2 == 0:
        n //= 2
    for i in range(3, int(n**0.5)+2, 2):
        if i > n:
            break
        if n % i == 0:
            yield i
        while n % i == 0:
            n //= i
    if n > 2:
        yield n

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        if not A:
            return 0
        u = UnionFind(len(A))
        x = {}
        for i, a in enumerate(A):
            for f in factors(a):
                if f in x:
                    u.union(i, x[f])
                x[f] = i
        return max(u.size.values())


class DSU():
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [0 for _ in range(n)]
        self.size = n
    def find(self, x):
        # print('x = {0}, parent = {1}, self.parent[x] = {2}, cond = {3}'.format(x, self.parent, self.parent[x], x != self.parent[x]))
        if x != self.parent[x]:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def union(self, x, y):
        xp, yp = self.find(x), self.find(y)
        
        if xp == yp:
            return False
        # print('union, xp = {0}, yp = {1}'.format(xp, yp))
        if self.rank[xp] < self.rank[yp]:
            self.parent[xp] = yp
        elif self.rank[xp] > self.rank[yp]:
            self.parent[yp] = xp
        else:
            self.parent[xp] = yp
            self.rank[yp] += 1
        self.size -= 1
        return True
    def getSize(self):
        return self.size
    
class Solution:
    # refer submission. https://www.cnblogs.com/grandyang/p/13253468.html
    def largestComponentSize(self, A: List[int]) -> int:
        def getFactors(n):
            res = set()
            for i in range(2, int(sqrt(n)) + 2):
                if not n % i:
                    # don't count 1 in factor. e.g. [1,2,3,4,5,6,7,8,9]
                    for j in [i, n // i]:
                        if j != 1:
                            res.add(j)
            # prime number.
            if not res:
                return {n}
            return res
        
        # buld dsu based on index of A. union index.
        dsu = DSU(len(A) + 1)
        factor2Index = {}
        for i, n in enumerate(A):
            for factor in getFactors(n):
                if factor in factor2Index:
                    dsu.union(i, factor2Index[factor])
                factor2Index[factor] = i
        groupSize = collections.defaultdict(int)
        for i in range(len(A)):
            groupSize[dsu.find(i)] += 1
        return max(groupSize.values())
        


class DFU:
    def __init__(self, n):
        self.p = list(range(n)) 
        
    def find(self, x):
        if self.p[x] != x: 
            self.p[x] = self.find(self.p[x])
        return self.p[x]
    
    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr 

class Solution:
    def primes_set(self, d):
        for i in range(2, int(math.sqrt(d)) + 1):
            if d % i == 0:
                return self.primes_set(d // i) | set([i])
        return set([d])
    
    def largestComponentSize(self, A: List[int]) -> int:
        UF = DFU(len(A))
        primes = collections.defaultdict(list)
        
        for i, d in enumerate(A):
            primes_set = self.primes_set(d)
            for q in primes_set: primes[q].append(i) 
        
        
        for key, items in list(primes.items()):
            for i in range(len(items) - 1):
                UF.union(items[i], items[i + 1])
        
        # print(UF.p)
        return max(Counter([UF.find(i) for i in range(len(A))]).values())
            


class Solution:
  def largestComponentSize(self, A):
    p = list(range(max(A) + 1))
       
    def find(x):
      while p[x] != x:
        p[x] = p[p[x]]
        x = p[x]
      return x
    
    def union(x, y):
      p[find(x)] = p[find(y)]      
      
    for a in A:     
      for k in range(2, int(math.sqrt(a) + 1)):        
        if a % k == 0:
          union(a, k)
          union(a, a // k)
    
    return collections.Counter([find(a) for a in A]).most_common(1)[0][1]

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def union(x, y):
            graph[find(x)] = find(y)
        
        def find(x):
            path = []
            while graph[x] != x:
                path.append(x)
                x = graph[x]
            for n in path:
                graph[n] = x
            return x

        graph = {}
        for i, num in enumerate(A):
            if num not in graph:
                graph[num] = num
            for factor in range(2, int(math.sqrt(num) + 1)):
                if num % factor == 0:
                    for fac in (factor, num // factor):
                        if fac == 0:
                            print(num, fac)
                        if fac in graph:
                            union(num, graph[fac])
                        else:
                            graph[fac] = num

        roots = collections.defaultdict(int)
        for num in A:
            roots[find(num)] += 1
        return max(roots.values())

class Solution:
  def largestComponentSize(self, A):
    p = list(range(max(A) + 1))
       
    def find(x):
      while p[x] != x:
        p[x] = p[p[x]]
        x = p[x]
      return x
    
    def union(x, y):
      p[find(x)] = p[find(y)]      
      
    for a in A:     
      for k in range(2, int(math.sqrt(a) + 1)):    
        if a % k == 0:
          union(a, a // k)
          union(a, k)
    return collections.Counter([find(a) for a in A]).most_common(1)[0][1]

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        self.ret=0
        record={}
        disjoint=[-1]*len(A)
        def find(x):
            idx=x
            while disjoint[idx]>=0:
                idx=disjoint[idx]
            while disjoint[x]>=0:
                tmp=disjoint[x]
                disjoint[x]=idx
                x=tmp
            return idx
        def union(a,b):
            if a==b:
                return
            a_idx=find(a)
            b_idx=find(b)
            if a_idx==b_idx:
                return
            disjoint[a_idx]+=disjoint[b_idx]
            disjoint[b_idx]=a_idx
            self.ret=min(self.ret,disjoint[a_idx])
        def factor(x,idx):
            if x%2==0:
                union(record.get(2,idx),idx)
                record[2]=idx
                while x%2==0:
                    x=x//2
            i=3
            while i*i<=x:
                if x%i==0:
                    union(record.get(i,idx),idx)
                    record[i]=idx
                while x%i==0:
                    x=x//i
                i+=2
            if x>1:
                union(record.get(x,idx),idx)
                record[x]=idx
        for i,item in enumerate(A,0):
            factor(item,i)
        return -self.ret

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent = [-1]*100001
        
        def _find(x):
            if parent[x] == -1: return x
            parent[x] = _find(parent[x])
            return parent[x]
        
        def _union(x, y):
            xp = _find(x)
            yp = _find(y)
            if xp != yp:
                parent[yp] = xp
                
        for x in A:
            for i in range(2, int(sqrt(x))+1):
                if x%i == 0:
                    _union(i, x)
                    _union(x, x//i)
                    
        count = 0
        cache = {}
        for x in A:
            xp = _find(x)
            count = max(count, 1+cache.get(xp,0))
            cache[xp] = 1+cache.get(xp,0)
        return count           

class DisjointSet:
    def __init__(self, size):
        self.parents = list(range(size))
        self.sizes = [1]*size
        
    def find(self, x):
        if self.parents[x] != x:
            self.parents[x] = self.find(self.parents[x])
        return self.parents[x]
    
    def union(self, x, y):
        parent_x = self.find(x)
        parent_y = self.find(y)
        if parent_x != parent_y:
            self.sizes[parent_x] += self.sizes[parent_y]
            self.parents[parent_y] = parent_x


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        N = len(A)
        def to_divisors(n):
            if n%6 == 0:
                return [2, 3]
            if n%3 == 0:
                return [3]
            if n%2 == 0:
                return [2]
            return []
        maxA = max(A)
        divisors = [to_divisors(i) for i in range(maxA+1)]
        for i in range(4, maxA+1):
            if len(divisors[i]) == 0:
                for j in range(i, maxA+1, i):
                    divisors[j].append(i)
        disjoint_set = DisjointSet(N)
        divisor_to_index = {}
        for i, a in enumerate(A):
            for d in divisors[a]:
                if d in divisor_to_index:
                    disjoint_set.union(i, divisor_to_index[d])
                divisor_to_index[d] = i
        return max(disjoint_set.sizes)

class DSU:
    def __init__(self, n: int):
        self.n = n
        self.root = list(range(n))
        self.size = [1] * n
        self.max = 1
    
    def find(self, x: int) -> int:      
        if self.root[x] != x:
            self.root[x] = self.find(self.root[x])
        return self.root[x]     
   
    def union(self, x: int, y: int):
        rx, ry = self.find(x), self.find(y)
        if not rx == ry:
            self.root[rx] = ry
            self.size[ry] += self.size[rx]
            self.max = max(self.max, self.size[ry])
            
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        n = len(A)
        dsu = DSU(n)
        seen = {}
        for i, a in enumerate(A):
            for j in range(2, int(math.sqrt(a)) + 1):
                if a % j: continue
                if j in seen:    
                    dsu.union(i, seen[j])
                else:        
                    seen[j] = i
                if a // j in seen:    
                    dsu.union(i, seen[a // j])
                else:        
                    seen[a // j] = i
            if a in seen:
                dsu.union(i, seen[a])
            else:    
                seen[a] = i
        return dsu.max               

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        p = list(range(max(A) + 1))
        def find(x):
            while p[x] != x:
                p[x] = p[p[x]]
                x = p[x]
            return x

        def union(x, y):
             p[find(x)] = p[find(y)]      

        for a in A:     
            for k in range(2, int(math.sqrt(a) + 1)):        
                if a % k == 0:
                    union(a, k)
                    union(a, a // k)

        return collections.Counter([find(a) for a in A]).most_common(1)[0][1]

from typing import List
from collections import defaultdict
import time

DEBUG = False
# DEBUG = True

def debug(*args):
    if not DEBUG:
        return
    print((*args))

class Sieve:
    def __init__(self, max_n):
        self.prime_factors = defaultdict(list)
        for i in range(2, max_n + 1):
            if len(self.prime_factors[i]) > 0:
                continue
            for j in range(i, max_n + 1, i):
                self.prime_factors[j].append(i)


    def factors(self, n):
        return self.prime_factors[n]

sieve = Sieve(100000)

# s = Sieve(10000)
# print(s.factors(6))
# print(s.factors(512))
# print(s.factors(1007))
# print(s.factors(5040))

class Solution:
    def largestComponentSize(self, a: List[int]) -> int:
        # start = time.time()
        #
        by_factors = defaultdict(list)
        for x in a:
            for f in sieve.factors(x):
                by_factors[f].append(x)

        seen = set()
        seenf = set()
        ans = 0

        for x in a:
            if x in seen:
                continue
            seen.add(x)
            streak = 1
            todo = [f for f in sieve.factors(x) if f not in seenf]
            while len(todo) > 0:
                f = todo.pop()
                seenf.add(f)
                for cousin in by_factors[f]:
                    if cousin not in seen:
                        seen.add(cousin)
                        streak += 1
                        for ff in sieve.factors(cousin):
                            if ff not in seenf:
                                todo.append(ff)
                                seenf.add(ff)
            ans = max(ans, streak)

        # end = time.time()
        # print(end - start)
        return ans



class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        n = max(A) + 1
        parent = [i for i in range(n)]
        rank = [0] * n
        
        for a in A:
            for k in range(2, int(sqrt(a)) + 1):
                if a % k == 0:
                    self.union(parent, a, k, rank)
                    self.union(parent, a, a // k, rank)
        
        counter = collections.Counter()
        for a in A:
            counter[self.find_root(parent, a)] += 1
        
        return max(counter.values())
    
    def find_root(self, parent, x):
        if parent[x] != x:
            parent[x] = self.find_root(parent, parent[x])
        return parent[x]
    
    def union(self, parent, x, y, rank):
        x_root = self.find_root(parent, x)
        y_root = self.find_root(parent, y)
        if x_root != y_root:
            if rank[x_root] < rank[y_root]:
                parent[x_root] = y_root
            elif rank[x_root] > rank[y_root]:
                parent[y_root] = x_root
            else:
                parent[x_root] = y_root
                rank[y_root] += 1
    
    def find_common_factor(self, a, b):
        for i in range(2, min(a, b) + 1):
            if a % i == 0 and b % i == 0:
                return True
        return False


class UF:
    def __init__(self,n):
        self.p=[i for i in range(n)]
        self.s=[1]*n
        
    def find(self,x):
        if self.p[x]!=x:
            self.p[x]=self.find(self.p[x])
        return self.p[x]

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def add_prime(i,j,primes):
            if i not in primes:
                primes[i]=[j]
            else:
                primes[i].append(j)
        n=len(A)        
        g=UF(n)
        primes={}
        for j,k in enumerate(A):
            i=2
            while i*i<=k:
                if k%i==0:
                    add_prime(i,j,primes)
                    while k%i==0:
                        k=k//i
                i+=1
            if k>1:
                add_prime(k,j,primes)
        # print(primes)
        for l in primes.values():
            j,r=l[0],g.find(l[0])
            for i in l[1:]:
                nd=g.find(i)
                if nd!=r:
                    g.p[nd]=r
                    g.s[r]+=g.s[nd]
        # print(g.p)
        # print(g.s)
        return max(g.s)

import math

class DSU:
    def __init__(self, N):
        self.p = list(range(N))
        self.sizes = [1]*N

    def find(self, x):
        if x != self.p[x]:
            self.p[x] = self.find(self.p[x])
        return self.p[x]

    def union(self, x, y):
        x_root, y_root = self.find(x), self.find(y)
        if x_root == y_root:
            return
        
        if self.sizes[x_root] > self.sizes[y_root]:
            self.p[x_root] = y_root
            self.sizes[y_root] += self.sizes[x_root]
        else:
            self.p[y_root] = x_root
            self.sizes[x_root] += self.sizes[y_root]

class Solution:
    def prime_set(self, n):
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self.prime_set(n//i) | set([i])
        return set([n])

    def largestComponentSize(self, A: List[int]) -> int:               
        prime_map = {}
        for i in range(len(A)):
            P = self.prime_set(A[i])
            for p in P:
                if p not in prime_map:
                    prime_map[p] = []
                prime_map[p].append(i)
        
        DSU_groups = DSU(len(A))
        for _, group in prime_map.items():
            for i in range(len(group)-1):
                DSU_groups.union(group[i], group[i+1])
        
        return max(DSU_groups.sizes)

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:

        class UF:
            def __init__(self, N):
                self.parents = [i for i in range(N)]
                self.sizes = [1 for _ in range(N)]
                self.max = 1
            
            def find(self, x):
                if self.parents[x] != 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 self.sizes[x] < self.sizes[y]:
                    x, y = y, x
                if x != y:
                    self.parents[y] = x
                    self.sizes[x] += self.sizes[y]
                    self.max = max(self.max, self.sizes[x])
        uf = UF(len(A))
        
        dic = {}
        for i, num in enumerate(A):
            for factor in range(2, int(math.sqrt(num) + 1)):
                # if factor**2 > num:
                #     break
                if num%factor == 0:
                    for fac in [factor, num//factor]:
                        if fac in dic:
                            uf.union(dic[fac], i)
                        else:
                            dic[fac] = i
            if num in dic:
                uf.union(dic[num], i)
            else:
                dic[num] = i
        return uf.max

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent=[-1]*100001
        def _find(x):
            if parent[x]==-1:
                return x
            parent[x]=_find(parent[x])
            return parent[x]
        def _union(x, y):
            xp=_find(x)
            yp=_find(y)
            if xp!=yp:
                parent[yp]=xp
        for x in A:
            for i in range(2, int(sqrt(x))+1):
                if x%i==0:
                    _union(i,x)
                    _union(x,x//i)
        count=0
        cache={}
        for x in A:
            xp=_find(x)
            count=max(count,1+cache.get(xp,0))
            cache[xp]=1+cache.get(xp,0)
        return count    
                    
        


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent = [-1] * 100001

        def _find(x):
            if parent[x] == -1:
                return x

            parent[x] = _find(parent[x])
            return parent[x]

        def _union(x, y):
            xp = _find(x)
            yp = _find(y)

            if xp != yp:
                parent[yp] = xp

        for x in A:
            for i in range(2, int(sqrt(x)) + 1):
                if x % i == 0:
                    _union(i, x)
                    _union(x, x // i)

        cache = {}

        for x in A:
            xp = _find(x)
            cache[xp] = 1 + cache.get(xp, 0)

        print(cache)
        cache1 = sorted(list(cache.items()), key=lambda x: x[1])
        max = (cache1[-1][0])
        return cache[max]



class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        p = list(range(max(A) + 1))

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

        def union(x, y):
            p[find(x)] = p[find(y)]      

        for a in A:     
            for k in range(2, int(math.sqrt(a) + 1)):        
                if a % k == 0:
                    union(a, k)
                    union(a, a // k)

        return collections.Counter([find(a) for a in A]).most_common(1)[0][1]

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parents = {val:val for val in A}
        sizes = {val:1 for val in A}
        factorprez = {} 
        maxsize = 0
        
        def union(one, two):
            r1 = findroot(one)
            r2 = findroot(two)
            
            if r1 == r2: return sizes[r1]
            
            big, small = (r1, r2) if sizes[r1] > sizes[r2] else (r2, r1)
            parents[small] = big
            sizes[big] += sizes[small]
            return sizes[big]
            
        def findroot(node):
            if parents[node] != node:
                node = findroot(parents[node])
            return parents[node]
        
        def primes_before(val):
            candidates = [True] * (val + 1)
            primes = []
            for i in range(2, len(candidates)):
                if not candidates[i]: continue
                primes.append(i)
                for j in range(i, val+1, i):
                    candidates[j] = False
            return primes
        
        primes = primes_before(100000)
        primeset = set(primes)
        
        for val in A:
            sval = val
            prime_idx = 0
            while sval not in primeset and primes[prime_idx] <= sval:
                if sval % primes[prime_idx] == 0:
                    if primes[prime_idx] in factorprez:
                        maxsize = max(maxsize, union(val, factorprez[primes[prime_idx]]))
                    else:
                        factorprez[primes[prime_idx]] = val
                    
                    while sval % primes[prime_idx] == 0:
                        sval //= primes[prime_idx]
                
                prime_idx += 1
            
            if sval in primeset:
                if sval in factorprez:
                    maxsize = max(maxsize, union(val, factorprez[sval]))
                else:
                    factorprez[sval] = val

        return maxsize

class UnionFind:
    def __init__(self, N):
        self.par = list(range(N))
        self.rank = [0]*N
        self.size = [0]*N
        
    def find(self, x):
        if self.par[x] != x:
            self.par[x] = self.find(self.par[x])
        return self.par[x]
    
    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        if px==py: return
        if self.rank[px]<self.rank[py]:
            self.par[px]=py
            self.size[py]+=self.size[px]
        elif self.rank[px]>self.rank[py]:
            self.par[py]=px
            self.size[px]+=self.size[py]
        else:
            self.par[py]=px
            self.rank[px]+=1
            self.size[px]+=self.size[py]
        
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        N = max(A)
        primes = []
        res =0
        for i in range(2, int(N**0.5)+1):
            for j in primes:
                if i%j==0:
                    break
            else:
                primes.append(i)

        uf = UnionFind(N+1)
        used_primes = set()
        for a in A:
            if a<2: continue
            a_primes = []
            for p in primes:
                if p*p>a: break
                if a%p == 0:
                    a_primes.append(p)
                    while a%p == 0:
                        a //= p
            if a>1:
                a_primes.append(a)
                
            idx = uf.find(a_primes[0])
            used_primes.add(a_primes[0])
            uf.size[idx] += 1
            for i in range(1, len(a_primes)):
                uf.union(a_primes[0], a_primes[i])
            
        for a in used_primes:
            idx = uf.find(a)
            res = max(res, uf.size[idx])
            
        return res


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:

        ##############################
        # Union Find
        parents = [-1] * (max(A) + 1)

        def find(x :int) -> int:
            if parents[x] < 0:
                return x
            
            parents[x] = find( parents[x] )
            return parents[x]

        def union(x,y):
            root_x = find(x)
            root_y = find(y)

            if root_x == root_y:
                return
            
            depth_x = parents[root_x]
            depth_y = parents[root_y]

            if depth_x <= depth_y:
                parents[root_y] = root_x

                if depth_x == depth_y:
                    parents[root_x] -= 1

            else:
                parents[root_x] = root_y
        ##############################


        def get_factor(n :int) -> list:
            ans = []

            for i in range(2, int(n**(1/2)+1) ):  # exclude \"factor 1\" and \"max factor\"
                if  n % i == 0:
                    ans.append(i)

                    d = n / i
                    if (d != i) and (d % 1 == 0):
                        ans.append( int(d) )

            return ans


        for num in A:
            fact = get_factor(num)

            for v in fact:
                union(num, v)
        

        group = [ find(num) for num in A ]
        cnt = Counter(group)
        
        return cnt.most_common(1)[0][1]


class DSU:
    def __init__(self, N):
        self.p = list(range(N))

    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr

class Solution:
    def primes_set(self,n):
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self.primes_set(n//i) | set([i])
        return set([n])

    def largestComponentSize(self, A):
        n = len(A)
        UF = DSU(n)
        primes = defaultdict(list)
        for i, num in enumerate(A):
            pr_set = self.primes_set(num)
            for q in pr_set: primes[q].append(i)

        for __, indexes in primes.items():
            for i in range(len(indexes)-1):
                UF.union(indexes[i], indexes[i+1])

        return max(Counter([UF.find(i) for i in range(n)]).values())

class UF:
    def __init__(self,n):
        self.p=[i for i in range(n)]
        self.s=[1]*n
        
    def find(self,x):
        if self.p[x]!=x:
            self.p[x]=self.find(self.p[x])
        return self.p[x]
    
    def union(self,x,y):
        xr,yr = self.find(x), self.find(y)
        self.s[xr]+=self.s[yr]
        self.p[yr]=xr    

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def add_prime(i,j,primes):
            if i not in primes:
                primes[i]=[j]
            else:
                primes[i].append(j)
                
        g=UF(len(A))
        primes={}
        for j,k in enumerate(A):
            i=2
            while i*i<=k:
                if k%i==0:
                    add_prime(i,j,primes)
                    while k%i==0:
                        k=k//i
                i+=1
            if k>1:
                add_prime(k,j,primes)
        # print(primes)
        for l in primes.values():
            j,r=l[0],g.find(l[0])
            for i in l[1:]:
                if g.find(i)!=r:
                    g.union(j,i)
        # print(g.p)
        # print(g.s)
        return max(g.s)


class Solution:

    def largestComponentSize(self, A: List[int]) -> int:

        parent = [-1]*100001

        def _find (x):

            if parent[x] == -1:

                return x

            parent[x] = _find(parent[x])

            return parent[x]

        def _union(x, y):

            xp = _find(x)

            yp = _find(y)

            if xp != yp:

                parent[yp] = xp

        for x in A:

            for i in range(2, int(sqrt(x)) + 1):

                if x % i == 0:

                    _union(i, x)

                    _union(x, x//i)

        

        count = 0;

        cache = {}

        for x in A:

            xp = _find(x)

            count = max(count, 1 + cache.get(xp, 0))

            cache[xp] = 1 + cache.get(xp, 0)

        return count

    

    # O(N * sqrt*max(A[i]))


import math

class Solution:
    
    def __init__(self):
        self.prime_divisors_cache = {}
    
    def prime_divisors(self, x, i=2):
        if x in self.prime_divisors_cache:
            return self.prime_divisors_cache[x]
        while i * i <= x:
            if x % i != 0:
                i += 1
                if i > 3:
                    i += 1
            else:
                self.prime_divisors_cache[x] = set([i]) | self.prime_divisors(x // i, i)
                return self.prime_divisors_cache[x]
    
        res = set()
        if x > 1:
            res.add(x)
        
        self.prime_divisors_cache[x] = res
        return self.prime_divisors_cache[x]
            
            
    def largestComponentSize(self, A: List[int]) -> int:
        # related if NOT coprime
        
        # we can keep associated a list of prime factors with each set 
        
        # integers in A are unique
        # form a disjoint set structure
        # node label -> parent
        parent = dict()
        # representative label -> size of set
        size = dict()
        # keep track of list of representatives for ease
        reps = set()
        
        def getRep(x):
            # compress path to parent
            while parent[x] != x:
                x, parent[x] = parent[x], parent[parent[x]]
            return x
        
        # def getSize(x):
        #     return size[getRep(x)]
            
        def add(x):
            parent[x] = x
            size[x] = 1
            reps.add(x)
        
        def merge(x, y):
            x = getRep(x)
            y = getRep(y)
            if x == y:
                return
            if size[x] < size[y]:
                x, y = y, x
            size[x] += size.pop(y)
            parent[y] = x
            reps.remove(y)
        
        # prime -> list of numbers it divides
        prime2dividend = {}
        for x in A:
            add(x)
            for p in self.prime_divisors(x):
                if not p in prime2dividend:
                    prime2dividend[p] = [x]
                else:
                    prime2dividend[p].append(x)
        
        for _, xs in list(prime2dividend.items()):
            # guaranteed to be one
            first = xs.pop()
            for x in xs:
                merge(first, x)
        
        return max([size[rep] for rep in reps])
        
        
        


class Solution:    
    def get_prime_numbers(self, A, max_num: int) -> List[int]:
        is_prime_list = [True] * (max_num + 1)        
        prime_to_nums_dict = defaultdict(list)
        
        for i in range(2, max_num + 1):            
            if is_prime_list[i] == False: continue
            
            num = i
            while num <= max_num:
                if num in A:
                    prime_to_nums_dict[i].append(num)                                
                is_prime_list[num] = False
                num += i            
        
        return prime_to_nums_dict
    
    def find(self, union_list, index: int) -> int:
        if index == union_list[index]: return index
        #return self.find(union_list, union_list[index])    
        parent = self.find(union_list, union_list[index])
        union_list[index] = parent
        return parent
        
    def union(self, union_list, index1: int, index2: int) -> None:
        union1, union2 = self.find(union_list, index1), self.find(union_list, index2)                
        union_list[union1], union_list[index2] = union2, union2
        #union_list[union1] = union2
        
    def largestComponentSize(self, A: List[int]) -> int:
        if len(A) == 0: return 0        
        max_num = max(A)
        union_list = [i for i in range(max_num + 1)]
        count_list = [0] * (max_num + 1)
        
        # get prime numbers
        prime_to_nums_dict = self.get_prime_numbers(set(A), max_num) # prime numbers of A's numbers
        
        # linking numbers having the same prime 
        for prime, nums in list(prime_to_nums_dict.items()):
            for i in range(len(nums) - 1):
                self.union(union_list, nums[i], nums[i + 1])
        
        # print(prime_to_nums_dict)
        # print(union_list)
        
        # counting numbers in a component        
        for i, num in enumerate(A):
            #if num == 1: continue  
            count_list[self.find(union_list, num)] += 1        
        #print(count_list)
        return max(count_list)
# Time complexity: O(n * p) where n is the maximum number of A and p is the number of prime numbers less than n
# Space complexity: O(n + p) we can ignore p


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        ma = max(A)
        N = len(A)
        m = list(range(ma+1))
        for a in A:
            for k in range(2, int(math.sqrt(a))+1):
                if a%k == 0:
                    self.u(m,a,k)
                    self.u(m,a,a//k)
        count = collections.defaultdict(int)
        for a in A:
            count[self.f(m,a)] +=1
        return max(count.values())
    def f(self, m, a):
        while m[a] != a:
            m[a] = m[m[a]]
            a = m[a]
        return a
    def u(self, m, a, b):
        if m[a] == m[b]: return
        pa = self.f(m,a)
        pb = self.f(m,b)
        m[pa] = pb

class UF:
    def __init__(self,n):
        self.p=[i for i in range(n)]
        
    def find(self,x):
        if self.p[x]!=x:
            self.p[x]=self.find(self.p[x])
        return self.p[x]

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def add_prime(i,j,primes):
            if i not in primes:
                primes[i]=[j]
            else:
                primes[i].append(j)
        n=len(A)        
        g=UF(n)
        primes={}
        for j,k in enumerate(A):
            i=2
            while i*i<=k:
                if k%i==0:
                    add_prime(i,j,primes)
                    while k%i==0:
                        k=k//i
                i+=1
            if k>1:
                add_prime(k,j,primes)
        # print(primes)
        for l in primes.values():
            j,r=l[0],g.find(l[0])
            for i in l[1:]:
                s=g.find(i)
                if s!=r:
                    g.p[s]=r
        # print(g.p)
        # print(g.s)
        return max(Counter([g.find(i) for i in range(n)]).values())

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        p = list(range(max(A) + 1))
       
        def find(x):
            while p[x] != x:
                p[x] = p[p[x]]
                x = p[x]
            return x
    
        def union(x, y):
            p[find(x)] = p[find(y)]      

        for a in A:     
            for k in range(2, int(math.sqrt(a) + 1)):        
                if a % k == 0:
                    union(a, k)
                    union(a, a // k)

        return collections.Counter([find(a) for a in A]).most_common(1)[0][1]

import math

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent = dict()
        
        def find_parent(x):
            if x not in parent:
                parent[x] = -1
                return x 
            
            if parent[x] == -1:
                return x
            parent[x] = find_parent(parent[x])
            return parent[x]
        
        def union_num(x, y):
            px = find_parent(x)
            py = find_parent(y)
            if px != py:
                parent[py] = px
            return
        
        for x in A:
            for i in range(2, int(math.sqrt(x))+1):
                if x%i == 0:
                    union_num(i, x)
                    union_num(i, x//i)
                
        count = 0
        count_ref = dict()
        for x in A:
            p = find_parent(x)
            count_ref[p] = count_ref.get(p,0) + 1
            count = max(count, count_ref[p])
        return count
                


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        par=[-1]*100001
        def find1(x):
            if par[x]==-1:
                return x
            par[x]=find1(par[x])
            return par[x]
        
        def union1(x,y):
            xp=find1(x)
            yp=find1(y)
            if xp!=yp:
                par[yp]=xp
        
        for x in A:
            for i in range(2,int(sqrt(x))+1):
                if x%i==0:
                    union1(i,x)
                    union1(x,x//i)
                    
        cnt=0
        cach={}
        for x in A:
            xp=find1(x)
            cnt=max(cnt,1+cach.get(xp,0))
            cach[xp]=1+cach.get(xp,0)
        return cnt



class UF:
    def __init__(self,N):
        self.parent = [i for i in range(N)]
        self.size = [1 for i in range(N)]
    
    def find(self,x):
        if self.parent[x] == x:
            return x
        self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def union(self,X,Y):
        root_x = self.find(X)
        root_y = self.find(Y)
        if root_x != root_y:
            
            if self.size[root_x] >= self.size[root_y]:
                self.parent[root_y] = root_x
                self.size[root_x] += self.size[root_y] 
                
            else:
                self.parent[root_x] = root_y
                self.size[root_y] += self.size[root_x]
                

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        factor_map = {}
        uf = UF(len(A))
        for index,num in enumerate(A):
            for factor in range(2, int(sqrt(num)+ 1)):
                if num % factor == 0:
                    
                    if factor_map.get(factor) is None:
                        factor_map[factor] = index
                    else:
                        uf.union(index,factor_map[factor])
                        
                    j = num // factor
                    if factor_map.get(j) is None:
                        factor_map[j] = index
                    else:
                        uf.union(index,factor_map[j])
                        
            
            if factor_map.get(num) is None:
                factor_map[num] = index
            else:
                uf.union(index,factor_map[num])
                
        return max(uf.size)
            


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        ma = max(A)
        N = len(A)
        m = list(range(ma + 1))
        for a in A:
            for k in range(2, int(math.sqrt(a)) + 1):
                if a % k == 0:
                    self.u(m, a, k)
                    self.u(m, a, a // k)
        count = collections.defaultdict(int)
        for a in A:
            count[self.f(m, a)] += 1
        return max(count.values())
        
    def f(self, m, a):
        while m[a] != a:
            m[a] = m[m[a]]
            a = m[a]
        return a
    
    def u(self, m, a, b):
        if m[a] == m[b]: return
        pa = self.f(m, a)
        pb = self.f(m, b)
        m[pa] = pb

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        from math import sqrt
        from collections import defaultdict
        initial = set(A)
        parent = defaultdict(int)
        
        for e in A:
            parent[e] = e
        
        def find(c):
            if c not in parent:
                parent[c] = c
                return c
            while parent[c] != c:
                parent[c] = parent[parent[c]]
                c = parent[c]
            return c
        
        def union(c1, c2):
            p1, p2 = find(c1), find(c2)
            if p1 == p2:
                return
            parent[p1] = p2
        
        for e in A:
            for n in range(2, int(sqrt(e)) + 1):
                if e % n == 0:
                    # divisible by n
                    union(e, e // n)
                    union(e, n)
                    
        #print(parent)
           
        counts = defaultdict(int)
        for k in list(parent.keys()):
            if k in initial:
                counts[find(k)] += 1
        
        return max(counts.values())
        
        


#
# @lc app=leetcode id=952 lang=python3
#
# [952] Largest Component Size by Common Factor
#

# @lc code=start
from collections import defaultdict


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        small_primes = (2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317)
        label = defaultdict(int)
       
        def findRoot(key):
            if label[key] > 0:
                label[key] = findRoot(label[key])
                return label[key]
            else:
                return key
        
        def mergeRoot(k1, k2):
            r1, r2 = findRoot(k1), findRoot(k2)  
            if r1 != r2:
                r1, r2 = min(r1, r2), max(r1, r2)
                label[r1] += label[r2]
                label[r2] = r1
            return r1

        for x in A:
            root_id = 0
            t = sqrt(x) + 1
            for p in small_primes:
                if p > t:
                    break
                elif x % p == 0:
                    root_id = findRoot(p) if root_id == 0 else mergeRoot(root_id, p)
                    while x % p == 0:
                        x //= p
            if x != 1:
                root_id = findRoot(x) if root_id == 0 else mergeRoot(root_id, x)
            label[root_id] -= 1
        
        return -min(label.values())
# @lc code=end


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def find(m, a):
            while m[a] != a:
                m[a] = m[m[a]]
                a = m[a]
            return a
        
        def union(m, a, b):
            if m[a] == m[b]:
                return
            
            pa = find(m, a)
            pb = find(m, b)
            m[pa] = pb
        
        
        Max = max(A)
        m = [i for i in range(Max + 1)]
        for num in A:
            for k in range(2, int(math.sqrt(num)) + 1):
                if num % k == 0:
                    union(m, num, k)
                    union(m, num, num // k)
                    
        count = collections.defaultdict(int)
        for num in A:
            count[find(m, num)] += 1
            
        return max(count.values())
        


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        # union find
        '''
        def gcd(a, b):    
            if b==0:
                return a
            return gcd(b, a%b)
        '''
        def find(u):  # pass compresson
            if p[u]==-1:
                return u
            p[u]=find(p[u])
            return p[u]
            
        def union(u, v):
            u = find(u)
            v = find(v)
            
            if u!=v:
                if r[u]>r[v]:
                    p[v] = u
                elif r[u]<r[v]:
                    p[u] = v
                else:
                    p[v]=u
                    r[u]+=1
        '''
        def sieve(x):
            
            num = [True]*(x+1)
            
            k = 2
            while k*k<=x:
                if num[k]:
                    i = k*k
                    while i<=x:
                        num[i] = False
                        i += k
                k+=1        
                
            for i in range(2, x+1):
                if num[i]:
                    pr.append(i)
            
        '''         
        n = len(A)
        
        m = max(A)+1
        
        #pr = []
        #sieve(m-1)
        #l = len(pr)
            
        p = [-1]*m
        r = [0]*m
    
        for i in range(n):
            # prime factorization
            factor = 2
            num = A[i]
            while num>=factor*factor:  # here
                if num%factor==0:
                    num//=factor
                    union(A[i], factor)
                else:
                    factor+=1
            union(A[i], num)    # here
    
            ################
            #j = 0
            #while j<l and pr[j]<=A[i]:
            #    if A[i]%pr[j]==0:
            #        union(A[i], pr[j])
            #    j+=1
            ##################
            #j = 2
            #while j*j<=A[i]:
            #    if A[i]%j==0:
            #        union(A[i], j)
            #        union(A[i], A[i]//j)
            #    j+=1    
                
        
        s = [0]*m    
        for i in range(n):    
            s[find(A[i])]+=1
         
        return max(s)
        
        '''
        # dfs   TLE
        
        def gcd(a, b):    
            if b==0:
                return a
            return gcd(b, a%b)
        
        def dfs(u):
            y = 1
            for v in adj[u]:
                if not vis[v]:
                    vis[v] = True
                    y += dfs(v)
            
            return y
        
        
        n = len(A)
        
        adj = [ [] for i in range(n) ]
        
        for i in range(n):
            for j in range(i+1,n):
                if gcd(A[i], A[j])>1:
                    adj[i].append(j)
                    adj[j].append(i)
        
        
        
        res = 0
        
        vis = [False]*n
        
        for i in range(n):
            
            if not vis[i]:
                vis[i] = True
                res = max(res, dfs(i))
        
        return res
    '''


from collections import Counter, defaultdict


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def factorize(x):
            ret = set()
            i = 2
            while i * i <= x:
                while x % i == 0:
                    ret.add(i)
                    x = x // i
                i += 1
            
            if x != 1:
                ret.add(x)
            return ret
        
        factor_to_num = defaultdict(list)
        for i, a in enumerate(A):
            for factor in factorize(a):
                factor_to_num[factor].append(i)
        
        # init
        par = list(range(len(A)))
        rank = [0] * len(A)
        
        def find(x):
            if par[x] == x:
                return x
            else:
                ret = find(par[x])
                par[x] = ret
                return ret
        
        def unite(x, y):
            x = find(x)
            y = find(y)
            if x == y:
                return
            
            if rank[x] < rank[y]:
                par[x] = y
            else:
                par[y] = x
                if rank[x] == rank[y]:
                    rank[x] += 1
        
        for factor in factor_to_num.keys():
            nums = factor_to_num[factor]
            for i in range(1, len(nums)):
                unite(nums[i-1], nums[i])
        
        counter = Counter(find(i) for i in range(len(A)))
        return max(counter.values())

class DSU:
    def __init__(self, N):
        self.p = list(range(N))

    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr

class Solution:
    def primes_set(self,n):
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self.primes_set(n//i) | set([i])
        return set([n])

    def largestComponentSize(self, A):
        n = len(A)
        UF = DSU(n)
        primes = defaultdict(list)
        for i, num in enumerate(A):
            pr_set = self.primes_set(num)
            for q in pr_set: primes[q].append(i)

        for _, indexes in list(primes.items()):
            for i in range(len(indexes)-1):
                UF.union(indexes[i], indexes[i+1])

        return max(Counter([UF.find(i) for i in range(n)]).values())

class UnionFind:
    def __init__(self, A):
        self.factorparent = []
        for i in range(A):
            self.factorparent.append(i)
    
    def union(self, x, y):
        xp = self.find(x)
        yp = self.find(y)
        self.factorparent[xp] = yp
        
    def find(self, x):
        if x != self.factorparent[x]:
            self.factorparent[x] = self.find(self.factorparent[x])
        return self.factorparent[x]
        
class Solution1:
    def largestComponentSize(self, A: List[int]) -> int:
        if not A:
            return 0
        length = len(A)
        obj = UnionFind(length)
        primes = defaultdict(list)
        for i, n in enumerate(A):
            primeset = self.getPrime(n)
            for p in primeset:
                primes[p].append(i)
                
        for k, v in list(primes.items()):
            for i in range(len(v)-1):
                obj.union(v[i], v[i+1])
        primes = {}
        maxval = 0
        for i in range(length):
            val = obj.find(i)
            primes[val] = primes.get(val, 0) + 1
            maxval = max(maxval, primes[val])
        return maxval
    
    def getPrime(self, n):
        i = 2
        while i <= int(sqrt(n)):
            if n % i == 0:
                return self.getPrime(n // i) | set([i])
            i += 1
        return set([n])
                
                


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent = [-1]*100001
        def find (x):
            if parent[x] == -1:
                return x
            parent[x] = find(parent[x])
            return parent[x]

        def edge(x, y):
            xp = find(x)
            yp = find(y)
            if xp != yp:
                parent[yp] = xp

        for x in A:
            for i in range(2, int(sqrt(x)) + 1):
                if x % i == 0:
                    edge(i, x)
                    edge(x, x//i)
        
        count = 0
        cache = {}
        for x in A:
            xp = find(x)
            count = max(count, 1 + cache.get(xp, 0))
            cache[xp] = 1 + cache.get(xp, 0)
        return count

        
                    
                
            
            
            
            
        
                


class DSU:
    def __init__(self,n):
        self.p = list(range(n))
        
    def find(self,x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]
    
    def union(self,x,y):
        x1,y2 = self.find(x), self.find(y)
        self.p[x1] = y2

class Solution:
    def primes(self,n):
        for i in range(2,int(n**(1/2))+1):
            if n % i  == 0:
                return set([i]).union(self.primes(n//i))
        return set([n])
        
    def largestComponentSize(self, A: List[int]) -> int:
        prime = defaultdict(list)
        for i,n in enumerate(A):
            primeset = self.primes(n)
            for p in primeset:
                prime[p].append(i)
        N = len(A)
        dsu = DSU(N)
        for _,indexes in list(prime.items()):
            for i in range(len(indexes)-1):
                dsu.union(indexes[i],indexes[i+1])
                
        return max(Counter([dsu.find(i) for i in range(N)]).values())


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        p = list(range(max(A) + 1))

        def find(x):
            if p[x] != x:
                p[x] = find(p[x])
            return p[x]

        def union(x, y):
            p[find(x)] = p[find(y)]      

        for a in A:     
            for k in range(2, int(math.sqrt(a) + 1)):        
                if a % k == 0:
                    union(a, k)
                    union(a, a // k)

        return collections.Counter([find(a) for a in A]).most_common(1)[0][1]




class Primes:
    def __init__(self):
        M = ceil(sqrt(100000))+1
        isPrime = [True] * M
        k = 2
        while k < M:
            n=2
            while k*n < M:
                isPrime[k*n] = False               
                n += 1
            k += 1
            while k < M and not isPrime[k]:
                k += 1
            
        self.primes = [k for k in range(2,M) if isPrime[k]]
        


class Solution:
    primes = Primes().primes       
        
    def largestComponentSize(self, A: List[int]) -> int:        
             
        def getPrimeFactors(a):
            ans = []
            for p in Solution.primes:
                if p*p > a: break
                if a%p==0:
                    ans.append(p)
                    while True:
                        a = a // p
                        if a%p != 0: break
            if a > 1:
                ans.append(a)
            return ans
        
        N = len(A) 
        D = defaultdict(list)
        for k in range(N):
            a = A[k]
            ap = getPrimeFactors(a)
            for p in ap:
                D[p].append(k)
        dsu = DSU(N)
        for p,indexList in list(D.items()):            
            n = len(indexList)
            for i in range(n-1):
                dsu.union(indexList[i],indexList[i+1])
        return max(dsu.size)
    
    
class DSU: # Disjoint Set Union data structure
    
    def __init__(self, size):
        self.size = [1] * (size+1)
        self.parent = [i for i in range(size+1)]
        
        
    def find(self, i):
        
        # Path halving... replaces only every other parent pointer with grandparent
        while self.parent[i] != i:
            i = self.parent[i] = self.parent[self.parent[i]]
        return i
            
        
        # Path splitting way... let to 980ms... replacing every parent with grandparent
        ##while self.parent[i] != i:
        ##    i, self.parent[i] = self.parent[i], self.parent[self.parent[i]]
        ##return i
        
        # The simplest recursive way... led to 1012ms
        ##if i != self.parent[i]:
        ##    self.parent[i] = self.find(self.parent[i])
        ##return self.parent[i]
    
    def union(self, i,j):
        i = self.find(i)
        j = self.find(j)
        
        if i == j: return
        
        if self.size[i] > self.size[j]:
            i,j = j,i
            
        self.parent[i] = j
        self.size[j] += self.size[i]
        
        
        return j


        


from math import sqrt
from collections import Counter
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent = [i for i in range(len(A))]
        size = [1 for i in range(len(A))]
        primes = {}
        
        def find_parent(node):
            if node == parent[node]:
                return node
            parent[node] = find_parent(parent[node])
            return parent[node]
        
        def union(a, b):
            par_a = find_parent(a)
            par_b = find_parent(b)
            parent[par_a] = par_b
            
        def primes_set(n):
            for i in range(2, int(math.sqrt(n))+1):
                if n % i == 0:
                    return primes_set(n//i) | set([i])
            return set([n])
            
        for i, num in enumerate(A):
            pr_set = primes_set(num)
            for q in pr_set: 
                primes[q] = primes.get(q, []) + [i]
                        
        for i, nodes in list(primes.items()):
            nodes = list(set(nodes))
            for j in range(len(nodes)-1):
                union(nodes[j], nodes[j+1])

        return max(Counter([find_parent(i) for i in range(len(A))]).values())
            
            
            
        
        
            
        


class Solution:
    def largestComponentSize(self, nums: List[int]) -> int:
        uf = {}
        def find(x):
            if uf[x] != x:
                uf[x] = find(uf[x])
            return uf[x]
    
        def union(x, y):
            uf.setdefault(x, x)
            uf.setdefault(y, y)            
            uf[find(x)] = uf[find(y)]
        
        for num in nums:
            union(num, num)            
            for i in range(2, int(math.sqrt(num)) + 1):
                if num % i == 0:
                    union(num, i)
                    union(num//i, i)
        
        group_counter = collections.Counter()
        for num in nums:
            group_counter[find(num)] += 1
        
        return max(group_counter.values())


class UnionFind:
    def __init__(self, nums):
        self.nums = nums
        self.groups = list(range(len(nums)))
        self.sizes = [1] * len(nums)
    
    def union(self, a, b):
        a, b = self.find(a), self.find(b)
        if a == b:
            return
        
        if self.sizes[a] < self.sizes[b]:
            a, b = b, a

        self.sizes[a] += self.sizes[b]
        self.groups[b] = self.groups[a]

    def find(self, a):
        head = self.groups[a]
        while head != self.groups[head]:
            head = self.groups[head]

        node = self.groups[a]
        while node != self.groups[node]:
            node, self.groups[node] = self.groups[node], head

        return head

    def largest(self):
        return max(self.sizes)

class Solution:
    def largestComponentSize(self, a: List[int]) -> int:
        def factors(n):
            ans = {n}
            for i in range(2, int(math.sqrt(n)) + 1):
                if n % i == 0:
                    ans.add(i)
                    ans.add(n // i)
            return ans
        
        uf = UnionFind(a)
        primes = defaultdict(list)
        for i, num in enumerate(a):
            pr_set = factors(num)
            for prime in pr_set:
                primes[prime].append(i)
        
        for prime, idxs in primes.items():
            for i in range(len(idxs) - 1):
                uf.union(idxs[i],idxs[i + 1])
        return uf.largest()

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        graph = defaultdict(list)
        uf = UnionFind(len(A))
        
        for i, num in enumerate(A):
            prime_factors = set(self.get_prime_factors(num))
            for factor in prime_factors:
                graph[factor].append(i)
        
        for factor in graph:
            indices = graph[factor]
            for i in range(len(indices)-1):
                uf.union(indices[i], indices[i+1])
        
        counter = Counter()
        for i in range(len(A)):
            root = uf.find(i)
            counter[root] += 1
        
        return max(counter.values())
        
    def get_prime_factors(self, num):
        res = []
        factor = 2
        while num >= factor*factor:
            if num % factor == 0:
                res.append(factor)
                num = num // factor
            else:
                factor += 1
        res.append(num)
        return res

class UnionFind:
    def __init__(self, n):
        self.parent = list(range(n))
    
    def union(self, x, y):
        rootx = self.find(x)
        rooty = self.find(y)
        if rootx == rooty:
            return False
        self.parent[rooty] = rootx
        return True
    
    def find(self, x):
        while x != self.parent[x]:
            self.parent[x] = self.parent[self.parent[x]]
            x = self.parent[x]
        return x
        
            


from math import sqrt
from collections import Counter

class DisjointSet:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
    
    def find(self, x):
        # Does path compression as well
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
            
        return self.parent[x]
    
    def union(self, x, y):
        root1 = self.find(x)
        root2 = self.find(y)
        
        self.parent[root2] = root1
        
    
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        n = len(A)
        
        ds = DisjointSet(n)
    
        def prime_set(n):
            for i in range(2, int(sqrt(n)) + 1):
                if n % i == 0:
                    return prime_set(n // i) | set([i])
            
            return set([n])
        
        primes = {}
        for i in range(n):
            for prime in prime_set(A[i]):
                primes[prime] = primes.get(prime, []) + [i]
            
        for _, indices in list(primes.items()):
            for i in range(len(indices) - 1):
                ds.union(indices[i], indices[i + 1])
            
        print((ds.parent))
        print(primes)
        
        return max(Counter([ds.find(i) for i in range(n)]).values())


# Largest Component Size by Common Factor
# https://www.youtube.com/watch?v=6Ud_4A9qTp4

from math import sqrt
from collections import Counter
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent = {}
        
        def ufind(a):
            if a not in parent:
                parent[a] = a
            if a != parent[a]:
                parent[a] = ufind(parent[a])
            return parent[a]
        
        def uunion(a,b):
            ua = ufind(a)
            ub = ufind(b)

            parent[ua] = ub
        
        count = Counter()
        for x in A:
            y = 2
            factors = []
            # # 1
            # find common & primes of X
            while x >= y * y:
                if x % y == 0:
                    factors.append(y)
                    # delete y common
                    while x % y == 0:
                        x //= y
                y += 1
            if x > 1: # find new primes
                factors.append(x)

            # # 2
            # zip(factors, factors[1:]) -> [a,b,c] => ab , bc ~~
            # Linking parent (if link => small -> large)
            for a, b in zip(factors, factors[1:]):
                uunion(a, b)

            # # 3
            # prime > 0 
            # minimum factors += 1
            if len(factors)>0:
                count[factors[0]] += 1
        
        final_count = Counter()

        for key in count.keys():
            final_count[ufind(key)] += count[key]

        best = 0
        for key in final_count.keys():
            best = max(best, final_count[key])

        return best

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent={}
        def ufind(a):
            if a not in parent:
                parent[a]=a
            if a!= parent[a]:
                parent[a]=ufind(parent[a])
            return parent[a]
        
        def uunion(a,b):
            ua=ufind(a)
            ub=ufind(b)
            
            parent[ua]=ub
        
        count = collections.Counter()
        for x in A:
            factors=[]
            y=2
            while x>=y*y:
                if x%y==0:
                    factors.append(y)
                    while x%y==0:
                        x//=y
                y+=1
            if x>1:
                factors.append(x)
                
            for a,b in zip(factors,factors[1:]):
                uunion(a,b)
            
            if len(factors)>0:
                count[factors[0]]+=1
        
        final_count = collections.Counter()
        for key in count.keys():
            final_count[ufind(key)]+=count[key]
        
        best=0
        for key in final_count.keys():
            best=max(best,final_count[key])
        
        return best


class Primes:
    def __init__(self):
        M = ceil(sqrt(100000))+1
        isPrime = [True] * M
        k = 2
        while k < M:
            n=2
            while k*n < M:
                isPrime[k*n] = False               
                n += 1
            k += 1
            while k < M and not isPrime[k]:
                k += 1
            
        self.primes = [k for k in range(2,M) if isPrime[k]]
        


class Solution:
    primes = Primes().primes       
        
    def largestComponentSize(self, A: List[int]) -> int:        
             
        def getPrimeFactors(a):
            ans = []
            for p in Solution.primes:
                if p*p > a: break
                if a%p==0:
                    ans.append(p)
                    while True:
                        a = a // p
                        if a%p != 0: break
            if a > 1:
                ans.append(a)
            return ans
        
        N = len(A) 
        D = defaultdict(list)
        for k in range(N):
            a = A[k]
            ap = getPrimeFactors(a)
            for p in ap:
                D[p].append(k)
        dsu = DSU(N)
        for p,indexList in list(D.items()):            
            n = len(indexList)
            for i in range(n-1):
                dsu.union(indexList[i],indexList[i+1])
        return max(dsu.size)
    
    
class DSU: # Disjoint Set Union data structure
    
    def __init__(self, size):
        self.size = [1] * (size+1)
        self.parent = [i for i in range(size+1)]
        
        
    def find(self, i):
        
        while self.parent[i] != i:
            i, self.parent[i] = self.parent[i], self.parent[self.parent[i]]
        return i
        
        # The simplest recursive way... above just testing the Path splitting technique
        #if i != self.parent[i]:
        #    self.parent[i] = self.find(self.parent[i])
        #return self.parent[i]
    
    def union(self, i,j):
        i = self.find(i)
        j = self.find(j)
        
        if i == j: return
        
        if self.size[i] > self.size[j]:
            i,j = j,i
            
        self.parent[i] = j
        self.size[j] += self.size[i]
        
        
        return j


        


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        A = sorted(A)
        
        def factors(a):
            fact = set()
            for i in range(2, math.isqrt(a)+1):
                if a%i ==0:
                    fact.add(i)
                    fact.add(a//i)
            fact.add(a)
            return fact

        
        parent = [i for i in range(len(A))]
        nodes = [1] * len(A)
        rank = [1] * len(A)
        
        def find(a):
            if parent[a] == a:
                return a
            parent[a] = find(parent[a])
            return parent[a]
        
        def union(a,b):
            pa, pb = find(a), find(b)
            if rank[pa] >pb:
                parent[pb] = pa
                nodes[pa] += nodes[pb]
            elif rank[pa] >pb:
                parent[pa] = pb
                nodes[pb] += nodes[pa]
            else:
                parent[pb] = pa
                nodes[pa] += nodes[pb]
                rank[pa] +=1
        
        m = {}
        
        for i in range(len(A)):
            facts = factors(A[i])
            for f in facts:
                if f in m and find(i)  != find(m[f]):
                    union(i, m[f])
                else:
                    m[f] = i
            
                    
            
                    
        return max(nodes)
                    
                
                


from collections import defaultdict, Counter

class DSU:
    def __init__(self, N):
        self.par = list(range(N))
        self.rnk = [0] * N
        self.siz = [1] * N

    def find(self, x):
        if self.par[x] != x:
            self.par[x] = self.find(self.par[x])
        return self.par[x]

    def union(self, x, y):
        xr, yr = list(map(self.find, (x, y)))
        if xr == yr: return
        if self.rnk[xr] < self.rnk[yr]:
            xr, yr = yr, xr
        if self.rnk[xr] == self.rnk[yr]:
            self.rnk[xr] += 1

        self.par[yr] = xr 
        self.siz[xr] += self.siz[yr]

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        # Union-Find on Prime Factors
        # Time  complexity: O(N x (logM x logM + sqrt(M)))
        # Space complexity: O(M + N)
        # def primeDecompose(num):
        #     factor = 2
        #     prime_factors = []
        #     while num >= factor * factor:
        #         if num % factor == 0:
        #             prime_factors.append(factor)
        #             num //= factor
        #         else:
        #             factor += 1
        #     prime_factors.append(num)
        #     return prime_factors

        # dsu = DSU(max(A) + 1)
        # num_factor_map = {}

        # for num in A:
        #     prime_factors = list(set(primeDecompose(num)))
        #     # map a number to its first prime factor
        #     num_factor_map[num] = prime_factors[0]
        #     # merge all groups that contain the prime factors.
        #     for i in range(0, len(prime_factors) - 1):
        #         dsu.union(prime_factors[i], prime_factors[i + 1])

        # max_size = 0
        # group_count = defaultdict(int)
        # for num in A:
        #     group_id = dsu.find(num_factor_map[num])
        #     group_count[group_id] += 1
        #     max_size = max(max_size, group_count[group_id])

        # return max_size


        B = []
        for x in A:
            facs = []
            d = 2
            while d * d <= x:
                if x % d == 0:
                    while x % d == 0:
                        x //= d
                    facs.append(d)
                d += 1
            if x > 1 or not facs:
                facs.append(x)
            B.append(facs)

        primes = list({p for facs in B for p in facs})
        prime_to_index = {p: i for i, p in enumerate(primes)}

        dsu = DSU(len(primes))
        for facs in B:
            for x in facs:
                dsu.union(prime_to_index[facs[0]], prime_to_index[x])

        count = Counter(dsu.find(prime_to_index[facs[0]]) for facs in B)
        return max(count.values())
        



class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        uf = UnionFind(max(A))
        for num in A:
            for factor in range(2, int(sqrt(num)) + 1):
                if num % factor == 0:
                    uf.union(num, factor)
                    uf.union(num, num // factor)
        res = 0
        group_count = collections.defaultdict(int)
        for num in A:
            group_id = uf.find(num)
            group_count[group_id] += 1
            res = max(res, group_count[group_id])
        return res

class UnionFind:
    def __init__(self, size):
        self.parent = [i for i in range(0, size + 1)]
        self.size = [1] * (size + 1)
    
    def find(self, x):
        while self.parent[x] != x:
            self.parent[x] = self.parent[self.parent[x]]
            x = self.parent[x]
        return x

    def union(self, x, y):
        parent_x = self.find(x)
        parent_y = self.find(y)
        if parent_x == parent_y:
            return parent_x
        if self.size[parent_x] > self.size[parent_y]:
            parent_x, parent_y = parent_y, parent_x
        self.parent[parent_x] = parent_y
        self.size[parent_y] += self.size[parent_x]
        return parent_y


# Build the graph by checking if every pair of nodes has a common factor greater than one, and if
# it does, connect them together (Create an edge between them). The only issue with this is that it
# runs in N^2 time.
#
# Then, we use dfs to find the largest connected component?
#
# Using dfs to find the largest connected component is okay, as it runs in N time, the problem is
# finding every edge for every pair of numbers in A takes too long (N^2 time).
#
# We can't use dfs as there are too many pairs to make. What needs to be done instead is to use
# union find to group nodes by factors.

class DSU:
    
    def __init__(self):
        self.parent = defaultdict(lambda: -1)
        
    def union(self, x: int, y: int):
        xSet = self.find(x)
        ySet = self.find(y)
        self.parent[xSet] = ySet
        
    def find(self, x: int):
        if x not in self.parent:
            self.parent[x] = x
        if x != self.parent[x]:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
        
        
class Solution:
    
    def largestComponentSize(self, A: List[int]) -> int:
        counts = Counter()
        dsu = DSU()
        for node in A:
            k = 2
            factors = []
            while k * k <= node:
                if node % k == 0:
                    factors.append(k)
                    while node % k == 0:
                        node //= k
                        
                k += 1
            
            if node > 1:
                factors.append(node)
            
            for x, y in zip(factors, factors[1:]):
                dsu.union(x, y)
            
            if factors:
                counts[factors[0]] += 1
                
        finalCounts = Counter()
            
        for key in counts.keys():
            finalCounts[dsu.find(key)] += counts[key]

        return max(finalCounts.values())

class DSU:
    def __init__(self, N):
        self.p = list(range(N))

    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr

class Solution:
    def primes_set(self,n):
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self.primes_set(n//i) | set([i])
        return set([n])

    def largestComponentSize(self, A):
        n = len(A)
        UF = DSU(n)
        primes = defaultdict(list)
        for i, num in enumerate(A):
            pr_set = self.primes_set(num)
            for q in pr_set: primes[q].append(i)

        for _, indexes in list(primes.items()):
            for i in range(len(indexes)-1):
                UF.union(indexes[i], indexes[i+1])

        return max(Counter([UF.find(i) for i in range(n)]).values())
    
# class Solution:
#     def largestComponentSize(self, A: List[int]) -> int:
#         # go through A, 
#         # try each element from each group
#         ## if divides on element - accumulate groups, combine groups, add to group
#         ## else create new group
#         groups = []
#         for n in A:
#             indexesOfGroups = []
#             added = False
#             for i, g in enumerate(groups):
#                 for e in g:
#                     g = gcd(n, e)
#                     if g > 1:
#                         indexesOfGroups.append(i)
#                         added = True
#                         break
#             if not added:
#                 groups.append([n])        
#                 continue
#             if indexesOfGroups:
#                 mainGrIdx = indexesOfGroups[0]
#                 mainGr = groups[mainGrIdx]
#                 for i in range(len(indexesOfGroups)-1, 0, -1):
#                     idx = indexesOfGroups[i]
#                     mainGr.extend(groups[idx])
#                     del groups[idx]
#                 mainGr.append(n)    
#         # print(groups)    

#         mx = 0
#         for g in groups:
#             mx = max(mx, len(g))
#         return mx


from collections import defaultdict

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        us = UnionSet(max(A))
        num_fac_map = dict()
        
        for num in A:
            primes = list(self.getPrimes(num))
            
            num_fac_map[num] = primes[0]
            
            # union all factors of a number
            # eventually we know a number is linked to which factor that's linked most
            for i in range(len(primes) - 1):
                us.union(primes[i], primes[i + 1])
        
        _max = 0
        most_linked_fac_map = defaultdict(int)
        
        for num in A:
            fac = us.find(num_fac_map[num])
            most_linked_fac_map[fac] += 1
            _max = max(_max, most_linked_fac_map[fac])
        
        return _max
        
        
    def getPrimes(self, num):
        primes = set()
        factor = 2
        while num >= factor * factor:
            if num % factor == 0:
                primes.add(factor)
                num //= factor
            else:
                factor += 1
        primes.add(num)
        return primes
        
        
class UnionSet:
    
    def __init__(self, size):
        self.factors = [i for i in range(size + 1)]
        self.size = [1] * (size + 1)    # the number of factors that this factor can union to
    
    def find(self, ix):
        while self.factors[ix] != ix:
            ix = self.factors[ix]
        return ix
    
    def union(self, ix1, ix2):
        p1, p2 = self.find(ix1), self.find(ix2)
        if p1 == p2:
            return
        
        # make p1 small set, p2 large set
        if self.size[p1] > self.size[p2]:
            p1, p2 = p2, p1
        
        # make small set's parent to be the larger set
        self.factors[p1] = p2
        self.size[p2] += self.size[p1]

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        primes = []
        for x in range(2,int(max(A)**0.5)+1):
            for y in primes:
                if x%y == 0:
                    break
            else:
                primes.append(x)
        
        factors = collections.defaultdict(list)
        for a in A:
            x = a
            for p in primes:
                if p*p > x:
                    break
                if x%p == 0:
                    factors[a].append(p)
                    while x%p == 0:
                        x //= p
            if x > 1:
                factors[a].append(x)
                primes.append(x)
                
        n = len(primes)
        parent = [i for i in range(n)]
        PrimeToIndex = {p:i for i,p in enumerate(primes)}
        
        def find(i):
            if i != parent[i]:
                parent[i] = find(parent[i])
            return parent[i]
        
        def union(i,j):
            pi,pj = find(i),find(j)
            if pi != pj:
                parent[pi] = pj
                
                
                
        for a in A:
            if factors[a]:
                p0 = factors[a][0]
                for p in factors[a][1:]:
                    union(PrimeToIndex[p],PrimeToIndex[p0])
        
        count = collections.Counter(find(PrimeToIndex[factors[a][0]]) for a in A if factors[a])
        return max(count.values())
        
        


class DisjointSetUnion(object):
    
    def __init__(self, size):
        self.parent = [i for i in range(size + 1)]
        self.size = [1] * (size + 1)
        
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        
        return self.parent[x]

    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        if px == py:
            return px
        
        # connect the two sets (components)
        if self.size[px] > self.size[py]:
            # add the node to the union with less members
            # keeping px as the index of the smaller component
            px, py = py, px
        self.parent[px] = py
        self.size[py] += self.size[px]
        return py
            
            
class Solution:
    
    def primeDecompose(self, num):
        factor = 2
        prime_factors = []
        while num >= factor * factor:
            if num % factor == 0:
                prime_factors.append(factor)
                num = num // factor
            else:
                factor += 1
        
        prime_factors.append(num)
        return prime_factors

    def largestComponentSize(self, A: List[int]) -> int:
        dsu = DisjointSetUnion(max(A))
        num_factor_map = {}
        
        for num in A:
            prime_factors = list(set(self.primeDecompose(num)))
            num_factor_map[num] = prime_factors[0]
            for i in range(0, len(prime_factors) - 1):
                dsu.union(prime_factors[i], prime_factors[i+1])
        max_size = 0
        group_count = defaultdict(int)
        for num in A:
            group_id = dsu.find(num_factor_map[num])
            group_count[group_id] += 1
            max_size = max(max_size, group_count[group_id])
        
        return max_size



import collections


class UnionFind:
    def __init__(self, n):
        self.n = n
        self.parents = list(range(n))
        self.ranks = [0 for _ in range(n)]

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

    def merge(self, x, y):
        x = self.get_root(x)
        y = self.get_root(y)
        if x != y:
            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


def factorize_all(n):
    factorizations = [None] * (n + 1)
    factorizations[0] = {}
    factorizations[1] = {}
    for p in range(2, n + 1):
        if factorizations[p] is None:
            for k in range(1, n // p + 1):
                if factorizations[k] is None:
                    continue
                fs = factorizations[k].copy()
                if p in fs:
                    fs[p] += 1
                else:
                    fs[p] = 1
                factorizations[k * p] = fs
    return factorizations


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        uf = UnionFind(max(A) + 1)
        factorization = factorize_all(max(A))
        ids = dict()
        for a in A:
            if a < 2:
                continue
            factors = list(factorization[a].keys())
            ids[a] = factors[0]
            for p0, p1 in zip(factors, factors[1:]):
                uf.merge(p0, p1)
                
        counter = collections.defaultdict(int)
        maxval = 0
        for a in A:
            if a < 2:
                continue
            id_ = uf.get_root(ids[a])
            counter[id_] += 1
            maxval = max(maxval, counter[id_])
            
        return maxval

# https://www.tutorialspoint.com/largest-component-size-by-common-factor-in-cplusplus

from collections import defaultdict as dd

def find(parent,num) :

    if parent[num]==-1 :
        return num
    else :
        parent[num] = find(parent,parent[num])
    
    return parent[num]

def union(parent,u,v) :
    par_u = find(parent,u)
    par_v = find(parent,v)
    if par_u != par_v :
        parent[par_v] = par_u
        
class Solution:
    def largestComponentSize(self, a: List[int]) -> int:
        ans=0
        n=len(a)
        parent=[-1]*100001
        
        for i in range(n) :
            x=a[i]
            
            for j in range(2, int(x**0.5)+1) :
                
                if x%j == 0 :
                    
                    union(parent,j,x)
                    union(parent,x//j,x)
                               
        count = dd(int)    
        for i in range(len(a)) :
            par = find(parent,a[i])
            count[par]+=1
            ans=max(ans,count[par])

        return ans
                    
# from collections import defaultdict as dd

# def find(parent,num) :

#     if parent[num]==-1 :
#         return num
#     else :
#         parent[num] = find(parent,parent[num])
    
#     return parent[num]

# def union(parent,rank,u,v) :
#     par_u = find(parent,u)
#     par_v = find(parent,v)
    
#     if par_u == par_v :
#         return 
    
#     if rank[par_u] >= rank[par_v] :
#         parent[par_v] = par_u
#         rank[par_u] += rank[par_v]

#     else :
#         parent[par_u] = par_v
#         rank[par_v] += rank[par_u]
        

# class Solution:
#     def largestComponentSize(self, a: List[int]) -> int:
#         ans=0
#         n=len(a)
#         parent=[-1]*n
#         rank=[1]*n
        
#         factor = dd(int)
        
#         for i in range(n) :
#             x=a[i]
            
#             for j in range(2, int(x**0.5)+1) :
                
#                 if x%j == 0 :
#                     if factor[j] :
#                         union(parent,rank,factor[j],i)
                        
#                     else :
#                         factor[j]=i
                        
#                     if factor[x//j] :
#                         union(parent,rank,factor[x//j],i)

#                     else :
#                         factor[x//j]=i
                            
#             if factor[x] :
#                 union(parent,rank,factor[x],i)
#             else :
#                 factor[x]=i
                
#             ans = max(ans,rank[find(parent,i)])
            
#         return ans


from math import sqrt

class DSU:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [1] * n
        
    def find(self, x):
        if self.parent[x] == x:
            return x
        
        self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def union(self, x, y):
        if self.find(x) == self.find(y): return
        
        xrank = self.rank[x]
        yrank = self.rank[y]
        
        if xrank < yrank:
            self.parent[self.find(x)] = self.find(y)
            self.rank[x] = self.rank[y] + 1
        else: 
            self.parent[self.find(y)] = self.find(x)
            self.rank[y] = self.rank[x] + 1
        
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        n = len(A)
        
        uf = DSU(n)
        
        def fac(x):
            yield x
            for i in range(2, int(sqrt(x))+1): 
                if x % i == 0: 
                    yield i
                    yield x // i
                                
        graph = {}
        
        for idx, x in enumerate(A):   
            for e in fac(x):
                if e in graph: uf.union(idx, graph[e])
                graph[e] = idx
        
        ctr = collections.Counter()
        for i in range(n):
            ctr[uf.find(i)] += 1
        
        return ctr.most_common()[0][1]


from collections import Counter
class UnionFind:
    
    def __init__(self, size):
        self.parents = [i for i in range(size)]
        self.ranks = [0]*size
        
    def find(self, x):
        if x != self.parents[x]:
             self.parents[x] = self.find(self.parents[x])
        return self.parents[x]
    
    def union(self, x, y):
        xp, yp = self.find(x), self.find(y)
        if xp == yp:
            return
        if self.ranks[xp] < self.ranks[yp]: 
            self.parents[xp] = yp
        elif self.ranks[xp] > self.ranks[yp]: 
            self.parents[yp] = xp
        else:
            self.parents[xp] = yp
            self.ranks[yp] += 1


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        if not A:
            return 0
        
        n = max(A)
        dsu = UnionFind(n+1)
        
        for a in A:
            for k in range(2, int(a**0.5)+1):
                if a%k==0:
                    dsu.union(a, k)
                    dsu.union(a, a//k)
        
        return max(Counter([dsu.find(a) for a in A]).values())


# Start: 2020-08-30 10:49PM => 

class Solution:
    
    def largestComponentSize(self, A: List[int]) -> int:
        # initial: use union find?
        
        def get_primes_set(n):
            for i in range(2, int(math.sqrt(n))+1):
                if n % i == 0:
                    return get_primes_set(n//i) | set([i])
            return set([n])
        
        A = set(A)
        primes = set()
        
        children_of = collections.defaultdict(set)
        for a in A:
            ap = get_primes_set(a)
            prev = None
            for pr in ap:
                primes.add(pr)
                children_of[pr].add(a)
                if prev is not None:
                    children_of[pr].add(prev)
                    children_of[prev].add(pr)
                prev = pr
                
        print(children_of)
        
        seen = set()
        sizes = dict()
        # print(primes)
        for pr in primes:
            if pr in seen:
                continue
            sizes[pr] = 0
            to_explore = collections.deque([pr])
            # print(pr)
            while to_explore:
                # print(to_explore)
                curr = to_explore.popleft()
                if curr in seen:
                    continue
                seen.add(curr)
                sizes[pr] += curr in A
                for child in children_of[curr]:
                    to_explore.append(child)
        
        return max(sizes.values())
            


class UnionFind:
    def __init__(self, n): 
        self.ranks = [0]*n
        self.parents = [i for i in range(n)]
        
        
    def union(self, i, j): 
        pi = self.parent(i)
        pj = self.parent(j)
        if pi == pj: 
            return 
        else: 
            if self.ranks[pi] <= self.ranks[pj]: 
                self.parents[pi] = pj 
                self.ranks[pj] += 1 if self.ranks[pi] == self.ranks[pj] else 0 
            else: 
                self.parents[pj] = pi
                
    def parent(self, i): 
        if self.parents[i] != i: 
            self.parents[i] = self.parent(self.parents[i])
        return self.parents[i]

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        uf = UnionFind(max(A)+1)
        dic = {}
        for i, num in enumerate(A): 
            factor = self.decomp(num)
            dic[num] = factor[0]
            # print(num, factor)
            for i in range(0, len(factor)-1): 
                uf.union(factor[i], factor[i+1])
        
        count = collections.Counter()
        for num in A: 
            group_id = uf.parent(dic[num])
            count[group_id] += 1
        return max(count[i] for i in count)
        
    def decomp(self, num): 
        factor = 2
        ans = set()
        # print(\"num\", num)
        while num>=factor*factor: 
            if num%factor==0: 
                num //= factor 
                ans.add(factor)
            else: 
                factor += 1
        ans.add(num)
        # print(\"num end\", num)
        return list(ans)


class Solution:
    def find(self, parent: List[int], x: int):
        if not parent[x] == x:
            parent[x] = self.find(parent, parent[x])
        return parent[x]
    
    def largestComponentSize(self, A: List[int]) -> int:
        n, mx, res = 0, max(A), 0
        valtocnt = collections.Counter()
        parent = list(range(mx+1))  
        for num in A:
            for d in range(int(sqrt(num)), 1, -1):
                if num % d == 0:
                    parent[self.find(parent, num)] = parent[self.find(parent, d)]
                    parent[self.find(parent, num)] = parent[self.find(parent, num//d)]
        for num in A:
            valtocnt[self.find(parent, num)] += 1
            res = max(res, valtocnt[self.find(parent, num)])
        return res

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        primes = []
        for x in range(2, int(max(A)**0.5)+1):
            for y in primes:
                if x % y == 0:
                    break
            else:
                primes.append(x)
    
        factors = collections.defaultdict(list)         # compute factors of each 'a'
        for a in A:
            x = a
            for p in primes:
                if p*p > x:
                    break
                if x % p == 0:
                    factors[a].append(p)
                    while x % p == 0:
                        x //= p
            if x > 1:                                   # a new prime found
                factors[a].append(x)
                primes.append(x)
                
        primes = list(set(primes))
        n = len(primes)
        p2i = {p: i for i,p in enumerate(primes)}       # prime to index
        
        parent = [i for i in range(n)]                  # union-find on primes
        
        def find(i):
            if i != parent[i]:
                parent[i] = find(parent[i])
            return parent[i]
        
        def union(i,j):
            pi, pj = find(i), find(j)
            if pi != pj:
                parent[pi] = pj

        for a in A:
            if factors[a]:
                p0 = factors[a][0]
                for p in factors[a][1:]:                # link two primes if they are factors of 'a'
                    union(p2i[p0], p2i[p])
        
        count = collections.Counter(find(p2i[factors[a][0]]) for a in A if factors[a])      # each 'a' corresponds to a prime index
        return max(count.values())


class UnionFind:
     def __init__(self, n:int)->None:
        self.parent = [i for i in range(n)]
        
     def find(self, x:int)->int:
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
     def union(self, a:int, b:int):
        self.parent[self.find(b)] = self.find(a)

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        uf = UnionFind(100001)
        for x in A:
            for i in range(2,int(sqrt(x))+1):
                if x % i == 0:
                    uf.union(i,x)
                    uf.union(x,x//i)
        count = 0
        hashMap = {}
        for x in A:
            xp = uf.find(x)
            count = max(count,1 + hashMap.get(xp,0))
            hashMap[xp] = 1 + hashMap.get(xp,0)
        return count
        
        
                
        
                
            


class Node:
    def __init__(self,data):
        self.data=data
        self.p=None
    
class Solution:
    def find(self,node):
        if(node.p==node):
            return node
        node.p=self.find(node.p)
        return node.p
    
    def prime(self,val,d):
        for i in range(2,int((val)**(0.5))+1):
            if(val%i==0):
                if(i not in d):
                    node=Node(i)
                    node.p=node
                    d[i]=node
                    
                if(self.find(d[val].p)==d[val]):
                    d[val].p=d[i]
                else:
                    self.find(d[i]).p=self.find(d[val])
                v=val//i
                if(v!=i):
                    if(v not in d):
                        node=Node(v)
                        node.p=node
                        d[v]=node
                    self.find(d[v]).p=self.find(d[val])
                    
    def largestComponentSize(self, A: List[int]) -> int:
        d={}
        if(not A):
            return 0
        for i in A:
            if(i not in d):
                node=Node(i)
                node.p=node
                d[i]=node
            self.prime(i,d)
        fr=defaultdict(int)
        
        for i in A:
            fr[self.find(d[i]).data]+=1
        mx=0
        for i in fr.values():
            mx=max(i,mx)
        return mx

class UnionFind:
    def __init__(self, N):
        self.parents = [i for i in range(N)]
        self.size = [1]*N

    def find(self, x):
        root = x
        while root != self.parents[root]:
            root = self.parents[root]

        while x != root:
            parent = self.parents[x]
            self.parents[x] = root
            x = parent

        return root

    def union(self, a, b):
        root_a = self.find(a)
        root_b = self.find(b)
        if root_a == root_b:
            return False

        if self.size[root_a] <= self.size[root_b]:
            self.parents[root_a] = root_b
            self.size[root_b] += self.size[root_a]
        else:
            self.parents[root_b] = root_a
            self.size[root_a] += self.size[root_b]

        return True

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        uf = UnionFind(max(A)+1)
    
        for a in A:
            for factor in range(2, int(math.sqrt(a)) + 1):
                if a % factor == 0:
                    uf.union(a, factor)
                    uf.union(a, a // factor)
                
        group2size = defaultdict(int)
        for a in A:
            group2size[uf.find(a)] += 1
    
        return max(group2size.values())
        


class DSU:
    def __init__(self, N):
        self.parent = list(range(N))
        self.size = [1] * N
        
    def find(self, x):
        root = x
        while root != self.parent[root]:
            root = self.parent[root]
        
        while x != root:
            temp = self.parent[x]
            self.parent[x] = root
            x = temp
            
        return root
    
    def union(self, x, y):
        root1 = self.find(x)
        root2 = self.find(y)
        
        if root1 == root2: return False
        
        if self.size[root1] > self.size[root2]:
            self.parent[root2] = root1
            self.size[root1] += self.size[root2]
        else:
            self.parent[root1] = root2
            self.size[root2] += self.size[root1]
        
        return True
    

class Solution:
#     def commonFactor(self, x, y):
#         if x == y: return True
#         if y > x: return self.commonFactor(y, x)

#         while y:
#             x, y = y, x % y

#         return x != 1
        
    def largestComponentSize(self, A: List[int]) -> int:
        dsu = DSU(100001)
        
        for x in A:
            for j in range(2, int(x ** 0.5) + 1):
                if x % j == 0:
                    dsu.union(x, j)
                    dsu.union(x, x // j)
                    
        
        counter = collections.Counter()
        max_val = 0
        for x in A:
            counter[dsu.find(x)] += 1
        return counter.most_common(1)[0][1]

class DisjointSetUnion():
    def __init__(self, size):
        self.parents = [i for i in range(size + 1)]
        self.size = [1] * (size + 1)

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

    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        # x and y are in the same set
        if px == py:
            return px
        if self.size[px] > self.size[py]:
            px, py = py, px
        self.parents[px] = py
        self.size[py] += self.size[px]
        return py

import math
from collections import defaultdict
class Solution:
    def largestComponentSize(self, A) -> int:
        dsu = DisjointSetUnion(max(A))
        for a in A:
            for factor in range(2, int(math.sqrt(a)) + 1):
                if a % factor == 0:
                    dsu.union(a, factor)
                    dsu.union(a, a // factor)
        max_size = 0
        group_count = defaultdict(int)
        for a in A:
            idx = dsu.find(a)
            group_count[idx] += 1
            max_size = max(max_size, group_count[idx])
        return max_size

class DSU:
    def __init__(self, N):
        self.p = list(range(N))

    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr

class Solution:
    def primes_set(self,n):
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self.primes_set(n//i) | set([i])
        return set([n])

    def largestComponentSize(self, A):
        n = len(A)
        UF = DSU(n)
        primes = defaultdict(list)
        for i, num in enumerate(A):
            q=2
            while q*q<=num:
                if num%q==0:
                    primes[q].append(i)
                    while num%q==0:
                        num=num//q
                q+=1
            if num>1:
                primes[num].append(i) 

        for _, indexes in primes.items():
            for i in range(len(indexes)-1):
                UF.union(indexes[i], indexes[i+1])

        return max(Counter([UF.find(i) for i in range(n)]).values())


class UnionFind:
    def __init__(self, size):
        self.parent = [i for i in range(size + 1)] 
        self.rank = [1] * (size + 1)    
    
    def find(self, num):
        if num != self.parent[num]:
            self.parent[num] = self.find(self.parent[num])
        
        return self.parent[num]
    
    def union(self, a, b):
        pa = self.find(a)
        pb = self.find(b)
        
        if pa == pb:
            return
        
        if self.rank[pa] > self.rank[pb]:
            self.parent[pb] = pa
        elif self.rank[pb] > self.rank[pa]:
            self.parent[pa] = pb
        else:
            self.parent[pb] = pa
            self.rank[pa] += 1



            
import collections               
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        uf = UnionFind(max(A))
        a_to_factor = {}
        for a in A:
            factors = self.find_factors(a)
            a_to_factor[a] = factors[0]
            for i in range(0, len(factors) - 1):
                uf.union(factors[i], factors[i + 1])
        
        parent_to_count = collections.defaultdict(int)
        max_num = 0
        for a in A:
            parent = uf.find(a_to_factor[a])
            parent_to_count[parent] += 1 
            max_num = max(max_num, parent_to_count[parent])
        
        return max_num
            
    
    def find_factors(self, num):
        if num == 1:
            return [1]
        i = 2
        factors = list()
        while num >= i * i:
            if num % i == 0:
                factors.append(i)
                num = num//i
            else:
                i += 1
        factors.append(num)
        return list(set(factors))
        
        


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        dsu=Disj(max(A))
        for a in A:
            for factor in range(2,int(sqrt(a))+1):
                if a%factor==0:
                    dsu.union(a,factor)
                    dsu.union(a,a//factor)
        maxx=0
        group_count=defaultdict(int)
        for a in A:
            group_id=dsu.find(a)
            #print(group_id)
            group_count[group_id]+=1
            maxx=max(maxx,group_count[group_id])
        return maxx
        
class Disj(object):
    def __init__(self,size):
        self.parent=[i for i in range(size+1)]
        self.size=[1]*(size+1)
    
    def find(self,x):
        if self.parent[x]!=x:
            self.parent[x]=self.find(self.parent[x])
        return self.parent[x]
    
    def union(self,x,y):
        px,py=self.find(x),self.find(y)
        if px==py:
            return px
        if self.size[px]>self.size[py]:
            px,py=py,px
        self.parent[px]=py
        self.size[py]+=self.size[px]
        return py

from collections import defaultdict

class DSU:
    def __init__(self, N):
        self.par = list(range(N))
        self.rnk = [0] * N
        self.siz = [1] * N

    def find(self, x):
        if self.par[x] != x:
            self.par[x] = self.find(self.par[x])
        return self.par[x]

    def union(self, x, y):
        xr, yr = list(map(self.find, (x, y)))
        if xr == yr: return
        if self.rnk[xr] < self.rnk[yr]:
            xr, yr = yr, xr
        if self.rnk[xr] == self.rnk[yr]:
            self.rnk[xr] += 1

        self.par[yr] = xr 
        self.siz[xr] += self.siz[yr]

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        # Union-Find on Prime Factors
        def primeDecompose(num):
            factor = 2
            prime_factors = []
            while num >= factor * factor:
                if num % factor == 0:
                    prime_factors.append(factor)
                    num //= factor
                else:
                    factor += 1
            prime_factors.append(num)
            return prime_factors

        dsu = DSU(max(A) + 1)
        num_factor_map = {}

        for num in A:
            prime_factors = list(set(primeDecompose(num)))
            # map a number to its first prime factor
            num_factor_map[num] = prime_factors[0]
            # merge all groups that contain the prime factors.
            for i in range(0, len(prime_factors) - 1):
                dsu.union(prime_factors[i], prime_factors[i + 1])

        max_size = 0
        group_count = defaultdict(int)
        for num in A:
            group_id = dsu.find(num_factor_map[num])
            group_count[group_id] += 1
            max_size = max(max_size, group_count[group_id])

        return max_size



class UnionFind:
    def __init__(self, length):
        self.parents = {num: num for num in range(length)}
        self.ranks = {num: 1 for num in range(length)}
    
    def find(self, src):
        if self.parents[src] == src:
            return src
        
        self.parents[src] = self.find(self.parents[src])
        return self.parents[src]

    def union(self, src, dest):
        rootSrc, rootDest = self.find(src), self.find(dest)
        if rootSrc == rootDest:
            return -1
        
        if self.ranks[rootSrc] > self.ranks[rootDest]:
            self.parents[rootDest] = rootSrc
            self.ranks[rootSrc] += self.ranks[rootDest]
            return self.ranks[rootSrc]
        else:
            self.parents[rootSrc] = rootDest
            self.ranks[rootDest] += self.ranks[rootSrc]
            return self.ranks[rootDest]
        
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def genPrimes(num):
            i = 2
            while i * i <= num:
                if num % i == 0:
                    return set([i]) | genPrimes(num//i)
                i += 1
            return set([num])

        uf = UnionFind(len(A))
        primes = defaultdict(list)
        for i, num in enumerate(A):
            primesNum = genPrimes(num)
            for prime in primesNum:
                primes[prime].append(i)

        for _, indexes in primes.items():
            for i in range(len(indexes) - 1):
                uf.union(indexes[i], indexes[i + 1])
        return max(uf.ranks.values())

# Reference: https://leetcode.com/problems/largest-component-size-by-common-factor/discuss/819772/TLE-Python-GCD-%2B-Union-Find-%2B-Rank-Compression

from typing import List
from math import gcd, sqrt
from collections import defaultdict

class DSU:
    def __init__(self, size):
        self.sizes = [1] * size
        self.parent = [i for i in range(size)]

    def find(self, u):
        if self.parent[u] != u:
            self.parent[u] = self.find(self.parent[u])
        return self.parent[u]

    def union(self, u, v):
        root_u = self.find(u)
        root_v = self.find(v)
        if root_u != root_v:
            if self.sizes[root_u] < self.sizes[root_v]:
                self.parent[root_u] = root_v
                self.sizes[root_v] += self.sizes[root_u]
            else:
                self.parent[root_v] = root_u
                self.sizes[root_u] += self.sizes[root_v]

    def size(self, u):
        return self.sizes[self.find(u)]

from itertools import count
def primes():
    def _not_divisible(n):
        return lambda x: x % n > 0
    yield 2
    odd = count(3, 2)
    while True:
        n = next(odd)
        yield n
        # sieve of Eratosthenes
        odd = list(filter(_not_divisible(n), odd))

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        # O(n * sqrt(max(A)))
        dsu = DSU(max(A) + 1)   # 0 is not being used

        for x in A:
            for factor in range(2, int(sqrt(x)) + 1):
                if x % factor == 0:
                    dsu.union(x, factor)
                    dsu.union(x, x // factor)

        ans, counter = 0, defaultdict(int)
        for x in A:
            counter[dsu.find(x)] += 1
            ans = max(ans, counter[dsu.find(x)])
        return ans

        # # O(n^2)
        # dsu = DSU(len(A))
        # for i in range(len(A)):
        #     for j in range(len(A)):
        #         if i != j and gcd(A[i], A[j]) > 1:
        #             dsu.union(i, j)
        # return max(dsu.sizes)


from collections import Counter, defaultdict, OrderedDict, deque
from bisect import bisect_left, bisect_right
from functools import reduce, lru_cache
from typing import List
import itertools
import math
import heapq
import string
true = True
false = False
MIN, MAX, MOD = -0x3f3f3f3f, 0x3f3f3f3f, 1000000007


#
# @lc app=leetcode id=952 lang=python3
#
# [952] Largest Component Size by Common Factor
#
# https://leetcode.com/problems/largest-component-size-by-common-factor/description/
#
# algorithms
# Hard (30.37%)
# Total Accepted:    18.1K
# Total Submissions: 53.6K
# Testcase Example:  '[4,6,15,35]'
#
# Given a non-empty array of unique positive integers A, consider the following
# graph:
#
#
# There are A.length nodes, labelled A[0] to A[A.length - 1];
# There is an edge between A[i] and A[j] if and only if A[i] and A[j] share a
# common factor greater than 1.
#
#
# Return the size of the largest connected component in the graph.
#
#
#
#
#
#
#
# Example 1:
#
#
# Input: [4,6,15,35]
# Output: 4
#
#
#
#
# Example 2:
#
#
# Input: [20,50,9,63]
# Output: 2
#
#
#
#
# Example 3:
#
#
# Input: [2,3,6,7,4,12,21,39]
# Output: 8
#
#
#
# Note:
#
#
# 1 <= A.length <= 20000
# 1 <= A[i] <= 100000
#
#
#
#
#
#
class UF:
    def __init__(self, n):
        self.p = list(range(n))
        self.size = [1] * n

    def merge(self, x, y):
        # Merge by size of set
        px, py = self.find(x), self.find(y)
        if px == py: return
        if self.size[px] < self.size[py]:
            self.p[px] = py
            self.size[py] += self.size[px]
        else:
            self.p[py] = px
            self.size[px] += self.size[py]

    def find(self, x):
        if x != self.p[x]:
            self.p[x] = self.find(self.p[x])
        return self.p[x]


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        uf = UF(max(A) + 1)
        for n in A:
            for i in range(2, math.ceil(math.sqrt(n)) + 1):
                if n % i == 0:
                    uf.merge(n, i)
                    uf.merge(n, max(n // i, 2))

        return Counter(list(map(uf.find, A))).most_common()[0][1]


sol = Solution()

ns = [2, 3, 6, 7, 4, 12, 21, 39]
ns = [1, 2, 3, 4, 5, 6, 7, 8, 9]
ns = [32, 5, 8, 11, 13, 78, 61, 16, 83, 22, 28, 93]


#https://leetcode.com/problems/largest-component-size-by-common-factor/discuss/581394/Python-1032ms-beat-100-time-and-space
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        primes = []
        for x in range(2, int(max(A)**0.5)+1):
            for y in primes:
                if x % y == 0:
                    break
            else:
                primes.append(x)
    
        factors = collections.defaultdict(list)         # compute factors of each 'a'
        for a in A:
            x = a
            for p in primes:
                if p*p > x:
                    break
                if x % p == 0:
                    factors[a].append(p)
                    while x % p == 0:
                        x //= p
            if x > 1:                                   # a new prime found
                factors[a].append(x)
                primes.append(x)
                
        primes = list(set(primes))
        n = len(primes)
        p2i = {p: i for i,p in enumerate(primes)}       # prime to index
        
        parent = [i for i in range(n)]                  # union-find on primes
        
        def find(i):
            if i != parent[i]:
                parent[i] = find(parent[i])
            return parent[i]
        
        def union(i,j):
            pi, pj = find(i), find(j)
            if pi != pj:
                parent[pi] = pj

        for a in A:
            if factors[a]:
                p0 = factors[a][0]
                for p in factors[a][1:]:                # link two primes if they are factors of 'a'
                    union(p2i[p0], p2i[p])
        
        count = collections.Counter(find(p2i[factors[a][0]]) for a in A if factors[a])      # each 'a' corresponds to a prime index
        return max(count.values())


# Reference: https://leetcode.com/problems/largest-component-size-by-common-factor/discuss/819772/TLE-Python-GCD-%2B-Union-Find-%2B-Rank-Compression

from math import gcd, sqrt
from collections import defaultdict

class DSU:
    def __init__(self, size):
        self.sizes = [1] * size
        self.parent = [i for i in range(size)]

    def find(self, u):
        if self.parent[u] != u:
            self.parent[u] = self.find(self.parent[u])
        return self.parent[u]

    def union(self, u, v):
        root_u = self.find(u)
        root_v = self.find(v)
        if root_u != root_v:
            if self.sizes[root_u] < self.sizes[root_v]:
                self.parent[root_u] = root_v
                self.sizes[root_v] += self.sizes[root_u]
            else:
                self.parent[root_v] = root_u
                self.sizes[root_u] += self.sizes[root_v]

    def size(self, u):
        return self.sizes[self.find(u)]


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        # O(n * sqrt(max(A)))
        dsu = DSU(max(A) + 1)   # 0 is not being used
        for x in A:
            for factor in range(2, int(sqrt(x)) + 1):
                if x % factor == 0:
                    dsu.union(x, factor)
                    dsu.union(x, x // factor)

        ans, counter = 0, defaultdict(int)
        for x in A:
            counter[dsu.find(x)] += 1
            ans = max(ans, counter[dsu.find(x)])
        return ans


        # # O(n^2)
        # dsu = DSU(len(A))
        # for i in range(len(A)):
        #     for j in range(len(A)):
        #         if i != j and gcd(A[i], A[j]) > 1:
        #             dsu.union(i, j)
        # return max(dsu.sizes)


import math

class DSU:
    def __init__(self, N):
        self.p = list(range(N))

    def find(self, x):
        if x != self.p[x]:
            self.p[x] = self.find(self.p[x])
        return self.p[x]

    def union(self, x, y):
        x_root, y_root = self.find(x), self.find(y)
        self.p[x_root] = y_root

class Solution:
    def prime_set(self, n):
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self.prime_set(n//i) | set([i])
        return set([n])

    def largestComponentSize(self, A: List[int]) -> int:               
        prime_map = {}
        for i in range(len(A)):
            P = self.prime_set(A[i])
            for p in P:
                if p not in prime_map:
                    prime_map[p] = []
                prime_map[p].append(i)
        
        DSU_groups = DSU(len(A))
        for _, group in prime_map.items():
            for i in range(len(group)-1):
                DSU_groups.union(group[i], group[i+1])
        
        return max(Counter([DSU_groups.find(x) for x in range(len(A))]).values())

#
# @lc app=leetcode id=952 lang=python3
#
# [952] Largest Component Size by Common Factor
#

# @lc code=start
from collections import defaultdict

   
class Solution:


    def largestComponentSize(self, A: List[int]) -> int:
        label = defaultdict(int)
        
        MAXA = 100001
        isPrime=[0 for _ in range(MAXA+1)]
        isPrime[0]=-1;isPrime[1]=-1 #0 and 1 are not prime numbers
        for i in range(2, MAXA):
            if isPrime[i]==0: #i is prime
                for multiple in range(i*i,MAXA+1,i):
                    if isPrime[multiple]==0:
                        isPrime[multiple]=i
                isPrime[i] = i # let i store itself for consistency

        def findRoot(key):
            if label[key] > 0:
                label[key] = findRoot(label[key])
                return label[key]
            else:
                return key
        
        def mergeRoot(k1, k2):
            r1, r2 = findRoot(k1), findRoot(k2)  
            if r1 != r2:
                r1, r2 = min(r1, r2), max(r1, r2)
                label[r1] += label[r2]
                label[r2] = r1
            return r1

        for x in A:
            root_id = 0
            prime_factors = set()
            while isPrime[x]!=-1:
                p = isPrime[x]
                root_id = findRoot(p) if root_id == 0 else mergeRoot(root_id, p)
                x //= p
            label[root_id] -= 1
        
        return -min(label.values())
# @lc code=end


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        dsu = DSU(max(A))
        
        for num in A:
            for factor in range(2, int(sqrt(num))+1):
                if num % factor == 0:
                    dsu.union(num, factor)
                    dsu.union(num, num // factor)
        
        max_size = 0
        group_count = {}
        for num in A:
            group_id = dsu.find(num)
            if group_id not in group_count:
                group_count[group_id] = 0
            group_count[group_id] += 1
        return max(group_count.values())

    
    
class DSU:
    def __init__(self, size):
        self.parent = [i for i in range(size+1)]
        self.size = [1 for i in range(size+1)]
    
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        if px == py:
            return px
        
        if self.size[px] > self.size[py]:
            px, py = py, px
        
        self.parent[px] = py
        self.size[py] += self.size[px]
        return py

class UnionFind:
    def __init__(self,n):
        self.parent = [i for i in range(n)]
        self.size = [1]*n
    def find(self,A):
        root=A
        while root!=self.parent[root]:
            root=self.parent[root]
            
        while A!=root:
            old_parent=self.parent[A]
            self.parent[A]=root
            A=old_parent
        return(root)
    
    def union(self,A,B):
        root_A = self.find(A)
        root_B = self.find(B)
        if root_A==root_B:
            return(False)
        
        if self.size[root_A]<self.size[root_B]:
            self.parent[root_A]=root_B
            self.size[root_B]+=self.size[root_A]
        else:
            self.parent[root_B]=root_A
            self.size[root_A]+=self.size[root_B]
            
        return(True)
class Solution:
    def gcd(self,a,b): 
    # Everything divides 0  
        if (b == 0): 
             return a 
        return gcd(b, a%b)
        
    def largestComponentSize(self, A: List[int]) -> int:
        dsu = UnionFind(max(A)+1) # cause we have max(A) as node

        # attribute each element in A
        #   to all the groups that lead by its factors.
        for a in A:
            for factor in range(2, int(sqrt(a))+1):
                if a % factor == 0:
                    dsu.union(a, factor)
                    dsu.union(a, a // factor)

        # count the size of group one by one
        group_count = defaultdict(int)
        for a in A:
            group_id = dsu.find(a)
            group_count[group_id] += 1
            
        return max(group_count.values())


#
# @lc app=leetcode id=952 lang=python3
#
# [952] Largest Component Size by Common Factor
#

# @lc code=start
from collections import defaultdict


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        small_primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317]
        label = defaultdict(int)
       
        def findRoot(key):
            if label[key] > 0:
                label[key] = findRoot(label[key])
                return label[key]
            else:
                return key
        
        def mergeRoot(k1, k2):
            r1, r2 = findRoot(k1), findRoot(k2)  
            if r1 != r2:
                r1, r2 = min(r1, r2), max(r1, r2)
                label[r1] += label[r2]
                label[r2] = r1
            return r1

        for x in A:
            root_id = 0
            t = sqrt(x) + 1
            for p in small_primes:
                if p > t:
                    break
                elif x % p == 0:
                    root_id = findRoot(p) if root_id == 0 else mergeRoot(root_id, p)
                    while x % p == 0:
                        x //= p
            if x != 1:
                root_id = findRoot(x) if root_id == 0 else mergeRoot(root_id, x)
            label[root_id] -= 1
        
        return -min(label.values())
# @lc code=end


from collections import defaultdict

class Solution:
    def largestComponentSize(self, a: List[int]) -> int:
        d = {}
        def find(x):
            if x != d.setdefault(x,x):
                d[x] = find(d[x])
            return d[x]
        def union(x,y):
            d[find(x)]=find(y)

        for n in a:
            for i in range(2,int(n**0.5)+1):
                if n%i: continue
                union(n,i)  
                union(n,n//i)

        counter = Counter(find(i) for i in a) 
        return max(counter.values())

import math

class DSU:
    def __init__(self, N):
        self.p = list(range(N))

    def find(self, x):
        while x != self.p[x]:
            self.p[x] = self.p[self.p[x]]
            x = self.p[x]   
        return x

    def union(self, x, y):
        x_root, y_root = self.find(x), self.find(y)
        self.p[x_root] = y_root

class Solution:
    def prime_set(self, n):
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self.prime_set(n//i) | set([i])
        return set([n])

    def largestComponentSize(self, A: List[int]) -> int:               
        prime_map = {}
        for i in range(len(A)):
            P = self.prime_set(A[i])
            for p in P:
                if p not in prime_map:
                    prime_map[p] = []
                prime_map[p].append(i)
        
        DSU_groups = DSU(len(A))
        for _, group in prime_map.items():
            for i in range(len(group)-1):
                DSU_groups.union(group[i], group[i+1])
        
        return max(Counter([DSU_groups.find(x) for x in range(len(A))]).values())

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        all_sets = dsu(max(A))
        
        for element in A:
            for factor in range(2, int(sqrt(element))+1):
                if element % factor == 0:
                    all_sets.union(element, factor)
                    all_sets.union(element, element // factor)
        
        result = 0
        count = defaultdict(int)
        for element in A:
            parent_id = all_sets.find(element)
            count[parent_id] += 1
            result = max(result, count[parent_id])
        return result
        
        
class dsu:
    def __init__(self, size):
        self.parent = [x for x in range(size + 1)]
        self.size = [1 for x in range(size + 1)]
    
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]

    def union(self, x , y):
        index_x = self.find(x)
        index_y = self.find(y)
        
        if index_x == index_y:
            return index_x
        
        if self.size[index_x] > self.size[index_y]:
            index_x, index_y = index_y, index_x
        self.parent[index_x] = index_y
        self.size[index_y] += self.size[index_x]
        return index_y

import collections
import math
class DSU:
    def __init__(self, n):
        self.par = list(range(n)) 
        #self.size = [1] * n
        
    def find(self, x):
        #print(x)
        if self.par[x] != x:
            self.par[x] = self.find(self.par[x])
        return self.par[x]
        #return x if self.par[x] == x else self.par[x] = self.find(self.par[x])
        
    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.par[xr] = yr
        #self.size[yr] += self.size[xr]
        #self.size[xr] = 0
        

class Solution:
    def sieve(self, n):#best sieve i have ever seen
        for i in range(2, int(math.sqrt(n)) + 1):
            if n % i == 0:
                return self.sieve(n//i) | set([i])
        #print(n) #this is def for 2,3
        return set([n])
    
    def largestComponentSize(self, A: List[int]) -> int:
        n = len(A)
        dsu = DSU(n)
        primes_and_multiples = collections.defaultdict(list)
        for i,num in enumerate(A):
            factors = self.sieve(num)
            for factor in factors:
                primes_and_multiples[factor].append(i)
        for primes in list(primes_and_multiples.values()):
            for i in range(len(primes) - 1): #could have done i-1, i with 1,len(primes)
                dsu.union(primes[i], primes[i+1])
        #return max(dsu.size)
        return max(collections.Counter([dsu.find(i) for i in range(n)]).values())
                
        
                
                
        
        



import math

class UnionFind:
    
    def __init__(self , size):
        self.id = [i for i in range(size)]
        
    def find(self , p):
        
        root = p
        while root != self.id[root]:
            root = self.id[root]
        
        while p != root:
            nxt = self.id[p]
            self.id[p] = root
            p = nxt
            
        return root
    
    
    def unify(self , p , q):
        
        root1 = self.find(p)
        root2 = self.find(q)
        if root1 == root2 : return 
        
        self.id[root2] = root1
            
        

        
    
    
        
        
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        max_val = max(A)
        uf = UnionFind(max_val + 1) # +1 for ease of access
        for num in A:
            for i in range(2 , int(math.sqrt(num))+1):
                if num % i == 0:
                    uf.unify(num , i)
                    uf.unify(num , num//i)
        
        parent_count = {}
        cur_max = 1
        for num in A:
            parent = uf.find(num)
            parent_count[parent] = 1 + parent_count.get(parent , 0)
            cur_max = max(cur_max , parent_count[parent])
            
        return cur_max
    
            
    


class UF:
    def __init__(self, n):
        self.roots = [i for i in range(n)]
        self.sz = [1 for _ in range(n)]
        
    def find(self, x):
        while x != self.roots[x]:
            self.roots[x] = self.roots[self.roots[x]]
            x = self.roots[x]
        return x
    
    def union(self, x, y):
        root_x = self.find(x)
        root_y = self.find(y)
        
        if self.sz[root_x] >= self.sz[root_y]:
            self.roots[root_y] = root_x
            self.sz[root_x] += self.sz[root_y]
        else:
            self.roots[root_x] = root_y
            self.sz[root_y] += self.sz[root_x]                        
import math 
from collections import defaultdict
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def factors(num):
            factor = 2
            prime_factors = []
            while num >= factor * factor:
                if num % factor == 0:
                    prime_factors.append(factor)
                    num = num // factor
                else:
                    factor += 1
            prime_factors.append(num)
            return prime_factors
            
        N = len(A)
        uf = UF(max(A)+1)
        num_factor_map = defaultdict(int)
        
        for num in A:
            num_factors = factors(num)
            num_factor_map[num] = num_factors[0]
            for i in range(len(num_factors)-1):
                uf.union(num_factors[i], num_factors[i+1])
                
        counter = defaultdict(int)
        for num in A:
            counter[uf.find(num_factor_map[num])] += 1
        return max(counter.values())
        


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        dsu = DSU(max(A)) 

        for n in A:
            for j in range(2, floor(sqrt(n))+1):
                if n % j == 0:
                    # print(n, j)
                    dsu.union(n, j)
                    dsu.union(n, n // j)
        
        maxSize = 0
        groupC = defaultdict(int)
        
        for n in A:
            parent = dsu.find(n)
            groupC[parent] += 1
            maxSize = max(maxSize, groupC[parent])
        
        
        return maxSize
            
        
class DSU:
    def __init__(self, largest):
        self.parent = [n for n in range(largest+1)]
        self.sz = [1] * (largest+1)
    def find(self, n):
        if n != self.parent[n]:
            self.parent[n] = self.find(self.parent[n])
        return self.parent[n]
        
    def union(self, n1, n2):
        xR, yR = self.find(n1), self.find(n2)
        
        if xR == yR:
            return
        
        if self.sz[xR] < self.sz[yR]:
            xR, yR = yR, xR
        
        self.parent[yR] = xR
        # self.sz[xR] += self.sz[yR]
        self.sz[yR] += self.sz[xR]

        
    def size(self, n):
        return self.sz[n]
            


from typing import Set

class myset(object):
    
    def __init__(self, maxi):
        self.s = [i for i in range(0, maxi+1)]
        self.l = [1]*(maxi+1)
        
    def find(self, x):
        if self.s[x] != x:
            self.s[x] = self.find(self.s[x])
            
        return self.s[x]
    
    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        
        if px == py:
            return px
        
        if px > py:
            px, py = py, px
            
        self.s[px]  = self.s[py]
        self.l[py] += self.l[px]
        
        return py

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        d:Dict[int][int] = {}
        p:List[int] = [1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317]
        
            
        def pf(x:int) -> List[int]:
            result:Set[int] = set()
            i:int = 0
            n:int = 2
            while x >= n*n:
                if x%n == 0:
                    result.add(n)
                    x = x // n
                else:
                    n += 1
            result.add(x)
            
            return list(result)
        
        if not A: return 0
        
        s = myset(max(A))
            
        mypf:List[int]
        for a in A:
            mypf = pf(a)
            print(mypf)
            d[a] = mypf[0]
            for i in range(len(mypf)-1):
                s.union(mypf[i], mypf[i+1])
        
        count = {}
        maxi:int = 0
        for a in A:
            id:int = s.find(d[a])
            if id in count:
                count[id] += 1
            else:
                count[id] = 1
            maxi = max(maxi, count[id])
            
        
        return maxi

class UnionFind:
    def __init__(self, count):
        self._parent = list(range(count))
        self._size = [1] * count
    
    def union(self, a, b):
        a, b = self.find(a), self.find(b)
        if a == b:
            return
        if self._size[a] < self._size[b]:
            a, b = b, a
        self._parent[b] = a
        self._size[a] += self._size[b]
    
    def find(self, x):
        while self._parent[x] != x:
            self._parent[x] = self._parent[self._parent[x]]
            x = self._parent[x]
        
        return self._parent[x]
    
    def size(self, x):
        return self._size[self.find(x)]
            

def prime_factors(num):
    if num < 2:
        return []
    
    factors = []
    
    for factor in range(2, int(num ** 0.5) + 1):
        if num % factor == 0:
            factors.append(factor)
            while num % factor == 0:
                num //= factor
            if num == 1:
                break
    
    if num > 1:
        factors.append(num)
    
    return factors


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        if not A:
            return 0
        
        length = len(A)
        union_find = UnionFind(length)
        roots = {}
        
        for index, num in enumerate(A):
            for factor in prime_factors(num):
                if factor not in roots:
                    roots[factor] = index
                union_find.union(roots[factor], index)
        
        return max(union_find.size(index) for index in range(length))


from collections import defaultdict


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        small_primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997]
        label = defaultdict(int)
       
        def findRoot(key):
            if label[key] > 0:
                label[key] = findRoot(label[key])
                return label[key]
            else:
                return key
        
        def mergeRoot(k1, k2):
            r1, r2 = findRoot(k1), findRoot(k2)
            if r1 != r2:
                r1, r2 = min(r1, r2), max(r1, r2)
                label[r1] += label[r2]
                label[r2] = r1
            return r1

        for x in A:
            root_id = 0
            for p in small_primes:
                if p > x:
                    break
                elif x % p == 0:
                    root_id = findRoot(p) if root_id == 0 else mergeRoot(root_id, p)
                    while x % p == 0:
                        x //= p
            if x != 1:
                root_id = findRoot(x) if root_id == 0 else mergeRoot(root_id, x)
            label[root_id] -= 1
        
        return -min(label.values())

import math
from collections import defaultdict
class UnionFind:
    def __init__(self, n):
        # initially, each node is an independent component
        self.parent = [i for i in range(n)]
        # keep the size of each component
        self.size = [1]*n
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    def union(self, x, y):
        px = self.find(x) 
        py = self.find(y)
        
        if px == py:
            return px
        #otherwise, connect the two sets
        if self.size[px] > self.size[py]:
            px,py = py,px
        self.parent[px] = py
        self.size[py] +=self.size[px]
        return py

class Solution:
    def largestComponentSize(self, A: list()) -> int:
        n = max(A)
        n_UnionFind = UnionFind(n+1)
        for a in A:
            for k in range(2, int(math.sqrt(a))+1):
                if a%k == 0:
                    n_UnionFind.union(a,k)
                    n_UnionFind.union(a,a//k)
        ans = 1
        count = defaultdict(int)
        for a in A:
            count[n_UnionFind.find(a)] +=1
            ans = max(ans, count[n_UnionFind.find(a)])
        return ans

#
# @lc app=leetcode id=952 lang=python3
#
# [952] Largest Component Size by Common Factor
#

# @lc code=start
from collections import defaultdict


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        small_primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997]
        label = defaultdict(int)
       
        def findRoot(key):
            if label[key] > 0:
                label[key] = findRoot(label[key])
                return label[key]
            else:
                return key
        
        def mergeRoot(k1, k2):
            r1, r2 = findRoot(k1), findRoot(k2)  
            if r1 != r2:
                r1, r2 = min(r1, r2), max(r1, r2)
                label[r1] += label[r2]
                label[r2] = r1
            return r1

        for x in A:
            root_id = 0
            t = sqrt(x) + 1
            for p in small_primes:
                if p > t:
                    break
                elif x % p == 0:
                    root_id = findRoot(p) if root_id == 0 else mergeRoot(root_id, p)
                    while x % p == 0:
                        x //= p
            if x != 1:
                root_id = findRoot(x) if root_id == 0 else mergeRoot(root_id, x)
            label[root_id] -= 1
        
        return -min(label.values())
# @lc code=end


class Solution:
    
    def primeDecompose(self, num):
        factor = 2
        prime_factors = []
        while num >= factor*factor:
            if not num % factor:
                prime_factors.append(factor)
                num //= factor
            else:
                factor += 1
        prime_factors.append(num)
        return prime_factors
    
    def largestComponentSize(self, A: List[int]) -> int:
        
        # 1. Find set of numbers that belongs to each prime factor
        factors = collections.defaultdict(set)
        for num in A:
            prime_factors = self.primeDecompose(num)
            for p in prime_factors:
                factors[p] |= set([num])
        
        primes = list(factors)
        
        group_id = 0
        group = {}
        prime_id = {}
        updated = set(primes)
        first_round = True
        
        for i in range(len(primes)):
            a = primes[i]
            
            if a not in factors:
                continue

            for b in list(factors):
                
                if b == a:
                    continue
                    
                if len(factors[b]) == 1:
                    del factors[b]
                elif factors[a] & factors[b]:
                    factors[a] |= factors[b]
                    del factors[b]

        return len(factors[max(factors, key = lambda f: len(factors[f]))])

class Solution:
    
    
            
    def largestComponentSize(self, A: List[int]) -> int:
        p = {}
        def find(i):
            if i not in p:
                p[i] = i
            if p[i] != i:
                p[i] = find(p[i])
            return p[i]

        for a in A:
            p[a] = a

        for a in A:
            limit = int(math.sqrt(a)) + 1
            for i in range(2, limit):
                if a % i == 0:
                    pa = find(a)
                    pi = find(i)
                    if pa in p and pi in p:
                        p[pa] = p[pi]

                    pa2 = find(a)
                    pi2 = find(a//i)

                    if pa2 in p and pi2 in p:
                        p[pa2] = p[pi2]

        c = {}
        for a in A:
            c[a] = find(a)

        ans = {}
        for k, v in list(c.items()):
            if v not in ans:
                ans[v] = 0
            ans[v] += 1

        return max(list(ans.values()))



class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        # common factor as key, value stored in a set
        parents = list(range(max(A) + 1))
        
        def find(x):
            # find the parent/root of x 
            # does path compression simultaneously
            while parents[x] != x:
                parents[x] = parents[parents[x]]
                x = parents[x]
            return x
        
        def union(x, y):
            parents[find(x)] = parents[find(y)]
        
        for num in A:
            for k in range(2, int(sqrt(num)) + 1): 
                if num % k == 0:
                    union(num, k)
                    union(num, num//k)
        counts = {}
        maxC = 0
        for num in A:
            target = find(num)
            counts[target] = counts.get(target, 0) + 1
            maxC = max(maxC, counts[target])
            
        return maxC


class unionfind:
    def __init__(self,size):
        self.parent=[i for i in range(size+1)]
        self.rank=[0 for _ in range(size+1)]
    def find(self,x):
        if(x!=self.parent[x]):
            self.parent[x]=self.find(self.parent[x])
        return(self.parent[x])
    def union(self,x,y):
        px=self.find(x)
        py=self.find(y)
        if(px==py):
            return(px)
        if(self.rank[px]>self.rank[py]):
            self.parent[py]=px
            return(px)
        else:
            self.parent[px]=py
            if(self.rank[px]==self.rank[py]):
                self.rank[py]+=1
            return(py)

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
            
        dsu=unionfind(max(A))
        for i in A:
            for factor in range(2,int(sqrt(i))+1):
                if((i%factor)==0):
                    dsu.union(i,factor)
                    dsu.union(i,i//factor)
                    
        max_size = 0
        group_count = defaultdict(int)
        for a in A:
            group_id = dsu.find(a)
            group_count[group_id] += 1
            max_size = max(max_size, group_count[group_id])

        return max_size

import math
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        n = max(A)
        array = [0] * (n+1)
        for i in range(n+1):
            array[i] = i
        
        def find(x:int) ->int:
            if x != array[x]:
                array[x] = find(array[x])
            return array[x]
            
        def union(x:int, y:int):
            xp = find(x)
            yp = find(y)
            if xp != yp:
                array[yp] = xp
        
        length = len(A)
        for i in range(length):
            for j in range(2, int(math.sqrt(A[i]))+1):
                if A[i]%j == 0:
                    union(j,A[i])
                    union(A[i],A[i]//j)
        maximum = 0
        res = {}
        for i in range(length):
            pal = find(A[i])
            maximum = max(maximum,res.get(pal,0)+1)
            res[pal] = res.get(pal,0) + 1
        return maximum


class Solution:

    def largestComponentSize(self, A: List[int]) -> int:
        
        parent = [-1]*100001
        
        def find(x , parent) :
            if parent[x] == -1 :
                return x
            
            parent[x] = find(parent[x] , parent)
            
            return parent[x]
        
        def union(x , y ) :
            xp = find(x , parent)
            yp = find(y , parent)
            
            if xp != yp :
                parent[yp] = xp
                
        for i in range(len(A)) :
            for j in range(2 , int(sqrt(A[i])) + 1) :
                
                if A[i] % j == 0 :
                    union(j , A[i])
                    union(A[i] , A[i] //j)
                    
        count = 0 
        cache = {}
        
        for x in A :
            p = find(x , parent) 
            count = max(count , 1 + cache.get(p , 0 ))
            
            cache[p] = cache.get(p , 0) + 1
            
        return count


import math
import collections
class Solution:
    def largestComponentSize(self, A) -> int:
        self.pre = {}
        for i in A:
            for d in range(2,int(math.sqrt(i)+1))[::-1]:
                if i%d == 0:
                    self.union(self.find(i),self.find(d))
                    self.union(self.find(i),self.find(i//d))
        count = collections.defaultdict(int)
        for i in A:
            count[self.find(i)] += 1
        return max(count.values())   
    def find(self,x):
        if x not in self.pre:
            self.pre[x] = x
        while self.pre[x] != x:
            self.pre[x] = self.pre[self.pre[x]]
            x = self.pre[x]
        return x
        
    def union(self,x,y):
        if self.pre[x] == self.pre[y] :return
        fx = self.find(x)
        fy = self.find(y)
        self.pre[fy] = fx

class Solution:
    def largestComponentSize(self, A: List[int], N = 100001) -> int:
        m = {}
        P = [i for i in range(N)]   # \\U0001f642 parent representative of disjoint sets
        L = [1] * N                 # \\U0001f925 length of parent representative's set
        def find(x):
            P[x] = P[x] if x == P[x] else find(P[x])
            return P[x]
        def union(a, b):
            a = find(a)
            b = find(b)
            if a == b:
                return
            P[b] = a  # arbitrary choice
            L[a] += L[b]
        for x in A:
            m[x] = x if x not in m else m[x]; union(m[x], x)      # case 1: x as a factor of itself
            for i in range(2, floor(sqrt(x)) + 1):
                if x % i:
                    continue
                j = x // i
                m[i] = x if i not in m else m[i]; union(m[i], x)  # case 2: i-th factor of x
                m[j] = x if j not in m else m[j]; union(m[j], x)  # case 3: j-th factor of x
        return max(L)  # \\U0001f3af maximum length of any parent representative's set


class Solution:
    
    def get_factors(self, n: int):
        factors = set()
        for factor in self.total_factors:
            if factor > n:
                break
            if n % factor == 0:
                factors.add(factor)
        for factor in factors:
            self.total_factors.remove(factor)
        return factors
    
    def get_prime_numbers(self, n_max: int):
        self.total_factors = [2,3]
        for val in range(3, n_max//2 + 2, 2):
            for i in range(3, int(val**0.5) + 2, 2):
                if val % i == 0:
                    break
                else:
                    if i >= int(val**0.5):
                        self.total_factors.append(val)
    
    def largestComponentSize(self, A: List[int]) -> int:
        #A.sort()
        #self.get_prime_numbers(A[-1])
        #print(self.total_factors)
        N = max(A) + 1
        nods = {d:d for d in range(N)}
        
        def find(x):
            root = x
            while nods[root] != root:
                root = nods[root]
            while nods[x] != root:
                parent = nods[x]
                nods[x] = root
                x = parent
            return root
        
        def union(x,y):
            rx,ry = find(x), find(y)
            if rx != ry:
                nods[ry] = rx
        
        for a in A:
            for factor in range(2, int(sqrt(a))+1):
                if a % factor == 0:
                    union(a, factor)
                    union(a, a//factor)
                    
        counts = collections.defaultdict(int)
        for a in A:
            counts[find(a)] += 1
        print(counts)
        return max(counts.values())
            
                
    
    def largestComponentSize_slow(self, A: List[int]) -> int:
        A.sort()
        self.get_prime_numbers(A[-1])
        #print(self.total_factors)
        max_len = 0
        while len(A) > max_len:
            factors = self.get_factors(A[0])
            new_len = 1
            A.remove(A[0])
            while factors:
                factor = factors.pop()
                to_remove = []
                for i in range(len(A)):
                    if A[i] % factor == 0:
                        new_len += 1
                        rest = A[i] / factor
                        while rest % factor == 0:
                            rest /= factor
                        factors = factors | self.get_factors(rest)
                        to_remove.append(i)
                A = [A[i] for i in range(len(A)) if i not in to_remove]
            max_len = max(new_len, max_len)
        return max_len
    
        


from collections import defaultdict, Counter
from functools import lru_cache

MAX_N = 100000


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        # compute factors
        sieve = Sieve(MAX_N)
        factors = defaultdict(list)
        for x in A:
            for factor in sieve.factorize(x):
                factors[factor].append(x)
        '''
        f = Factors()
        factors = defaultdict(list)
        for x in A:
            for factor in f.find_for(x):
                factors[factor].append(x)
        '''

        uf = UnionFind()
        for values in list(factors.values()):
            for i in range(1, len(values)):
                uf.connect(values[i-1], values[i])
                
        return max(list(Counter(uf.root(x) for x in A).values()), default=0)
        '''
        
        # build bipartite graph from factors and values
        g = Graph()
        for factor, values in factors.items():
            g.add_factor(factor)
            for value in values:
                g.add_value(value)
                g.connect(factor, value)
        
        return g.find_largest_connected_size()
        '''

    
class UnionFind:
    def __init__(self):
        self.parents = {}
    
    def connect(self, a, b):
        if a not in self.parents:
            self.parents[a] = a
        
        if b not in self.parents:
            self.parents[b] = b
            
        root = self.root(b)
        self.parents[self.root(a)] = root
        return root
    
    def root(self, a):
        if a not in self.parents:
            self.parents[a] = a
            return a

        if a == self.parents[a]:
            return a
        
        self.parents[a] = self.root(self.parents[a])
        
        return self.parents[a]


class Sieve:
    def __init__(self, max_n):
        self.primes = self._compute_primes(max_n)
        # better runtime than simply empty dict!
        self.factors = {p: [p] for p in self.primes}
        
    def _compute_primes(self, max_n):
        primes = list()
        sieve = [True] * (max_n+1)
        for prime in range(2, max_n+1):
            if not sieve[prime]:
                continue
            
            primes.append(prime)
            
            # better runtime than a manual while loop!
            for j in range(prime+prime, max_n+1, prime):
                sieve[j] = False
        
        return primes
    
    # this hurts the runtime!
    #@lru_cache(maxsize=MAX_N)
    def factorize(self, n):
        if n in self.factors:
            return self.factors[n]
        
        self.factors[n] = factors = set()
        work = n
        for prime in self.primes:
            # does not improve runtime!
            if work < prime:
                break
            
            if work % prime == 0:
                factors.add(prime)
                work //= prime
                
                factors.update(self.factorize(work))
                break

        return factors
        
        
class Graph:
    def __init__(self):
        self.adj = {}
        self.factors = set()
        self.values = set()
    
    def add_vertex(self, p, label):
        if p not in self.adj:
            self.adj[p] = set()
        if label == 'factor':
            self.factors.add(p)
        else:
            self.values.add(p)
    
    def add_factor(self, factor):
        self.add_vertex(factor, 'factor')
        
    def add_value(self, value):
        self.add_vertex(value, 'value')
        
    def connect(self, p, q):
        self.adj[p].add(q)
        self.adj[q].add(p)

    def find_largest_connected_size(self):
        seen = set()
        largest = 0
        for p in list(self.adj.keys()):
            count = self._dfs_from(p, seen)
            largest = max(largest, count)
            
        return largest
    
    def _dfs_from(self, p, seen):
        if p in seen:
            return 0
        
        seen.add(p)
        
        count = 1 if p in self.values else 0
        
        return count + sum(self._dfs_from(q, seen) for q in self.adj[p])


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        n = len(A)
        parent = list(range(n+1))
        def find(x):
            if parent[x]!=x:
                parent[x] = find(parent[x])
            return parent[x]
        
        def union(x, y):
            px = find(x)
            py = find(y)
            parent[px] = py
            
        div_bucket = collections.defaultdict(list)
        def findDivisor(num):
            if num < 2:
                return set()
            for div in range(2, int(math.sqrt(num)) + 2):
                if num%div == 0:
                    return findDivisor(num//div) | {div}
            return {num}
                    
        for i in range(n):
            div_set = set()
            div_set = findDivisor(A[i])
            for div in div_set:
                div_bucket[div].append(i)
                        

        for _, nums in list(div_bucket.items()):
            for j in range(len(nums)-1):
                union(nums[j], nums[j+1])

        return max(collections.Counter([find(x) for x in range(n)]).values())


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        factor = {}
        dsu = DSU()
        
        def get_primes(num):
            primes = set()
            i = 2
            while i * i <= num:
                if num % i == 0:
                    while num % i == 0:
                        num = num // i
                    primes.add(i)
                i += 1
            if num > 1:
                primes.add(num)
            return primes
        
        for num in A:
            primes = get_primes(num)
            for p in primes:
                factor.setdefault(p, num)
                if dsu.find(num) != dsu.find(factor[p]):
                    dsu.union(num, factor[p])
        ans = 0
        for v in list(factor.values()):
            ans = max(dsu.count[v], ans)
        return ans
    
    
class DSU:
    def __init__(self):
        self.father = {}
        self.count = {}
    
    def find(self, a):
        self.father.setdefault(a, a)
        self.count.setdefault(a, 1)
        if a != self.father[a]:
            self.father[a] = self.find(self.father[a])
        return self.father[a]
    
    def union(self, a, b):
        _a = self.find(a)
        _b = self.find(b)
        if _a != _b:
            self.father[_a] = _b
            self.count[_b] += self.count[_a]
    
    


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent = {}
        
        def find(a):
            if a not in parent: 
                parent[a] = a
                return a
            if parent[a] == a:
                return a
            parent[a] = find(parent[a])
            return parent[a]
        
        for num in A:
            parent[num] = num
        
        for num in A:
            for i in range(2, int(sqrt(num)) + 1):
                if num % i == 0:
                    parent[find(num)] = parent[find(i)]
                    parent[find(num)] = parent[find(num / i)]
        
        count = {}
        maxi = 1
        for num in A:
            tmp = find(num)
            if tmp not in count:
                count[tmp] = 1
            else:
                count[tmp] += 1
            maxi = max(maxi, count[tmp])
        
        return maxi
        
        
    def largestComponentSize2(self, A: List[int]) -> int:
        
        def gcd(a, b):
            while b != 0:
                a, b = b, a % b
            return a
        
        visited = [False] * len(A)
        group = [-1] * len(A)
        stack = []
        num = 0
        maxGrp = 0
        
        for i in range(len(A)):
            if visited[i] == False:
                stack.append(i)
                numGrp = 0
            
                while len(stack) > 0:
                    curr = stack.pop()
                    for j in range(len(A)):
                        if j == curr: 
                            continue
                        if group[j] == -1:
                            if A[curr] % 2 == A[j] % 2 == 0 or gcd(A[curr], A[j]) > 1:
                                group[j] = num
                                numGrp += 1
                                stack.append(j)

                visited[i] = True
                maxGrp = max(maxGrp, numGrp)
                num += 1
                
        
        return maxGrp
        


class UF:
    def __init__(self,size):
        self.d = [i for i in range(size+1)]
    def find(self,m):

        if self.d[m] != m:
            self.d[m] = self.find(self.d[m])
        return self.d[m]
    def union(self,m,n):
        pm = self.find(m)
        pn = self.find(n)

        self.d[pm] = pn

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        uf = UF(max(A))
        for a in A:
            for factor in range(2,int(a**0.5)+1):
                if a % factor == 0:
                    uf.union(a,factor)
                    uf.union(a,a//factor)
        ret = 0
        C = collections.Counter()
        for a in A:
            group_id = uf.find(a)
            C[group_id] += 1
            ret = max(ret,C[group_id])
        return ret

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        parent = [-1]*1000001
        
        def find(node):
            if parent[node] == -1:
                return node
            parent[node] = find(parent[node])
            return parent[node]
                
        
        def union(X,Y):
            parentX = find(X)
            parentY = find(Y)

            if parentX != parentY:
                parent[parentY] = parentX

        for node in A:
            for i in range(2,int(sqrt(node)) + 1):
                if node%i == 0:
                    union(i,node)
                    union(node,node//i)
        count = 0
        d = {}
        
        for node in A:
            parentNode = find(node)
            count = max(count, 1 + d.get(parentNode,0))
            d[parentNode] = 1 + d.get(parentNode,0)
        return count
            


from collections import defaultdict, Counter

MAX_N = 100000


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        sieve = Sieve(MAX_N+1)
        factors = defaultdict(list)
        for x in A:
            for factor in sieve.factorize(x):
                factors[factor].append(x)

        uf = UnionFind()
        for values in list(factors.values()):
            for i in range(1, len(values)):
                uf.connect(values[i-1], values[i])
                
        return max(list(Counter(uf.root(x) for x in A).values()), default=0)
        '''
        
        # build bipartite graph from factors and values
        g = Graph()
        for factor, values in factors.items():
            g.add_factor(factor)
            for value in values:
                g.add_value(value)
                g.connect(factor, value)
        
        return g.find_largest_connected_size()
        '''

    
class UnionFind:
    def __init__(self):
        self.parents = {}
    
    def connect(self, a, b):
        if a not in self.parents:
            self.parents[a] = a
        
        if b not in self.parents:
            self.parents[b] = b
            
        root = self.root(b)
        self.parents[self.root(a)] = root
        return root
    
    def root(self, a):
        if a not in self.parents:
            self.parents[a] = a
            return a

        if a == self.parents[a]:
            return a
        
        self.parents[a] = self.root(self.parents[a])
        
        return self.parents[a]


class Sieve:
    def __init__(self, limit):
        self.primes = self._compute_primes(limit)
        # better runtime than simply empty dict!
        self.factors = {p: {p} for p in self.primes}
        self.factors[1] = set()
        
    def _compute_primes(self, limit):
        primes = list()
        sieve = [True] * limit
        for prime in range(2, limit):
            if not sieve[prime]:
                continue
            
            primes.append(prime)
            
            # better runtime than a manual while loop!
            for j in range(prime+prime, limit, prime):
                sieve[j] = False
        
        return primes
    
    # this hurts the runtime!
    #@lru_cache(maxsize=MAX_N)
    def factorize(self, n):
        if n in self.factors:
            return self.factors[n]
        
        for prime in self.primes:
            if n % prime == 0:
                factors = self.factors[n] = self.factorize(n // prime).union({prime})
                return factors

        raise ValueError(f'Value larger than max known prime: {n}')
        
        
class Graph:
    def __init__(self):
        self.adj = {}
        self.factors = set()
        self.values = set()
    
    def add_vertex(self, p, label):
        if p not in self.adj:
            self.adj[p] = set()
        if label == 'factor':
            self.factors.add(p)
        else:
            self.values.add(p)
    
    def add_factor(self, factor):
        self.add_vertex(factor, 'factor')
        
    def add_value(self, value):
        self.add_vertex(value, 'value')
        
    def connect(self, p, q):
        self.adj[p].add(q)
        self.adj[q].add(p)

    def find_largest_connected_size(self):
        seen = set()
        largest = 0
        for p in list(self.adj.keys()):
            count = self._dfs_from(p, seen)
            largest = max(largest, count)
            
        return largest
    
    def _dfs_from(self, p, seen):
        if p in seen:
            return 0
        
        seen.add(p)
        
        count = 1 if p in self.values else 0
        
        return count + sum(self._dfs_from(q, seen) for q in self.adj[p])


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        if not A: return 0
        root = list(range(max(A) + 1))
        def find(i):
            while not root[i] == i:
                root[i] = root[root[i]]
                i = root[i]
            return i

        def union(a, i):
            root[find(a)] = find(i)

        for a in A:
            for i in range(2, int(math.sqrt(a)) + 1):
                if a % i == 0:
                    union(a, i)
                    union(a, a // i)
        return Counter([find(a) for a in A]).most_common()[0][1]

from collections import defaultdict, Counter
from functools import lru_cache

MAX_N = 100000


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        # compute factors
        sieve = Sieve(MAX_N)
        factors = defaultdict(list)
        for x in A:
            for factor in sieve.factorize(x):
                factors[factor].append(x)
        '''
        f = Factors()
        factors = defaultdict(list)
        for x in A:
            for factor in f.find_for(x):
                factors[factor].append(x)
        '''

        '''
        uf = UnionFind()
        for values in factors.values():
            for i in range(1, len(values)):
                uf.connect(values[i-1], values[i])
                
        return max(Counter(uf.root(x) for x in A).values(), default=0)
        '''
        
        # build bipartite graph from factors and values
        g = Graph()
        for factor, values in list(factors.items()):
            g.add_factor(factor)
            for value in values:
                g.add_value(value)
                g.connect(factor, value)
        
        return g.find_largest_connected_size()


class Factors:
    def __init__(self):
        self.primes = self.find_primes(100000+1)
        self.factors = {p: [p] for p in self.primes}
        self.factors[1] = []
    
    def find_primes(self, limit):
        primes = []
        nums = [True] * limit
        nums[0] = nums[1] = False
        for n in range(limit):
            if nums[n]:
                primes.append(n)
                for j in range(n+n, limit, n):
                    nums[j] = False
        
        return primes
    
    def find_for(self, n):
        if n in self.factors:
            return self.factors[n]
        
        self.factors[n] = factors = set()
        for prime in self.primes:
            if n % prime == 0:
                factors.add(prime)
                for f in self.find_for(n // prime):
                    factors.add(f)
                break
        
        return factors

    
class UnionFind:
    def __init__(self):
        self.parents = {}
    
    def connect(self, a, b):
        if a not in self.parents:
            self.parents[a] = a
        
        if b not in self.parents:
            self.parents[b] = b
            
        root = self.root(b)
        self.parents[self.root(a)] = root
        return root
    
    def root(self, a):
        if a not in self.parents:
            self.parents[a] = a
            return a

        if a == self.parents[a]:
            return a
        
        self.parents[a] = self.root(self.parents[a])
        
        return self.parents[a]


class Sieve:
    def __init__(self, max_n):
        self.primes = self._compute_primes(max_n)
        self.factors = {p: [p] for p in self.primes}
        # self.factors = {}
        
    def _compute_primes(self, max_n):
        primes = list()
        sieve = [True] * (max_n+1)
        for prime in range(2, max_n+1):
            if not sieve[prime]:
                continue
            
            primes.append(prime)
            
            for j in range(prime+prime, max_n+1, prime):
                sieve[j] = False
        
        return primes
    
    def factorize(self, n):
        if n in self.factors:
            return self.factors[n]
        
        self.factors[n] = factors = set()
        work = n
        for prime in self.primes:
            # does not improve runtime!
            if work < prime:
                break
            
            if work % prime == 0:
                factors.add(prime)
                work //= prime
                
                factors.update(self.factorize(work))
                break

        return factors
        
        
class Graph:
    def __init__(self):
        self.adj = {}
        self.factors = set()
        self.values = set()
    
    def add_vertex(self, p, label):
        if p not in self.adj:
            self.adj[p] = set()
        if label == 'factor':
            self.factors.add(p)
        else:
            self.values.add(p)
    
    def add_factor(self, factor):
        self.add_vertex(factor, 'factor')
        
    def add_value(self, value):
        self.add_vertex(value, 'value')
        
    def connect(self, p, q):
        self.adj[p].add(q)
        self.adj[q].add(p)

    def find_largest_connected_size(self):
        seen = set()
        largest = 0
        for p in list(self.adj.keys()):
            count = self._dfs_from(p, seen)
            largest = max(largest, count)
            
        return largest
    
    def _dfs_from(self, p, seen):
        if p in seen:
            return 0
        
        seen.add(p)
        
        count = 1 if p in self.values else 0
        
        return count + sum(self._dfs_from(q, seen) for q in self.adj[p])


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        divisors, groups, sizes = {}, {}, {}

        # Find all divisors of the numbers in the list
        for num in A:
            added = False

            for i in range(2, max(int(math.sqrt(num)) + 1, 4)):
                if num % i == 0:
                    added = True

                    # Found two divisors
                    # First is i
                    if i not in divisors:
                        divisors[i] = set()
                    divisors[i].add(num)

                    # Second is num divided by i
                    if (num_i := int(num / i)) > 1:
                        if num_i not in divisors:
                            divisors[num_i] = set()
                        divisors[num_i].add(num)

            if not added:

                # This is a prime number
                if num not in divisors:
                    divisors[num] = set()
                divisors[num].add(num)

        # Union function
        def union(node1: int, node2: int) -> None:
            parent1 = find(node1)
            parent2 = find(node2)

            # Check if these nodes already belong to the same parent
            if parent1 == parent2:
                return
            elif parent1 < parent2:

                # Union to the smallest parent 1
                groups[parent2] = parent1
                sizes[parent1] = sizes[parent1] + sizes[parent2]

            else:
                # Union to the smallest parent 2
                groups[parent1] = parent2
                sizes[parent2] = sizes[parent1] + sizes[parent2]

        # Find function
        def find(node: int) -> int:

            # If this node hasn't been created yet
            if node not in groups:
                groups[node] = node
                sizes[node] = 1
                return node

            # Check if this node is also the parent (final node)
            if groups[node] == node:
                return node

            # Apply path compression
            groups[node] = find(groups[node])

            # Return the parent
            return groups[node]

        # Union-find algorithm to union all groups with common divisor
        for _, common_numbers in list(divisors.items()):
            num1 = random.sample(common_numbers, 1)[0]

            for num2 in common_numbers:
                if num1 != num2:
                    union(num1, num2)

        return max(list(sizes.values()), default=1)


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent = {}
        
        for num in A:
            parent[num] = num
            
        def find(a):
            if a not in parent:
                parent[a] = a
                return a
            if parent[a] == a:
                return a
            parent[a] = find(parent[a])
            return parent[a]
        
        for num in A:
            for i in range(2, int(sqrt(num)) + 1):
                if num % i == 0:
                    parent[find(num)] = parent[find(i)]
                    parent[find(num)] = parent[find(num / i)]
        
        count = defaultdict(int)
        maxi = 1
        for num in A:
            tmp = find(num)
            count[tmp] += 1
            maxi = max(maxi, count[tmp])
            
        return maxi

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        factor = {}
        dsu = DSU()
        
        def get_primes(num):
            primes = []
            i = 2
            while i * i <= num:
                if num % i == 0:
                    while num % i == 0:
                        num = num // i
                    primes.append(i)
                i += 1
            if num > 1:
                primes.append(num)
            return primes
        
        for num in A:
            primes = get_primes(num)
            for p in primes:
                factor.setdefault(p, num)
                if dsu.find(num) != dsu.find(factor[p]):
                    dsu.union(num, factor[p])
        ans = 0
        for v in list(factor.values()):
            ans = max(dsu.count[v], ans)
        return ans
    
    
class DSU:
    def __init__(self):
        self.father = {}
        self.count = {}
    
    def find(self, a):
        self.father.setdefault(a, a)
        self.count.setdefault(a, 1)
        if a != self.father[a]:
            self.father[a] = self.find(self.father[a])
        return self.father[a]
    
    def union(self, a, b):
        _a = self.find(a)
        _b = self.find(b)
        if _a != _b:
            self.father[_a] = _b
            self.count[_b] += self.count[_a]
    
    


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        dsu = DSU()
        prime_to_index = {}
        for i, num in enumerate(A):
            primes = self.getPrimes(num)
            for prime in primes:
                if prime in prime_to_index:
                    dsu.union(prime_to_index[prime],i)
                else:
                    prime_to_index[prime] = i
        return max(dsu.count.values())
                        
    
    def getPrimes(self, num):
        primes = set()
        i = 2
        while i * i <= num:
            if num % i == 0:
                while num % i == 0:
                    num = num // i
                primes.add(i)
            i += 1
        if num > 1:
            primes.add(num)
        return primes
    
class DSU:
    def __init__(self):
        self.father = {}
        self.count = {}
    
    def find(self, a):
        self.father.setdefault(a, a)
        self.count.setdefault(a, 1)
        if a != self.father[a]:
            self.father[a] = self.find(self.father[a])
        return self.father[a]
    
    def union(self, a, b):
        _a = self.find(a)
        _b = self.find(b)
        if _a != _b:
            self.father[_a] = self.father[_b]
            self.count[_b] += self.count[_a]
        
        
        
        
        


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        p = list(range(max(A) + 1))
       
        def find(x):
            while p[x] != x:
                p[x] = p[p[x]]
                x = p[x]
            return x
    
        def union(x, y):
            p[find(x)] = p[find(y)]      
      
        for a in A:     
            for k in range(2, int(math.sqrt(a) + 1)):        
                if a % k == 0:
                    union(a, k)
                    union(a, a // k)
    
        return collections.Counter([find(a) for a in A]).most_common(1)[0][1]

from collections import defaultdict, Counter
from functools import lru_cache

MAX_N = 100000


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        # compute factors
        '''
        sieve = Sieve(MAX_N)
        factors = defaultdict(list)
        for x in A:
            for factor in sieve.factorize(x):
                factors[factor].append(x)
        '''
        f = Factors()
        factors = defaultdict(list)
        for x in A:
            for factor in f.find_for(x):
                factors[factor].append(x)

        '''
        uf = UnionFind()
        for values in factors.values():
            for i in range(1, len(values)):
                uf.connect(values[i-1], values[i])
                
        return max(Counter(uf.root(x) for x in A).values(), default=0)
        '''
        
        # build bipartite graph from factors and values
        g = Graph()
        for factor, values in list(factors.items()):
            g.add_factor(factor)
            for value in values:
                g.add_value(value)
                g.connect(factor, value)
        
        return g.find_largest_connected_size()


class Factors:
    def __init__(self):
        self.primes = self.find_primes(100000+1)
        self.factors = {p: [p] for p in self.primes}
        self.factors[1] = []
    
    def find_primes(self, limit):
        primes = []
        nums = [True] * limit
        nums[0] = nums[1] = False
        for n in range(limit):
            if nums[n]:
                primes.append(n)
                for j in range(n+n, limit, n):
                    nums[j] = False
        
        return primes
    
    def find_for(self, n):
        if n in self.factors:
            return self.factors[n]
        
        self.factors[n] = factors = set()
        for prime in self.primes:
            if n % prime == 0:
                factors.add(prime)
                for f in self.find_for(n // prime):
                    factors.add(f)
                break
        
        return factors

    
class UnionFind:
    def __init__(self):
        self.parents = {}
    
    def connect(self, a, b):
        if a not in self.parents:
            self.parents[a] = a
        
        if b not in self.parents:
            self.parents[b] = b
            
        root = self.root(b)
        self.parents[self.root(a)] = root
        return root
    
    def root(self, a):
        if a not in self.parents:
            self.parents[a] = a
            return a

        if a == self.parents[a]:
            return a
        
        self.parents[a] = self.root(self.parents[a])
        
        return self.parents[a]


class Sieve:
    def __init__(self, max_n):
        self.primes = self._compute_primes(max_n)
        self.factors = {p: [p] for p in self.primes}
        # self.factors = {}
        
    def _compute_primes(self, max_n):
        primes = list()
        sieve = [True] * (max_n+1)
        for prime in range(2, max_n+1):
            if not sieve[prime]:
                continue
            
            primes.append(prime)
            
            for j in range(prime+prime, max_n+1, prime):
                sieve[j] = False
        
        return primes
    
    @lru_cache(maxsize=MAX_N)
    def factorize(self, n):
        if n in self.factors:
            return self.factors[n]
        
        self.factors[n] = factors = set()
        work = n
        for prime in self.primes:
            if work < prime:
                break
            
            if work % prime == 0:
                factors.add(prime)
                work //= prime
                
                factors.update(self.factorize(work))
                break

        return factors
        
        
class Graph:
    def __init__(self):
        self.adj = {}
        self.factors = set()
        self.values = set()
    
    def add_vertex(self, p, label):
        if p not in self.adj:
            self.adj[p] = set()
        if label == 'factor':
            self.factors.add(p)
        else:
            self.values.add(p)
    
    def add_factor(self, factor):
        self.add_vertex(factor, 'factor')
        
    def add_value(self, value):
        self.add_vertex(value, 'value')
        
    def connect(self, p, q):
        self.adj[p].add(q)
        self.adj[q].add(p)

    def find_largest_connected_size(self):
        seen = set()
        largest = 0
        for p in list(self.adj.keys()):
            count = self._dfs_from(p, seen)
            largest = max(largest, count)
            
        return largest
    
    def _dfs_from(self, p, seen):
        if p in seen:
            return 0
        
        seen.add(p)
        
        count = 1 if p in self.values else 0
        
        return count + sum(self._dfs_from(q, seen) for q in self.adj[p])


class UnionFind:
    def __init__(self, maxval):
        self.arr = [i for i in range(maxval)]
    
    def find(self, n):
        if n != self.arr[n]:
            self.arr[n] = self.find(self.arr[n])
        return self.arr[n]
    
    def union(self, a, b):
        self.arr[self.find(a)] = self.arr[self.find(b)]

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        maxval = max(A)+1
        oUnionFind = UnionFind(maxval)
        
        for i in A:
            for j in range(2, int(math.sqrt(i))+1):
                if i % j == 0:
                    oUnionFind.union(i, j)
                    oUnionFind.union(i, i//j)
        
        counter = collections.defaultdict(int)
        for i in A:
            counter[oUnionFind.find(i)] += 1
        
        return max(list(counter.values()))

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent = [-1] * 100001

        def _find(x):
            if parent[x] == -1:
                return x

            parent[x] = _find(parent[x])
            return parent[x]

        def _union(x, y):
            xp = _find(x)
            yp = _find(y)

            if xp != yp:
                parent[yp] = xp

        for x in A:
            for i in range(2, int(sqrt(x)) + 1):
                if x % i == 0:
                    _union(i, x)
                    _union(x, x // i)

        cache = {}

        for x in A:
            xp = _find(x)
            cache[xp] = 1 + cache.get(xp, 0)
            
        cache1 = sorted(list(cache.items()), key=lambda x: x[1])
        maxi = cache1[-1][0]
        
        return cache[maxi]


class DisjointSet:
    def __init__(self, n):
        self.set = list(range(n))
    def find(self, i):
        if self.set[i] != i:
            self.set[i] = self.find(self.set[i])
        return self.set[i]
        
    def union(self, i, j):
        ii, jj = self.find(i), self.find(j)
        self.set[ii] = jj

class Solution:
    def primeFactors(self,n):
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self.primeFactors(n//i) | set([i])
        return set([n])
        
    def largestComponentSize(self, A):
        n = len(A)
        unionFind = DisjointSet(n)
        primes = defaultdict(list)
        for i, num in enumerate(A):
            pr_set = self.primeFactors(num)
            for q in pr_set: primes[q].append(i)
        for _, indexes in list(primes.items()):
            for i in range(len(indexes)-1):
                unionFind.union(indexes[i], indexes[i+1])
        return max(Counter([unionFind.find(i) for i in range(n)]).values())


class DSU:
    
    def __init__(self, N):
        self.data = list(range(N))

    def union(self, x, y):
        xp, yp = self.find(x), self.find(y)
        self.data[xp] = yp
    
    def find(self, x):
        if self.data[x] != x:
            self.data[x] = self.find(self.data[x])
        return self.data[x]
            

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        def primeFactors(n):
            
            for i in range(2, int(math.sqrt(n)) + 1):
                if n % i == 0:
                    return primeFactors(n // i) | set([i])
                
            return set([n])
        
        primes = collections.defaultdict(list)
        
        for i, num in enumerate(A):
            factors = primeFactors(num)
            for factor in factors:
                primes[factor].append(i)
                
        dsu = DSU(len(A))
        
        for factor, nums in primes.items():
            for i in range(1, len(nums)):
                dsu.union(nums[i-1], nums[i])
                
        counter = collections.Counter(dsu.find(i) for i in dsu.data)
        
        return max(v for v in counter.values())

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent = [-1]*1000001

        def _find(a):
            if parent[a] == -1:
                return a
            parent[a] = _find(parent[a])
            return parent[a]

        def _union(a, b):
            ap = _find(a)
            bp = _find(b)
            if ap != bp:
                parent[bp] = ap

        for a in A:
            for i in range(2, int(sqrt(a)) + 1):
                if a % i == 0:
                    _union(i, a)
                    _union(a, a//i)

        cnt = 0
        tmp = {}
        for a in A:
            ap = _find(a)
            cnt = max(cnt, 1 + tmp.get(ap, 0))
            tmp[ap] = 1 + tmp.get(ap, 0)
        return cnt


class Union:
    def __init__(self, arr):
        self.weight = {}
        self.par = {}
        for a in range(1, max(arr) + 1):
            self.par[a] = a
            self.weight[a] = 1
        
    def find(self, a):
        while self.par[a] != a:
            a = self.par[a]
        return a
    
    def union(self, a, b):
        
        pa, pb = self.find(a), self.find(b)
        if pa == pb:
            return
        if self.weight[pa] < self.weight[pb]:
            pa, pb = pb, pa
            
        self.weight[pa] += self.weight[pb]
        self.par[pb] = pa
            
        
    def getMaxWeight(self):
        return max(list(map(len, list(self.weight.values()))))

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        union = Union(A)
        for a in A:
            sqr = int(sqrt(a))
            for j in range(2, sqr + 1):
                if a % j == 0:
                    union.union(a, a // j)
                    union.union(a, j)
                    
        groups = collections.defaultdict(int)
        for a in A:
            groups[union.find(a)] += 1
            
        return max(groups.values())
        
                    
                    
        
                


class UF:        
    def __init__(self) -> None:
        self.parent = {}
        self.sz = {}
        self.count = 0
        
    def add(self, p):    
        if p not in self.parent:
            self.parent[p] = p
            self.sz[p] = 1
            self.count += 1
                          
    def find(self, p: int) -> int:
        while p != self.parent[p]:
            self.parent[p] = self.parent[self.parent[p]]
            p = self.parent[p]
        return p  
              
    def union(self, p: int, q: int) -> None:
        i = self.find(p)
        j = self.find(q)             
        if i == j:    
            return 
        if self.sz[i] > self.sz[j]:                 
            self.parent[j] = i
            self.sz[i] += self.sz[j]
        else:             
            self.parent[i] = j
            self.sz[j] += self.sz[i]                                           
        self.count -= 1 
        
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def fac(n): 
            for i in range(2, int(n**0.5)+1):
                if n % i == 0:
                    n //= i
                    return set((i,)) | fac(n)
            return set((n,))
        @lru_cache(None) 
        def group_id(p):
            return uf.find(p)
        uf = UF()
        c = Counter() 
        for n in A:
            factors = fac(n)
            key = tuple(sorted(factors))
            c[key] += 1
            if c[key] == 1:
                p = factors.pop()
                uf.add(p)
                for q in factors:
                    uf.add(q)
                    uf.union(p, q)
        if uf.count == 1:
            return len(A)            
        groups = Counter()
        for factors, value in c.items():
            groups[group_id(factors[0])] += value
        return groups.most_common()[0][1]    

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        mp={} # for union find
        ans=0
        
        def find(a):
            if a not in mp: mp[a]=a
            if mp[a]!=a:
                mp[a]=find(mp[a])
            return mp[a]
            
        def union(a,b): # b is smaller
            pa=find(a)
            pb=find(b)
            if pa!=pb:
                mp[pa]=pb
            
        for a in A:
            t=int(math.sqrt(a))
            for k in range(2,t+1):
                if a%k==0:
                    union(a,k)
                    union(a,a/k)
        return collections.Counter([find(a) for a in A]).most_common(1)[0][1]


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent = {}
        size = {}
        def find(x):
            if parent[x] != x:
                parent[x] = find(parent[x])
            return parent[x]
        def union(rootlist):
            if not rootlist: return
            for i in range(1, len(rootlist)):
                parent[rootlist[i]] = rootlist[0]
                size[rootlist[0]] += size[rootlist[i]]
            size[rootlist[0]]+=1
        fact = [[] for _ in range(len(A))]
        for j in range(len(A)):
            num,p = A[j],2
            while num >= p*p:
                if num%p == 0:
                    fact[j].append(p)
                    size[p], parent[p] = 0, p
                    while num%p == 0:
                        num//=p
                p+=1
            if num > 1:
                fact[j].append(num)
                size[num], parent[num] =  0, num
        for i in range(len(fact)):
            rootset = set()
            for factor in fact[i]:
                rootset.add(find(factor))
            union(list(rootset))
        return max(size.values())


from typing import List
from collections import defaultdict, deque
from math import sqrt

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        factors = defaultdict(set)
        disjoint = list(range(len(A)))
        
        def populateFactors():
            for i in range(len(A)):
                a = A[i]
                if a == 1:
                    continue
                x = a
                while x % 2 == 0:
                    factors[2].add(i)
                    x //= 2
                for n in range(3, int(sqrt(x) + 1), 2):
                    while x % n == 0:  # n is a factor
                        factors[n].add(i)
                        x //= n
                        if x <= 1:
                            break
                if x > 1:
                    factors[x].add(i)
        def find(i):
            while disjoint[i] != i:
                i = disjoint[i]
            return i
        def union(i, j):
            disjoint[find(j)] = find(i)
        
        populateFactors()
        for factor in factors:
            x = None
            for i in factors[factor]:
                if x is None: x = i
                union(x, i)
        count = defaultdict(int)
        for i in range(len(A)):
            count[find(i)] += 1
        return max(count.values())

class DSU: 
    def __init__(self, n):
        self.p = list(range(n))
        
    def find(self, x):
        if self.p[x] != x: 
            self.p[x] = self.find(self.p[x])
        return self.p[x]
    
    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr

class Solution:
    def primes_set(self, n):
        for i in range(2, int(math.sqrt(n)) + 1):
            if n % i == 0:
                return self.primes_set(n // i) | set([i])
        return set([n])
    
    def largestComponentSize(self, A: List[int]) -> int:
        n = len(A)
        UF = DSU(n) 
        primes = collections.defaultdict(list)
        for i, num in enumerate(A): 
            pr_set = self.primes_set(num)
            for q in pr_set: primes[q].append(i)
                
        for _, indexes in primes.items():
            for i in range(len(indexes) - 1):
                UF.union(indexes[i], indexes[i + 1])
        return max(Counter([UF.find(i) for i in range(n)]).values())

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        parent = dict()
        def find(x):
            parent.setdefault(x,x)
            if x!=parent[x]:
                parent[x] = find(parent[x])
            return parent[x]
        
        def union(x,y):
            px = find(x)
            py = find(y)
            parent[px]=py
            
        visited = set()
        graph = collections.defaultdict(set)
        count = 0
        
        
        for a in A:
            for fact in range(2,int(sqrt(a))+1):
                if a%fact==0:
                    x = a
                    y = fact
                    z = a//fact
                    
                    px = find(a)
                    py = find(y)
                    pz = find(z)
                    
                    if px!=py:
                        union(x,y)
                    if px!=pz:
                        union(x,z)
        
                    
        mem = collections.Counter()
        for item in A:
            p = find(item)
            mem[p]+=1
        maxVal = mem.most_common()
        return(maxVal[0][1])

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        if len(A) <= 1:
            return len(A)

        #create union
        maxA = max(A)
        unionL = list(range(maxA+1)) #initialize, each one is a component itself
        size = [1]*(maxA+1)  #every component has size 1, the element itself initially

        def findRoot(i):
            k1 = i
            while unionL[k1] != k1:
                unionL[k1] = unionL[unionL[k1]]
                k1 = unionL[k1]
            return k1

        def union(x, y):
            k1 = findRoot(x)
            k2 = findRoot(y)
            if k1 != k2:
                if size[k1] < size[k2]:
                    unionL[k1] = k2  #can improve with size
                    size[k2] += size[k1]
                else:
                    unionL[k2] = k1  #can improve with size
                    size[k1] += size[k2]
            return

        for item in A:
            mid = int(math.sqrt(item))+1
            for k in range(2, mid+1):  #mid included
                if item % k == 0:
                    union(item, k)
                    if item//k != 1:
                        union(item, item//k)

        count = {}
        for item in A:
            root = findRoot(item)
            if root in count:
                count[root] += 1
            else:
                count[root] = 1

        return max(count.values())












class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        A_max = max(A)
        primes = []
        seive = [True] * (int(sqrt(A_max)) + 1)
        seive[:2] = [False, False]
        for i in range(len(seive)):
            if seive[i]:
                primes.append(i)
                for j in range(i + i, len(seive), i):
                    seive[j] = False
        
        graph = defaultdict(list)
        for i, num in enumerate(A):
            for p in primes:
                if p * p > num:
                    
                    break
                if num % p  == 0:
                    while num % p == 0:
                        num //= p
                    graph[p].append(i)
            if num > 1:
                graph[num].append(i)
        print(graph)
        uf = DS(len(A))
        for indx in list(graph.values()):
            for i in range(1, len(indx)):
                uf.union(indx[i - 1], indx[i])
        parents = [uf.find(i) for i in range(len(A))]
        return max(Counter(parents).values())
                


class DS:
    def __init__(self, n):
        self.p = [-1]*n
    
    def find(self, x):
        if self.p[x] >= 0:
            self.p[x] = self.find(self.p[x])
            return self.p[x]
        return x
    
    def union(self, x, y):
        x, y = self.find(x), self.find(y)
        if x == y:
            return
        if self.p[x] < self.p[y]:
            self.p[x] -= 1
            self.p[y] = x

            
        else:
            self.p[y] -= 1
            self.p[x] = y
            
        
        


from typing import List
from collections import defaultdict, deque
from math import sqrt

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        factors = defaultdict(set)
        disjoint = list(range(len(A)))
        
        def populateFactors():
            for i in range(len(A)):
                a = A[i]
                if a == 1:
                    continue
                x = a
                while x % 2 == 0:
                    factors[2].add(i)
                    x //= 2
                for n in range(3, int(sqrt(x) + 1), 2):
                    while x % n == 0:  # n is a factor
                        factors[n].add(i)
                        x //= n
                        if x <= 1:
                            break
                if x > 1:
                    factors[x].add(i)
        def find(i):
            while disjoint[i] != i:
                i = disjoint[i]
            return i
        def union(i, j):
            disjoint[find(j)] = find(i)
        
        populateFactors()
        for factor in factors:
            x = None
            for i in factors[factor]:
                if x is None: x = i
                union(x, i)
        count = defaultdict(int)
        for i in range(len(A)):
            count[find(i)] += 1
        return max(count.values())


class unionfind:
    def __init__(self, N):
        self.parents = list(range(N))
        self.size = [1] * N
    
    def find(self, x):
        while x != self.parents[x]:
            x = self.parents[x]
        return x
    
    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        if px != py:
            sizex, sizey = self.size[px], self.size[py]
            if sizex < sizey:
                self.parents[px] = py
                self.size[py] += sizex
            else:
                self.parents[py] = px
                self.size[px] += sizey
        else: return
        
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        factor_dic = collections.defaultdict(int)
        uf = unionfind(len(A))
        for idx, a in enumerate(A):
            for factor in range(2, int(a**0.5) + 1):
                if a%factor == 0:
                    for fac in [factor, a//factor]:
                        if fac not in factor_dic:
                            factor_dic[fac] = idx
                        else:
                            # if idx == 2:
                            #     print(idx, fac)
                            #     print(factor_dic)
                            uf.union(idx, factor_dic[fac])
            if a not in factor_dic:
                factor_dic[a] = idx
            else:
                uf.union(idx, factor_dic[a])
        # print(factor_dic)
        # print(uf.parents)
        # print(uf.size)
        return max(uf.size)



class UF:        
    def __init__(self) -> None:
        self.parent = {}
        self.sz = {}
        self.count = 0
        
    def add(self, p):    
        if p not in self.parent:
            self.parent[p] = p
            self.sz[p] = 1
            self.count += 1
                          
    def find(self, p: int) -> int:
        while p != self.parent[p]:
            self.parent[p] = self.parent[self.parent[p]]
            p = self.parent[p]
        return p  
              
    def union(self, p: int, q: int) -> None:
        i = self.find(p)
        j = self.find(q)             
        if i == j:    
            return 
        if self.sz[i] > self.sz[j]:                 
            self.parent[j] = i
            self.sz[i] += self.sz[j]
        else:             
            self.parent[i] = j
            self.sz[j] += self.sz[i]                                           
        self.count -= 1 
        
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def fac(n): 
            for i in range(2, int(n**0.5)+1):
                if n % i == 0:
                    n //= i
                    return set((i,)) | fac(n)
            return set((n,))
        @lru_cache(None) 
        def group_id(p):
            return uf.find(p)
        uf = UF()
        c = Counter() 
        for n in A:
            factors = fac(n)
            key = tuple(sorted(factors))
            c[key] += 1
            if c[key] == 1:
                p = factors.pop()
                uf.add(p)
                for q in factors:
                    uf.add(q)
                    uf.union(p, q)
        if uf.count == 1:
            return len(A)            
        groups = Counter()
        for factors, value in list(c.items()):
            groups[group_id(factors[0])] += value
        return groups.most_common()[0][1]    
            
            
            
            
            
        


class Solution:
    
    def largestComponentSize(self, A: List[int]) -> int:
        
        parent = [-1] * 100001
        
        def _find(x):
            if parent[x] == -1:
                return x
            parent[x] = _find(parent[x])
            return parent[x]
        
        def _union(x , y):
            x_parent = _find(x)
            y_parent = _find(y)
            
            if x_parent != y_parent:
                parent[y_parent] = x_parent
                
        
        for x in A:
            for i in range(2 , int(sqrt(x))+1):
                if x % i == 0:
                    _union(i , x)
                    _union(x , x//i)
                    
        count = 0
        cache = {}
        for x in A:
            xp = _find(x)
            count = max(count , 1 + cache.get(xp, 0))
            cache[xp] = 1 + cache.get(xp , 0)
            
        return count
    
        


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent = [-1] * 100_001 # One more than all values
        def find(x):
            if parent[x] == -1: return x
            parent[x] = find(parent[x])
            return parent[x]

        def union(x, y):
            xp, yp = find(x), find(y)
            if xp != yp: parent[yp] = xp

        for x in A:
            for i in range(2, int(sqrt(x)) + 1):
                if x % i == 0:
                    union(i, x)
                    union(x, x // i)
        count = 0
        cache = dict()
        for x in A:
            xp = find(x)
            count = max(count, 1 + cache.get(xp, 0))
            cache[xp] = 1 + cache.get(xp, 0)
        return count        
    
        def gcd(a, b):
            if b == 0: return a
            return gcd(b, a % b)
        graph = dict()
        for a in A: graph[a] = list()
        n = len(A)
        for i in range(n - 1):
            for j in range(i + 1, n):
                a, b = A[i], A[j]
                if gcd(a, b) > 1: graph[a].append(b)
                
        for a in graph.keys(): print(f'graph[{a}]', graph[a])
        largest = float('-inf')
        def dfs(graph, node, count):
            nonlocal largest
            print('node', node, 'count', count, 'largest', largest)
            if not graph[node]:
                largest = max(largest, count)
                return
            for c in graph[node]: dfs(graph, c, count + 1)
        for a in A: dfs(graph, a, 1)
        print(largest)
        print('-' * 50)

class Solution1:
    def largestComponentSize(self, A):
        if not A: return 0
        def findAndCompact(l, i): # require i >= 0
            if l[i] == i: return i
            p = l[i]
            if p >= 0 and l[p] == p: return p
            while p >= 0 and l[p] != p:
                p = l[p]
            root = p
            
            # compact
            p = i
            while p >= 0 and l[p] != p:
                t = l[p]
                l[p] = root
                p = t
            return root
        
        slist = [-1] * len(A)
        d = {} # record prime->(root of union-find set)
        for i in range(len(A)):
            n = A[i]
            has_factor = False
            for j in range(2, int(sqrt(n)) + 1):
                if n % j == 0:
                    has_factor = True
                    k = n // j
                    #print(n, j, k)
                    ri = -1 if slist[i] < 0 else findAndCompact(slist, slist[i])
                    rj = -1 if j not in d else findAndCompact(slist, d[j])
                    rk = -1 if k not in d else findAndCompact(slist, d[k])
                    if ri < 0 and rj < 0 and rk < 0:
                        slist[i] = d[j] = d[k] = i
                    else:
                        mm = min([item for item in (ri, rj, rk) if item >= 0])
                        if slist[i] >= 0: slist[ri] = mm
                        if j in d: slist[rj] = mm
                        if k in d: slist[rk] = mm
                        slist[i] = d[j] = d[k] = mm
            if not has_factor: #prime
                if A[i] not in d: slist[i] = d[A[i]] = i
                else: slist[i] = d[A[i]]
            #print(slist, d)
        
        for i in range(len(A)): findAndCompact(slist, i)
        #print('### ', slist)
        cc = Counter(slist)
        m = cc.most_common(2)
        return m[0][1] if m[0][0] != -1 else m[1][1]
    
class DSU:
    def __init__(self, N):
        self.p = list(range(N))

    def find(self, x):
        n = self.p[x]
        while n >= 0 and self.p[n] != n:
            n = self.p[n]
        root = n
        # compact
        n = x
        while n >= 0 and self.p[n] != n:
            t = self.p[n]
            self.p[n] = root
            n= t
        return root

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr

class Solution:
    def primes_set(self,n):
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self.primes_set(n//i) | set([i])
        return set([n])

    def largestComponentSize(self, A):
        max_num = max(A);
        ufs = DSU(max_num + 1);

        for num in A:
            for k in range(2, int(sqrt(num)) + 1):
                if num % k == 0:
                    ufs.union(num, k);
                    ufs.union(num, num // k);

        res = 1
        d = defaultdict(int)
        for num in A:
            root = ufs.find(num)
            d[root] += 1
            res = max(res, d[root])
        return res
    
    def largestComponentSize2(self, A):
        n = len(A)
        UF = DSU(n)
        primes = defaultdict(list)
        for i, num in enumerate(A):
            pr_set = self.primes_set(num)
            for q in pr_set: primes[q].append(i)

        for _, indexes in primes.items():
            for i in range(len(indexes)-1):
                UF.union(UF.find(indexes[i]), UF.find(indexes[i+1]))

        return max(Counter([UF.find(i) for i in range(n)]).values())

#
# @lc app=leetcode id=952 lang=python3
#
# [952] Largest Component Size by Common Factor
#

# @lc code=start
from collections import defaultdict


class Solution:
    small_primes = (2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317)
    def largestComponentSize(self, A: List[int]) -> int:
        label = defaultdict(int)
       
        def findRoot(key):
            if label[key] > 0:
                label[key] = findRoot(label[key])
                return label[key]
            else:
                return key
        
        def mergeRoot(k1, k2):
            r1, r2 = findRoot(k1), findRoot(k2)  
            if r1 != r2:
                r1, r2 = min(r1, r2), max(r1, r2)
                label[r1] += label[r2]
                label[r2] = r1
            return r1

        for x in A:
            root_id = 0
            t = sqrt(x) + 1
            for p in Solution.small_primes:
                if p > t:
                    break
                elif x % p == 0:
                    root_id = findRoot(p) if root_id == 0 else mergeRoot(root_id, p)
                    while x % p == 0:
                        x //= p
            if x != 1:
                root_id = findRoot(x) if root_id == 0 else mergeRoot(root_id, x)
            label[root_id] -= 1
        
        return -min(label.values())
# @lc code=end


class UnionFindSet:
    def __init__(self, n):
        self.parants = [0] * n
        self.rank = [0] * n

        # self is a distinct group
        for i in range(n):
            self.parants[i] = i
        
    def find(self, x):
        if x != self.parants[x]:
            self.parants[x] = self.find(self.parants[x])
        return self.parants[x]

    def union(self, x, y):
        px, py = self.find(x), self.find(y)

        # already in same group, no need to merge again
        if px == py: return False
        
        if self.rank[px] < self.rank[py]:
            self.parants[px] = py
        elif self.rank[px] > self.rank[py]:
            self.parants[py] = px
        else:
            self.parants[py] = px
            self.rank[py] += 1

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        s = UnionFindSet(max(A) + 1)

        for x in A:
            for i in range(2, int(math.sqrt(x)) + 1):
                if x % i == 0:
                    s.union(x, i)
                    s.union(x, x // i)
        
        hash = defaultdict(int)
        
        for x in A:
            hash[s.find(x)] += 1 

        return max(hash.values())
        
        


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent = [-1]*100001
        def _find(x):
            if parent[x]==-1:
                return x
            parent[x]=_find(parent[x])
            return parent[x]

        def _union(x,y):
            xp = _find(x)
            yp = _find(y)
            if xp != yp:
                parent[yp] = xp

        for x in A:
            for i in range(2, int(math.sqrt(x))+1):
                if x%i == 0:
                    _union(i,x)
                    _union(x,x//i)
        count = 0
        cache = {}
        for x in A:
            xp = _find(x)
            count = max(count, 1+cache.get(xp,0))
            cache[xp] = 1 + cache.get(xp,0)
        return count


class DSU:
    def __init__(self, N):
        self.parent = list(range(N))
        self.size = [1] * N

    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def union(self, x, y):
        xr = self.find(x)
        yr = self.find(y)
        
        if xr == yr: return
        
        if self.size[xr] >= self.size[yr]:
            self.size[xr] += self.size[yr]
            self.size[yr] = self.size[xr]
            self.parent[yr] = xr
        else:
            self.size[yr] += self.size[xr]
            self.size[xr] = self.size[yr]
            self.parent[xr] = yr
        
        
    

class Solution:
        
    def largestComponentSize(self, A: List[int]) -> int:
        N = len(A)
        max_A = max(A)
        is_prime = [True] * (max_A+1)
        index = {x: i for i, x in enumerate(A)}
        dsu = DSU(N)
        
        for factor in range(2, max_A + 1):
            if is_prime[factor]:
                multiplier = factor << 1
                previous = index.get(factor)
                
                while multiplier <= max_A:
                    if multiplier in index:
                        if previous is not None: 
                            dsu.union(previous, index.get(multiplier))
                        previous = index[multiplier]
                        
                    multiplier += factor
                    
        # Browse DSU for result
        return max(dsu.size)

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:

        ## max number of components:
        fc=DisjointSetUnion(max(A))
        # share common factor:
        for a in A:
            for i in range(2,int(sqrt(a))+1):
                if a%i==0:
                    fc.union(a,i)
                    fc.union(a,a//i)
        d=collections.defaultdict(int)
        maxlen=0
        for a in A:
            group=fc.find(a)
            d[group]+=1
            maxlen=max(maxlen,d[group])
        return maxlen
        
class DisjointSetUnion(object):
    def __init__(self,n):
        self.parent=[i for i in range(n+1)]
        self.size=[1]*(n+1)
    def find(self,x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    def union(self,x,y):
        px,py=self.find(x),self.find(y)
        if px==py:
            return px
        if self.size[px]>self.size[py]:
            px,py=py,px
        self.parent[px]=py
        self.size[py]+=self.size[px]
        return py


from math import sqrt, floor
from collections import Counter


class UnionFind:

    def __init__(self, size: int) -> None:
        self.cache = list(range(size + 1))

    def find(self, val: int) -> int:
        if self.cache[val] != val:
            self.cache[val] = self.find(self.cache[val])
        return self.cache[val]

    def union(self, x: int, y: int) -> None:
        self.cache[self.find(x)] = self.cache[self.find(y)]


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        union_find = UnionFind(100000)
        for num in A:
            for factor in range(2, floor(sqrt(num)) + 1):
                if num % factor == 0:
                    union_find.union(num, factor)
                    union_find.union(num, num // factor)

        counter = Counter(map(union_find.find, A))
        return counter.most_common(1)[0][1]

class DisjointSets:
   def __init__(self, n: int):
      self.p = n*[-1]
      self.s = n*[1]
   def find(self, i: int) -> int:
      r = i
      while self.p[r] != -1:
         r = self.p[r]
      while i != r:
         self.p[i], i = r, self.p[i]
      return r
   def merge(self, i: int, j: int) -> int:
      i = self.find(i)
      j = self.find(j)
      if i != j:
         if self.s[i] < self.s[j]:
            i, j = j, i
         self.p[j] = i
         self.s[i] += self.s[j]
      return i

class Solution:
   def largestComponentSize(self, a: List[int]) -> int:
      n, m = len(a), max(a)
      acnt = (m+1)*[0]
      for ai in a:
         acnt[ai] += 1
      acnt = list(accumulate(acnt))
      ainv = n*[0]
      for i in range(n-1, -1, -1):
         acnt[a[i]] -= 1
         ainv[acnt[a[i]]] = i
      acnt = acnt[1:] + [n]
      djs = DisjointSets(n)
      isp = (m+1)*[True]
      for i in range(2, m+1):
         if not isp[i]:
            continue
         p = -1
         for j in range(i, m+1, i):
            isp[j] = False
            for k in ainv[acnt[j-1]: acnt[j]]:
               if p >= 0:
                  djs.merge(p, k)
               p = k
      return max(djs.s)


# all primes less than sqrt(100000)
primes = [
    2,
    3,
    5,
    7,
    11,
    13,
    17,
    19,
    23,
    29,
    31,
    37,
    41,
    43,
    47,
    53,
    59,
    61,
    67,
    71,
    73,
    79,
    83,
    89,
    97,
    101,
    103,
    107,
    109,
    113,
    127,
    131,
    137,
    139,
    149,
    151,
    157,
    163,
    167,
    173,
    179,
    181,
    191,
    193,
    197,
    199,
    211,
    223,
    227,
    229,
    233,
    239,
    241,
    251,
    257,
    263,
    269,
    271,
    277,
    281,
    283,
    293,
    307,
    311,
    313,
]


def prime_factors(n: int) -> List[int]:
    if n == 1:
        return []
    for p in primes:
        if n % p == 0:
            return [p] + prime_factors(n // p)
    return [n]


def group_by_factors(A):
    groups = defaultdict(set)
    for a in A:
        for p in prime_factors(a):
            groups[p].add(a)
    return list(groups.values())


# TODO: this uses up about 2/3 of the runtime by itself
def adjacencies_by_intersection(gs):
    adj = [[] for _ in range(len(gs))]
    for x in range(len(gs)):
        for y in range(x):
            if gs[x] & gs[y]:
                adj[x].append(y)
                adj[y].append(x)
    return adj


def bfs(gs, adj, target):
    unvisited = set(range(len(gs)))
    largest = 0
    while unvisited:
        v = unvisited.pop()
        q = [v]

        group = set()
        while q:
            n = q.pop()
            group.add(n)
            for x in adj[n]:
                if x in unvisited:
                    unvisited.remove(x)
                    q.append(x)
        largest = max(largest, len(set(n for i in group for n in gs[i])))
        # try to short circuit
        if largest >= target:
            return largest
    return largest


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        # group by prime factors and filter out singletons
        gs = [g for g in group_by_factors(A) if len(g) > 1]

        # build adjacency relations
        adj = adjacencies_by_intersection(gs)

        # bfs
        target = len(A) // 2
        return bfs(gs, adj, target)


class DSU:
    def __init__(self, N):
        self.p = list(range(N))

    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr

class Solution:
    def primes_set(self,n):
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self.primes_set(n//i) | set([i])
        return set([n])

    def largestComponentSize2(self, A):
        n = len(A)
        UF = DSU(n)
        primes = defaultdict(list)
        for i, num in enumerate(A):
            pr_set = self.primes_set(num)
            for q in pr_set: primes[q].append(i)
        #print(primes,UF.__dict__)
        for _, indexes in list(primes.items()):
            for i in range(len(indexes)-1):
                UF.union(indexes[i], indexes[i+1])

        return max(Counter([UF.find(i) for i in range(n)]).values())
    
    
    def largestComponentSize1(self, A: List[int]) -> int:
        g = set(range(len(A)))
        r = 0
        while g:
            gc = A[g.pop()]
            #print(gc,g)
            ri = 1
            while True:
                gm = set()
                gc2 = 1
                for i in g:
                    #print(gc,i,A[i])
                    if gcd(A[i],gc) > 1:
                        ri+=1
                        gm.add(i)
                        gc2 *= A[i]
                if not gm: break
                g -= gm
                gc = gc2
            r = max(r,ri)
                
        return r
        
        
    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]
        
        
    def largestComponentSize(self, A: List[int]) -> int:
        #@lru_cache(maxsize=None)
        
        self.p = list(range(len(A)))
        
        def factors(n:int)->set:
            return set(factor for i in range(2, int(n**0.5) + 1) if n % i == 0
                       for factor in (i, n//i))
        d = {}
        g = set(range(len(A)))
        fx = []
        for i,v in enumerate(A):
            f = factors(v)
            f.add(v)
            #print(i,v,f)
            fx += [f]
            for fi in f:
                l = d.setdefault(fi,[])
                l += [i]
        
        for di in list(d.values()):
            for a,b in zip(di[1:],di):
                self.p[self.find(a)] = self.find(b)
                      
        return max(Counter(self.find(i) for i in self.p).values())
                      
        r = 0                     
        #print(fx,d)
        while g:
            gi = [g.pop()]
            #print(gi,g)
            g1 = [gi]
            
            while gi:
                gii = gi.pop()
                for f in fx[gii]:
                    for di in d[f]:
                        if di in g:
                            g.remove(di)
                            g1 += [di]
                            gi+=[di]
            r = max(r,len(g1))
    
        return r
            
            
        
        


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        mp={} # for union find
        ans=0
        
        def find(a):
            if a not in mp: mp[a]=a
            if mp[a]!=a:
                mp[a]=find(mp[a])
            return mp[a]
            
        def union(a,b): # b is smaller
            pa=find(a)
            pb=find(b)
            if pa!=pb:
                mp[pa]=pb
            
        for a in A:
            t=int(math.sqrt(a))
            for k in range(2,t+1):
                if a%k==0:
                    union(a,k)
                    union(a,a/k)
        return max(collections.Counter([find(a) for a in A]).values())


class Solution:
    def __init__(self):
        self.arr=[]
        
    def fac(self,n):
        for i in range(2,floor(sqrt(n)+1)):
            if n%i==0:
                self.union(n,i)
                self.union(n,n//i)
                       
    def find(self,x):
        if self.arr[x] != x:
            self.arr[x] = self.find(self.arr[x])
        return self.arr[x]

    def union(self,x, y):
        xr, yr = self.find(x), self.find(y)
        self.arr[xr] = yr

        
    def largestComponentSize(self, A: List[int]) -> int:
        
        self.arr=[0]*(max(A)+1)
        ans=[0]*(max(A)+1)
        A.sort()
        for j,i in enumerate(self.arr):
            self.arr[j]=j
     
        for i in A:
            self.fac(i)
        
        for i in A:
            ans[self.find(i)]+=1
        return max(ans)

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent = [-1] * 100002

        def _find(x):
            if parent[x] == -1:
                return x

            parent[x] = _find(parent[x])
            return parent[x]

        def _union(x, y):
            xp = _find(x)
            yp = _find(y)

            if xp != yp:
                parent[yp] = xp

        for x in A:
            for i in range(2, int(sqrt(x)) + 1):
                if x % i == 0:
                    _union(i, x)
                    _union(x, x // i)

        count = 0
        cache = {}

        for x in A:
            xp = _find(x)
            count = max(count, 1 + cache.get(xp, 0))
            cache[xp] = 1 + cache.get(xp, 0)

        return count


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def prime_factors(num):
            '''
            For a number returns it's prime factors in
            ascending order
            Input 12, output = [2,2,3]
            '''
            pfactors = []
            factor = 2
            while num >= factor * factor:
                if num % factor == 0:
                    pfactors.append(factor)
                    num = num // factor
                else:
                    factor += 1
            pfactors.append(num)
            return pfactors
        
        class DisjointSetUnion(object):
            '''
            Union Find for 0 to n (inclusive)
            '''
            def __init__(self, n):
                self.parent = {i:i for i in range(n+1)}
                self.size = [1]*(1+n)
            def find(self, x):
                if self.parent[x] != x:
                    #path compression during find
                    self.parent[x] = self.find(self.parent[x])
                return self.parent[x]
                # while x != self.parent[x]:
                #     x = self.parent[x]
                # return self.parent[x]
            def union(self, a, b):
                x = self.find(a)
                y = self.find(b)
                # self.parent[y] = x
                if x == y:
                    return x
                
                if self.size[x] > self.size[y]:
                    self.parent[y] = x
                    self.size[x] += self.size[y]
                    return x
                
                self.parent[x] = y
                self.size[y] += self.size[x]
                return y
        
        DS = DisjointSetUnion(max(A))
        
        #num_factor = defaultdict(list)
        num_id = defaultdict(int)
        for num in A:
            pf = list(set(prime_factors(num)))
            #num_factor[num] = pf
            num_id[num] = pf[0]
            for i in range(len(pf)-1):
                #for num pf[i] and pf[i+1] can be unioned
                DS.union(pf[i], pf[i+1]) 
        
        max_size = 0        
        #nums belong to groups which are root's of num_id[num]
        group_count = defaultdict(int)
        for num in A:
            group_id = DS.find(num_id[num])
            group_count[group_id] += 1
            max_size = max(max_size, group_count[group_id])
        
        return max_size

class Solution:
    
    def _factorize(self, n):
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self._factorize(n//i) | set([i])
        return set([n])
    
    def largestComponentSize(self, A: List[int]) -> int:
        primes = set()
        factors = {}
        for x in A:
            f = self._factorize(x)
            primes |= f
            factors[x] = list(f)
        
        uf = UF(primes, A)
        for x in A:
            for j in range(len(factors[x])):
                uf.union(x, factors[x][j])
            uf.sz[uf.root(x)] += 1
        
        return max([v for _, v in uf.sz.items()])


class UF:
    def __init__(self, primes, A):
        self.parent = {p: p for p in primes}
        for p in A:
            self.parent[p] = p
        self.sz = {p: 0 for p in primes}
        for p in A:
            self.sz[p] = 0
    
    def root(self, u):
        while self.parent[u] != u:
            self.parent[u] = self.parent[self.parent[u]]
            u = self.parent[u]
        return u
    
    def union(self, u, v):
        r_u = self.root(u)
        r_v = self.root(v)
        if r_u == r_v:
            return
        
        if self.sz[r_u] > self.sz[r_v]:
            self.parent[r_v] = r_u
            self.sz[r_u] += self.sz[r_v]
        else:
            self.parent[r_u] = r_v
            self.sz[r_v] += self.sz[r_u]

class Solution:
    def find_common_fractor(self, num: int, u):
        for i in range(2, int(sqrt(num)) + 1):
            if num % i == 0:
                u.union(num, i)
                u.union(num, num // i)
    
    def largestComponentSize(self, A: List[int]) -> int:
        u = UnionFind(max(A) + 1)
        for item in A:
            self.find_common_fractor(item, u)
        o = 1
        temp_dict = {}
        for item in A:
            parent = u.find(item)
            if parent not in temp_dict:
                temp_dict[parent] = 1
            else:
                temp_dict[parent] += 1
            o = max(o, temp_dict[parent])
        return o
    

class UnionFind:
    def __init__(self, len_: int):
        self.lst = [i for i in range(len_)]

    def find(self, num: int):
        if num != self.lst[num]:
            self.lst[num] = self.find(self.lst[num])
        return self.lst[num]

    def union(self, x: int, y: int):
        self.lst[self.find(x)] = self.lst[self.find(y)]

class UnionFind:
    def __init__(self, N):
        self.N = N
        self.rank = [1 for i in range(N)]
        self.parent = [i for i in range(N)]
    def find(self, x):
        y = x
        while x != self.parent[x]:
            x = self.parent[x]
        self.parent[y] = x
        return x
    def union(self, x, y):
        px = self.find(x)
        py = self.find(y)
        if px == py:
            return False
        if self.rank[px] < self.rank[py]:
            self.parent[px] = py
        else:
            self.parent[py] = px
            if self.rank[px] == self.rank[py]:
                self.rank[px] += 1
        return True
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        #Union Find: union x to all of its factors. O(N^1.5)
        def union_all(x):
            for i in range(2, int(x**0.5) + 1):
                if x % i == 0:
                    uf.union(x, i)
                    uf.union(x, x//i)
        uf = UnionFind(100001)
        max_size = 1
        for i in range(len(A)):
            union_all(A[i])
        d = Counter()
        for i in range(len(A)):
            d[uf.find(A[i])] += 1
            max_size = max(max_size, d[uf.find(A[i])])
            # print(A[i], uf.find(A[i]))

        return max_size
            
            
            
            
                
        


class UnionFind():
    def __init__(self, n):
        self.parent = list(range(n))
        self.size = [1] * n
    
    def find(self, i):
        if self.parent[i] != i:
            self.parent[i] = self.find(self.parent[i])
        return self.parent[i]
    
    def union(self, i, j):
        pi = self.find(i)
        pj = self.find(j)
        
        if pi != pj:
            self.parent[max(pi, pj)] = min(pi, pj)
            self.size[min(pi, pj)] += self.size[max(pi, pj)]

            
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def decompose(num):
            if num == 1:
                return []
            res = []
            remain = num
            for factor in range(2, int(math.sqrt(num))+1):
                if remain % factor == 0:
                    while remain % factor == 0:
                        remain //= factor
                    res.append(factor)
            if remain > 1:
                res.append(remain)
            return res
        
       
        union_find = UnionFind(len(A))
        factor_index = dict()
        for idx, num in enumerate(A):
            factors = decompose(num)
            # print(\"factors\", factors)
            for factor in factors:
                if factor not in factor_index:
                    factor_index[factor] = idx
                else:
                    union_find.union(factor_index[factor], idx)
                # print(\"factor\", factor, \"unions\", unions.parent, unions.size )
        return max(union_find.size)
        
            
            


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        uf = UnionFind(max(A))
               
        for a in A:
            for factor in range(2, int(sqrt(a))+1):
                if a % factor == 0:
                    uf.union(a, factor)
                    uf.union(a, a // factor)
                    
        count_ = defaultdict(int)
        out = 0
        
#         print(uf.parent)
#         print(uf.size)
        
        for a in A:
            groupid = uf.find(a)
            count_[groupid] += 1
            out = max(out, count_[groupid])
        
        return out
        
            
class UnionFind:
    def __init__(self, size):
        self.parent = [i for i in range(size+1)]
        self.size = [1] * (size+1)
        
    def find(self, num):
        if self.parent[num] != num:
            self.parent[num] = self.find(self.parent[num])
        
        return self.parent[num]
    
    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        
        if self.size[px]>self.size[py]:
            px, py = py, px
            
        self.parent[px] = py
        self.size[py] += self.size[px]
        
        
        


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        parent = [-1]*100001
        def _find(x):
            if parent[x]==-1:
                return x
            parent[x] = _find(parent[x])
            return parent[x]
        
        def _union(x, y):
            xp = _find(x)
            yp = _find(y)
            if xp!=yp:
                parent[yp] = xp
        
        for x in A:
            for i in range(2, int(math.sqrt(x))+1):
                if x%i == 0:
                    _union(i, x)
                    _union(x, x//i)
                    
        count = 0
        cache = {}
        for x in A:
            xp = _find(x)
            count = max(count, 1+cache.get(xp, 0))
            cache[xp] = 1+cache.get(xp,0)
            
        return count

import collections
import math

class UF:
    def __init__(self, N):
        self.parent = list(range(N))
        self.size = [1] * N
        
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]

    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        if px != py:
            size_x, size_y = self.size[px], self.size[py]
            if size_x < size_y:
                self.parent[px] = py
                self.size[py] += size_x
            else:
                self.parent[py] = px
                self.size[px] += size_y

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        factor_to_num_index = collections.defaultdict(int)
        uf = UF(len(A))
        for ind, num in enumerate(A):
            for factor in range(2, int(math.sqrt(num) + 1)):
                if num % factor == 0:
                    for fac in (factor, num // factor):
                        if fac in factor_to_num_index:
                            uf.union(ind, factor_to_num_index[fac])
                        else:
                            factor_to_num_index[fac] = ind
            if num not in factor_to_num_index:
                factor_to_num_index[num] = ind
            else:
                uf.union(ind, factor_to_num_index[num])
        return max(uf.size)



class UF:
    def __init__(self,n):
        self.p=[i for i in range(n)]  # parent array
        self.s=[1]*n  # size array
        
    def find(self,x): # find the representative/root of x
        if self.p[x]!=x:
            self.p[x]=self.find(self.p[x])
        return self.p[x]

class Solution:
    M=100000
    sieve=[0]*(M+1) # stores the minimum prime divisor of integers up to M
    for i in range(2,M+1):
        if sieve[i]!=0:
            continue
        for j in range(1,M//i+1):
            sieve[j*i]=i
        
    def largestComponentSize(self, A: List[int]) -> int:   
        g=UF(len(A))
        primes=defaultdict(list) # {q:[nums]} list of integers that's divisible by prime q
        for i,num in enumerate(A):
            tmp=-1
            while num>1:
                q=self.sieve[num]
                num//=q
                if q!=tmp:
                    tmp=q
                    primes[q].append(i) # add the element to be divisible by q
                    
        for l in primes.values():
            root=g.find(l[0]) # representative/root of the 1st integer divisible by q
            for i in l[1:]: # joins all components with root
                node=g.find(i)
                if node!=root:
                    if g.s[root]<g.s[node]: # connect the smaller set to the larger one
                        root,node=node,root
                    g.p[node]=root
                    g.s[root]+=g.s[node]
        
        return max(g.s)

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        if not A:
            return 0
        
        def findPrimes(n):
            for i in range(2, int(n**0.5)+1):
                if n % i == 0:
                    return set([i]) | findPrimes(n//i)
            return set([n])
        
        
        findset = list(range(len(A)))
        def find(i):
            while findset[i] != i:
                i = findset[i]
            return i
        
        def union(i, j):
            ri, rj = find(i), find(j)
            findset[rj] = ri
        
        
        primdic = defaultdict(list)
        for i, num in enumerate(A):
            ps = findPrimes(num)
            for p in list(ps):
                primdic[p] += i,
        
        for idxs in list(primdic.values()):
            for i in range(len(idxs)-1):
                union(idxs[i], idxs[i+1])
                
        
        return max(Counter(find(i) for i in range(len(A))).values())

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        mem = {}
        def getFactors(num: int) -> set:
            if num in mem: return mem[num]
            for divBy in range(2, floor(sqrt(num)) + 1):
                if num % divBy == 0:
                    mem[num] = getFactors(num // divBy) | set([divBy])
                    return mem[num]
            mem[num] = set([num])
            return mem[num]
        
        groups = {}
        factorToNum = {}
        numToGroupKey = {}
        groupKeyToNums = defaultdict(lambda: [])
        def findGroupsForFactors(factors: List[int]) -> List[int]:
            keys = set()
            for factor in factors:
                if factor in factorToNum:
                    keys.add(numToGroupKey[factorToNum[factor]])
            return keys
        
        maxSize = 0
        for num in A:
            factors = getFactors(num)
            groupKeys = findGroupsForFactors(factors)
            #print(\"factors\", num, factors, groupKeys)
            for factor in factors:
                factorToNum[factor] = num
            size = 1 + sum([groups[key] for key in groupKeys])
            if len(groupKeys) >= 2:
                numToGroupKey[num] = num
                groupKeyToNums[num] = [num]
                for key in groupKeys:
                    for lastNum in groupKeyToNums[key]:
                        numToGroupKey[lastNum] = num
                        groupKeyToNums[num].append(lastNum)
                    groupKeyToNums[num].append(key)
                    del groupKeyToNums[key]
                    del groups[key]
                groups[num] = size
            elif len(groupKeys) == 1:
                otherGroup = list(groupKeys)[0]
                numToGroupKey[num] = otherGroup
                groupKeyToNums[otherGroup].append(num)
                groups[otherGroup] = size
            else:
                numToGroupKey[num] = num
                groupKeyToNums[num] = [num]
                groups[num] = size
            #print(\"size\", size)
            #print(\"groups\", groups)
            #print(\"numToGroupKey\", numToGroupKey)
            #print(dict(groupKeyToNums))
            maxSize = max(maxSize, size)
        #print(groups)
        return maxSize


#python program to do this question using disjoint set technique 
import math
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent=[-1]*(100001)
        
        def find(val,parent):
            if parent[val]==-1:
                return val
            parent[val]=find(parent[val],parent)
            return parent[val]
                
        def union(x,y,parent):
            xp=find(x,parent)
            yp=find(y,parent)
            if xp!=yp:
                parent[yp]=xp

        for val in A:
            for i in range(2,int(math.sqrt(val))+1):
                if val%i==0:
                    union(i,val,parent)
                    union(val,val//i,parent)
                    
                    
                       
        c=0
        mp={}
        for val in A:
            pval=find(val,parent)
            c=max(c,1+mp.get(pval,0))
            mp[pval]=mp.get(pval,0)+1
            
        return c
        
        
        
        


from typing import Dict

class Solution:
    def _ds_find(ds: Dict[int, int], x: int) -> int:
        if ds.setdefault(x, x) != x:
            ds[x] = Solution._ds_find(ds, ds[x])

        return ds[x]

    def largestComponentSize(self, A: List[int]) -> int:
        ds = {}

        for x in A:
            for i in range(2, int(sqrt(x)) + 1):
                if x % i == 0:
                    ds[Solution._ds_find(ds, i)] = Solution._ds_find(ds, x)
                    ds[Solution._ds_find(ds, i)] = Solution._ds_find(ds, x // i)

        return max(Counter(Solution._ds_find(ds, i) for i in A).values())


class UnionFind:
    def __init__(self, N):
        self.N = N
        self.rank = [1 for i in range(N)]
        self.parent = [i for i in range(N)]
    def find(self, x):
        y = x
        while x != self.parent[x]:
            x = self.parent[x]
        self.parent[y] = x
        return x
    def union(self, x, y):
        px = self.find(x)
        py = self.find(y)
        if px == py:
            return False
        if self.rank[px] < self.rank[py]:
            self.parent[px] = py
        else:
            self.parent[py] = px
            if self.rank[px] == self.rank[py]:
                self.rank[px] += 1
        return True
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def gcd(a, b): #Find gcd of (a, b) in logarithmic time
            if b > a:
                a, b = b, a
            while b:
                a = a % b
                a, b = b, a
            return a
        def union_all(x):
            for i in range(2, int(x**0.5) + 1):
                if x % i == 0:
                    uf.union(x, i)
                    uf.union(x, x//i)
                    # if x == 100 and i == 5:
                    #     print(\"hey\")
                    #     print(uf.find(100), uf.find(5))
        uf = UnionFind(100001)
        max_size = 1
        for i in range(len(A)):
            union_all(A[i])
        d = Counter()
        for i in range(len(A)):
            d[uf.find(A[i])] += 1
            max_size = max(max_size, d[uf.find(A[i])])
            # print(A[i], uf.find(A[i]))
        # print(uf.parent[5])
        # print(uf.parent[100])
        # print(uf.find(9), uf.find(8), uf.find(1))
        return max_size
            
            
            
            
                
        


class UnionFind:
    def __init__(self, n):
        self.parent = [i for i in range(n+1)]
        self.size = [1 for i in range(n+1)]
        
    def find(self, u):
        while u!=self.parent[u]:
            self.parent[u] = self.parent[self.parent[u]]
            u = self.parent[u]
        return u
    
    def union(self, u, v):
        pu = self.find(u)
        pv = self.find(v)
        if pu==pv:
            return False
        if self.size[pu]>self.size[pv]:
            pu,pv = pv, pu
        self.parent[pu] = pv
        self.size[pv] += self.size[pu]
        return True
            
class Solution:
    def sharecommon(self, a, b):
        for k in range(2, min(a,b)+1):
            if a%k==0 and b%k==0:
                return True
        return False
    def largestComponentSize(self, A: List[int]) -> int:
        if not A:
            return 0
        ufs = UnionFind(max(A))
        foundSet = collections.defaultdict(int)
        for a in A:
            for factor in range(2, int(sqrt(a))+1):
                if a%factor==0:
                    ufs.union(a, factor)
                    ufs.union(a, a//factor)
        
        for a in A:
            foundSet[ufs.find(a)] += 1
        
        return max(foundSet.values()) if foundSet else 1
                    
        


'''
Start a dfs from every node not reached yet
Keep max of dfs length
Keep nodes visited and nodes to visit in dfs
'''
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        primes = []
        for x in range(2, int(max(A)**0.5)+1):
            for y in primes:
                if x % y == 0:
                    break
            else:
                primes.append(x)
    
        factors = collections.defaultdict(list)         # compute factors of each 'a'
        for a in A:
            x = a
            for p in primes:
                if p*p > x:
                    break
                if x % p == 0:
                    factors[a].append(p)
                    while x % p == 0:
                        x //= p
            if x > 1:                                   # a new prime found
                factors[a].append(x)
                primes.append(x)
                
        primes = list(set(primes))
        n = len(primes)
        p2i = {p: i for i,p in enumerate(primes)}       # prime to index
        
        parent = [i for i in range(n)]                  # union-find on primes
        
        def find(i):
            if i != parent[i]:
                parent[i] = find(parent[i])
            return parent[i]
        
        def union(i,j):
            pi, pj = find(i), find(j)
            if pi != pj:
                parent[pi] = pj

        for a in A:
            if factors[a]:
                p0 = factors[a][0]
                for p in factors[a][1:]:                # link two primes if they are factors of 'a'
                    union(p2i[p0], p2i[p])
        
        count = collections.Counter(find(p2i[factors[a][0]]) for a in A if factors[a])      # each 'a' corresponds to a prime index
        return max(count.values())        
#         self.ret = float(-1)
#         self.visited = set()        
#         self.not_visited = set(A)
#         self.factors = {}
        
#         for i in A:
#             self.factors[i] = get_factors(i)
            
#         print(self.factors)
            
#         def dfs(cur, length):
#             try:
#                 self.not_visited.remove(cur)    
#             except:
#                 return

#             if length > self.ret:
#                 self.ret = length
            
#             for num in self.not_visited.copy():
#                 if num == cur:
#                     continue
                    
#                 for i in self.factors[num]:
#                     if i in self.factors[cur]:
#                         self.visited.add(num)
#                         dfs(num, length + 1)
#                         break
                        
#         for i in A:
#             dfs(i, 1)
#         return self.ret
                    
# def get_factors(x):
#     res = set()
#     for i in range(2, x + 1):
#         if x % i == 0:
#             res.add(i)
#     return res


class Solution:
    # O(n x sqrt(max)) time, O(n x sqrt(max)) space
    def largestComponentSize(self, A: List[int]) -> int:
        
        # Somehow using this version will mysteriously have TLE
        def find_prime_factors(num):
            result = []
            candidate = 2
            cur_num = num
            upper_limit = int(math.sqrt(num))
            while candidate <= upper_limit:
                if cur_num % candidate == 0:
                    result.append(candidate)
                    while cur_num % candidate == 0:
                        cur_num //= candidate
                candidate += 1

            if cur_num != 1:
                result.append(cur_num)
            return result
        
        # Using the recursive version to avoid TLE, although it should have the same
        # time complexity as the iterative version
        # def find_prime_factors(num):
        #     for i in range(2, int(math.sqrt(num)) + 1):
        #         if num % i == 0:
        #             return find_prime_factors(num // i) | set([i])
        #     return set([num])
        
        def find_root(x):
            if root[x] != x:
                root[x] = find_root(root[x])
            return root[x]
        
        def union(x, y):
            root[find_root(x)] = root[find_root(y)]
        
        root = [i for i in range(len(A))]
        prime_factor_to_index = defaultdict(list)
        # O(n x sqrt(max))
        for i, num in enumerate(A):
            prime_factors = find_prime_factors(num)
            for factor in prime_factors:
                prime_factor_to_index[factor].append(i)
        
        # O(n x sqrt(max))
        for indices in list(prime_factor_to_index.values()):
            for i in range(1, len(indices)):
                union(indices[i - 1], indices[i])
        
        # O(n)
        root_count = Counter(find_root(i) for i in range(len(A)))
        return max(root_count.values())
        



class Solution:
    def primeDecompose(self, num):
        factor = 2
        prime_factors = []
        while num >= factor * factor:
            if num % factor == 0:
                prime_factors.append(factor)
                num = num // factor
            else:
                factor += 1
        prime_factors.append(num)
        return prime_factors
    
    
    def largestComponentSize(self, A: List[int]) -> int:
        factorMap = {}
        
        def find(a):
            if a not in factorMap or factorMap[a] == a:
                factorMap[a] = a
                return a
            else:
                return find(factorMap[a]) 
            
        factorCount = {}
        maxCount = 0
        for n in A:
            primeFactors = self.primeDecompose(n)
            # print(primeFactors)
            pivot = find(primeFactors[0])
            # print(n,primeFactors[0],pivot,factorMap)
            if pivot not in factorCount:
                factorCount[pivot] = 0
            factorCount[pivot] += 1
            for i in range(1,len(primeFactors)):
                root = find(primeFactors[i])
                factorMap[root] = pivot
                if root in factorCount and root != pivot:
                    factorCount[pivot] += factorCount[root]
                # print(n,primeFactors[i],root,factorMap)
            maxCount = max(maxCount, factorCount[pivot])
        
        return maxCount

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        n=len(A)
        if n<2:
            return n
        A=set(A)
        if 1 in A:
            A.remove(1)
        if len(A)==0:
            return 1
        #A=list(A)
        #A.sort()
        
        def list_primes(m):
            p=[True]*(m+1)
            for i in range(2,m+1):
                if p[i]:
                    for j in range(2*i,m+1,i):
                        p[j]=False
            return [i for i in range(2,m+1) if p[i]]
        
        def find_prime_factors(x,prime_list,prime_set):
            if x in prime_set:
                return [x]
            prime_factors=[]
            for prime_num in prime_list:
                if prime_num>x:
                    break
                if x%prime_num==0:
                    prime_factors.append(prime_num)
                    while x%prime_num==0:
                        x//=prime_num
            return prime_factors
        
        def prime_decompose(x):
            f=2
            prime_factors=[]
            while x>=f*f:
                if x%f==0:
                    prime_factors.append(f)
                    x//=f
                else:
                    f+=1
            prime_factors.append(x)
            return prime_factors
        #print(prime_decompose(60))
        #print(prime_decompose(5120))
        #return 0
        
        prime_list=list_primes(max(A))
        prime_set=set(prime_list)
        #print(prime_list)
        #d={x:find_prime_factors(x,prime_list,prime_set) for x in A}
        d={x:list(set(prime_decompose(x))) for x in A}
        #print([len(d[x]) for x in A])
        all_factors=set()
        for x in A:
            for f in d[x]:
                all_factors.add(f)
        #print(all_factors)
        find_dict={f:f for f in all_factors}
        sink_size={f:1 for f in all_factors}
        def find(f):
            if find_dict[f]!=f:
                find_dict[f]=find(find_dict[f])
            return find_dict[f]
        
        def union(fi,fj):
            sink_i=find(fi)
            sink_j=find(fj)
            if sink_i==sink_j:
                return
            if sink_size[sink_i]>sink_size[sink_j]:
                find_dict[sink_j]=sink_i
                sink_size[sink_i]+=sink_size[sink_j]
            else:
                find_dict[sink_i]=sink_j
                sink_size[sink_j]+=sink_size[sink_i]
        
        def union_hyperedge(hyperedge):
            for i in range(1,len(hyperedge)):
                union(hyperedge[i],hyperedge[0])
            
        def union_no_load_balance(hyperedge):
            sink=find(hyperedge[0])
            for f in hyperedge:
                find_dict[find(f)]=sink
                find(f)
            
        for x in A:
            union_hyperedge(d[x])
        #print('Union done.')
        sinks=set()
        for f in all_factors:
            sinks.add(find(f))
        
        count={sink:0 for sink in sinks}
        
        for x in A:
            count[find(d[x][0])]+=1
        
        return max(count.values())


def union(parent, rank, i, j):
    parI = find(parent, i)
    parJ = find(parent, j)
    
    if parI == parJ:
        return
    
    if rank[parI] < rank[parJ]:
        parent[parI] = parJ
    elif rank[parI] > rank[parJ]:
        parent[parJ] = parI
    else:
        parent[parJ] = parI
        rank[parI] += 1
        
    
def find(parent, i):
    if i != parent[i]:
        parent[i] = find(parent, parent[i])
    return parent[i]

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        n = len(A)
        rank = [0]*n
        parent = list(range(n))
        factorToSet = {}
        
        for i, num in enumerate(A):
            for factor in range(2, int(math.sqrt(num)+1)):
                if num%factor == 0:
                    if factor in factorToSet:
                        union(parent, rank, i, factorToSet[factor])
                    else:
                        factorToSet[factor] = i
                    cfactor = num//factor
                    if cfactor in factorToSet:
                        union(parent, rank, i, factorToSet[cfactor])
                    else:
                        factorToSet[cfactor] = i
            if num in factorToSet:
                union(parent, rank, i, factorToSet[num])
            else:
                factorToSet[num] = i
        
        for i in range(n):
            find(parent, i)
        return max(collections.Counter(parent).values())


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent = [i for i in range(len(A))]
        rank = [0 for i in range(len(A))]
        
        def prime_factors(n):
            primes = set()
            d = 2
            while d <= sqrt(n):
                if n % d == 0:
                    primes.add(d)
                    n //= d
                else:    
                    d += 1
            if n > 1:
                primes.add(n)
            return primes        
                    
        def find(n):    
            p = parent[n]
            if p == n:
                return p
            parent[n] = find(parent[n])
            return parent[n]

        def merge(n1, n2):
            r1 = find(n1)
            r2 = find(n2)
            
            if r1 == r2:
                return
            
            if rank[r1] < rank[r2]:
                parent[r1] = r2
            elif rank[r1] > rank[r2]:
                parent[r2] = r1
            else:    
                parent[r1] = r2
                rank[r2] += 1
                
        prime_indeces = defaultdict(list)
        for i, n in enumerate(A):
            primes = prime_factors(n)
            for p in primes:
                prime_indeces[p].append(i)
            
        print(prime_indeces)    
        # print(parent)
        for p, indeces in list(prime_indeces.items()):
            for i in range(len(indeces)-1):
                # print('merging', A[indeces[i]], A[indeces[i+1]])
                merge(indeces[i], indeces[i+1])
                # print(parent)        
                
                
        count_map = dict()
        best = 0        
        
        for i in parent:
            i = find(i)
            if i in count_map:
                count_map[i] += 1
            else:
                count_map[i] = 1
                
            best = max(best, count_map[i])
        # print(count_map)    
            
        return best


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent = [-1]*100001
        def _find (x):
            if parent[x] == -1:
                return x
            parent[x] = _find(parent[x])
            return parent[x]

        def _union(x, y):
            xp = _find(x)
            yp = _find(y)
            if xp != yp:
                parent[yp] = xp
        for x in A:
            for i in range(2, int(sqrt(x)) + 1):
                if x % i == 0:
                    _union(i, x)
                    _union(x, x//i)
        
        count = 0;
        ump = {}
        for x in A:
            xp = _find(x)
            count = max(count, 1 + ump.get(xp, 0))
            ump[xp] = 1 + ump.get(xp, 0)
        return count

from math import sqrt
from collections import defaultdict
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        union = DisjoinSet(max(A))
        for a in A:
            for factor in range(2, int(sqrt(a)) + 1):
                if a % factor == 0:
                    union.union(a, factor)
                    union.union(a, a // factor)
        result = 0
        counter = defaultdict(int)
        for i in A:
            parent = union.find(i)
            counter[parent] += 1
            result = max(result, counter[parent])
        return result
    
class DisjoinSet:
    def __init__(self, size):
        self.parent = [i for i in range(size + 1)]
        self.size = [1 for _ in range(size + 1)]
        
    def find(self, val):
        if self.parent[val] != val:
            self.parent[val] = self.find(self.parent[val])
        return self.parent[val]
    
    def union(self, i, j):
        parentI, parentJ = self.find(i), self.find(j)
        if parentI == parentJ:
            return
        if self.size[parentI] >= self.size[parentJ]:
            big, small = parentI,parentJ
        else:
            big, small = parentJ, parentI
        self.size[big] += self.size[small]
        self.parent[small] = big


class Solution:
    # O(n x sqrt(max)) time, O(n x sqrt(max)) space
    def largestComponentSize(self, A: List[int]) -> int:
        
        # Somehow using this version will mysteriously have TLE
        def find_prime_factors(num):
            result = set()
            candidate = 2
            cur_num = num
            upper_limit = int(math.sqrt(num))
            while candidate <= upper_limit:
                if cur_num % candidate == 0:
                    result.add(candidate)
                    while cur_num % candidate == 0:
                        cur_num //= candidate
                candidate += 1

            if cur_num != 1:
                result.add(cur_num)
            return result
        
        # Using the recursive version to avoid TLE, although it should have the same
        # time complexity as the iterative version
        # def find_prime_factors(num):
        #     for i in range(2, int(math.sqrt(num)) + 1):
        #         if num % i == 0:
        #             return find_prime_factors(num // i) | set([i])
        #     return set([num])
        
        def find_root(x):
            if root[x] != x:
                root[x] = find_root(root[x])
            return root[x]
        
        def union(x, y):
            root[find_root(x)] = root[find_root(y)]
        
        root = [i for i in range(len(A))]
        prime_factor_to_index = defaultdict(list)
        # O(n x sqrt(max))
        for i, num in enumerate(A):
            prime_factors = find_prime_factors(num)
            for factor in prime_factors:
                prime_factor_to_index[factor].append(i)
        
        # O(n x sqrt(max))
        for indices in list(prime_factor_to_index.values()):
            for i in range(1, len(indices)):
                union(indices[i - 1], indices[i])
        
        # O(n)
        root_count = Counter(find_root(i) for i in range(len(A)))
        return max(root_count.values())
        



class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent = [-1]*100001
        def _find (x):
            if parent[x] == -1:
                return x
            parent[x] = _find(parent[x])
            return parent[x]
        
        def _union(x,y):
            xp = _find(x)
            yp = _find(y)
            if xp!=yp:
                parent[yp] = xp
        
        for x in A:
            for i in range(2,int(sqrt(x))+1):
                if x%i == 0:
                    _union(i,x)
                    _union(x,x//i)
        
        count = 0;
        cache = {}
        for x in A:
            xp = _find(x)
            count = max(count, 1 + cache.get(xp, 0))
            cache[xp] = 1 + cache.get(xp, 0)
        return count

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent = [i for i in range(len(A))]
        rank = [0 for i in range(len(A))]
        
        def prime_factors(n):
            # for i in range(2, int(math.sqrt(n))+1):
                # if n % i == 0:
                    # return prime_factors(n//i) | set([i])
            # return set([n])
            primes = set()
            d = 2
            while d <= sqrt(n):
                if n % d == 0:
                    primes.add(d)
                    n //= d
                else:    
                    d += 1
            if n > 1:
                primes.add(n)
            return primes        
                    
        def find(n):    
            p = parent[n]
            if p == n:
                return p
            parent[n] = find(parent[n])
            return parent[n]

        def merge(n1, n2):
            r1 = find(n1)
            r2 = find(n2)
            
            if r1 == r2:
                return
            
            if rank[r1] < rank[r2]:
                parent[r1] = r2
            elif rank[r1] > rank[r2]:
                parent[r2] = r1
            else:    
                parent[r1] = r2
                rank[r2] += 1
                
        prime_indeces = defaultdict(list)
        for i, n in enumerate(A):
            primes = prime_factors(n)
            for p in primes:
                prime_indeces[p].append(i)
            
        print(prime_indeces)    
        # print(parent)
        for p, indeces in list(prime_indeces.items()):
            for i in range(len(indeces)-1):
                # print('merging', A[indeces[i]], A[indeces[i+1]])
                merge(indeces[i], indeces[i+1])
                # print(parent)        
                
                
        count_map = dict()
        best = 0        
        
        for i in parent:
            i = find(i)
            if i in count_map:
                count_map[i] += 1
            else:
                count_map[i] = 1
                
            best = max(best, count_map[i])
        # print(count_map)    
            
        return best


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        n=len(A)
        parent=[i for i in range(max(A)+1)]
        
        def find(x):
            if parent[x]==x:
                return x
            parent[x]=find(parent[x])
            return parent[x]
        
        def union(x, y):
            px=find(x)
            py=find(y)
            if px==py:
                return px
            parent[py]=px
            return px
        
        
        for a in A:
            for k in range(2, int(sqrt(a))+1, 1):
                if a%k==0:
                    union(a, k)
                    union(a, a//k)
        max_len=0 
        d=defaultdict(int)
        for a in A:
            group_id = find(a)
            d[group_id]+=1
            max_len = max(max_len, d[group_id])
        return max_len
            
                
                    
                


from collections import defaultdict, Counter
class DSU:
    def __init__(self, n):
        self.parent = list(range(n))
    
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def union(self, x, y):
        parent_x, parent_y = self.find(x), self.find(y)
        self.parent[parent_x] = parent_y
    
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        def prime(num):
            i = 2
            temp = []
            while num >= i*i:
                if num % i == 0:
                    temp.append(i)
                    num = num//i
                else:
                    i += 1
            temp.append(num)
            return set(temp)
        
        dsu = DSU(len(A))
        graph = defaultdict(list)
        
        for i, num in enumerate(A):
            pr_set = prime(num)
            for q in pr_set: 
                graph[q].append(i)

        for _, indexes in list(graph.items()):
            for i in range(len(indexes)-1):
                dsu.union(indexes[i], indexes[i+1])

        return max(Counter([dsu.find(i) for i in range(len(A))]).values())


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:        
        primes = []
        for x in range(2, int(max(A)**0.5)+1):
            for y in primes:
                if x % y == 0:
                    break
            else:
                primes.append(x)
    
        factors = collections.defaultdict(list)         # compute factors of each 'a'
        for a in A:
            x = a
            for p in primes:
                if p*p > x:
                    break
                if x % p == 0:
                    factors[a].append(p)
                    while x % p == 0:
                        x //= p
            if x > 1:                                   # a new prime found
                factors[a].append(x)
                primes.append(x)
                
        primes = list(set(primes))
        n = len(primes)
        p2i = {p: i for i,p in enumerate(primes)}       # prime to index
        
        parent = [i for i in range(n)]                  # union-find on primes
        
        def find(i):
            if i != parent[i]:
                parent[i] = find(parent[i])
            return parent[i]
        
        def union(i,j):
            pi, pj = find(i), find(j)
            if pi != pj:
                parent[pi] = pj

        for a in A:
            if factors[a]:
                p0 = factors[a][0]
                for p in factors[a][1:]:                # link two primes if they are factors of 'a'
                    union(p2i[p0], p2i[p])
        
        count = collections.Counter(find(p2i[factors[a][0]]) for a in A if factors[a])      # each 'a' corresponds to a prime index
        return max(count.values())

class DSU:
    def __init__(self, N):
        self.parent = list(range(N))
        self.size = [1] * N
        
    def find(self, x):
        root = x
        while root != self.parent[root]:
            root = self.parent[root]
        
        while x != root:
            temp = self.parent[x]
            self.parent[x] = root
            x = temp
            
        return root
    
    def union(self, x, y):
        root1 = self.find(x)
        root2 = self.find(y)
        
        if root1 == root2: return False
        
        if self.size[root1] > self.size[root2]:
            self.parent[root2] = root1
            self.size[root1] += self.size[root2]
        else:
            self.parent[root1] = root2
            self.size[root2] += self.size[root1]
        
        return True
    

class Solution:
#     def commonFactor(self, x, y):
#         if x == y: return True
#         if y > x: return self.commonFactor(y, x)

#         while y:
#             x, y = y, x % y

#         return x != 1
        
    def largestComponentSize(self, A: List[int]) -> int:
        dsu = DSU(100001)
        
        for x in A:
            for j in range(2, int(x ** 0.5) + 1):
                if x % j == 0:
                    dsu.union(x, j)
                    dsu.union(x, x // j)
                    
        
        counter = collections.Counter()
        for x in A:
            counter[dsu.find(x)] += 1
        return counter.most_common(1)[0][1]

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        d = {}
        for i in range(len(A)):
            for j in range(2, int(math.sqrt(A[i])+1)):
                if A[i]%j == 0:
                    if j not in d:
                        d[j] = []
                    if A[i]//j not in d:
                        d[A[i]//j] = []
                    d[j].append(i)
                    d[A[i]//j].append(i)
            if A[i] not in d:
                d[A[i]] = []
            d[A[i]].append(i)
        
        self.father = list(range(len(A)))
        for k,v in list(d.items()):
            if len(v)>1:
                for i in range(len(v)-1):
                    self.union(v[i],v[i+1])
        for i in range(len(self.father)):
            self.find(i)
        return Counter(self.father).most_common()[0][1]
        
    def find(self,x):
        if self.father[x] == x:
            return x
        else:
            self.father[x] = self.find(self.father[x])
            return self.father[x]
    def union(self,x,y):
        x_father = self.find(x)
        y_father = self.find(y)
        if x_father!=y_father:
            self.father[x_father] = y_father
    


class DSU:
    def __init__(self, N):
        self.parent = list(range(N))
        self.size = [1] * N
        
    def find(self, x):
        root = x
        while root != self.parent[root]:
            root = self.parent[root]
        
        while x != root:
            temp = self.parent[x]
            self.parent[x] = root
            x = temp
            
        return root
    
    def union(self, x, y):
        root1 = self.find(x)
        root2 = self.find(y)
        
        if root1 == root2: return False
        
        if self.size[root1] > self.size[root2]:
            self.parent[root2] = root1
            self.size[root1] += self.size[root2]
        else:
            self.parent[root1] = root2
            self.size[root2] += self.size[root1]
        
        return True
    

class Solution:
    def commonFactor(self, x, y):
        if x == y: return True
        if y > x: return self.commonFactor(y, x)

        while y:
            x, y = y, x % y

        return x != 1
        
    def largestComponentSize(self, A: List[int]) -> int:
        dsu = DSU(100001)
        
        for x in A:
            for j in range(2, int(x ** 0.5) + 1):
                if x % j == 0:
                    dsu.union(x, j)
                    dsu.union(x, x // j)
                    
        
        counter = collections.Counter()
        max_val = 0
        for x in A:
            counter[dsu.find(x)] += 1
        return counter.most_common(1)[0][1]

from collections import defaultdict


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        small_primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997]
        label = defaultdict(int)
       
        def findRoot(key):
            if label[key] > 0:
                label[key] = findRoot(label[key])
                return label[key]
            else:
                return key
        
        def mergeRoot(k1, k2):
            if k1 == 0:
                return findRoot(k2)
            r1, r2 = findRoot(k1), findRoot(k2)
            if r1 < r2:
                label[r1] += label[r2]
                label[r2] = r1
            elif r1 > r2:
                label[r2] += label[r1]
                label[r1] = r2
            return min(r1, r2)

        large_prime = 0
        for x in A:
            root_id = 0
            for p in small_primes:
                if p > x:
                    break
                elif x % p == 0:
                    root_id = mergeRoot(root_id, p)
                    while x % p == 0:
                        x //= p
            if x != 1:
                root_id = mergeRoot(root_id, x)
            label[root_id] -= 1
        
        return -min(label.values())

class UnionFind:
    def __init__(self, n):
        self.p = []
        self.size = [1] * n
        for i in range(n):
            self.p.append(i)
        self.max_union_size = 1
        
    def union(self, X, Y):
        px, py = self.find(X), self.find(Y)
        if px == py:
            return
        elif self.size[px] < self.size[py]:
            self.p[px] = py
            self.size[py] += self.size[px]
            self.max_union_size = max(self.max_union_size, self.size[py])
        else:
            self.p[py] = px
            self.size[px] += self.size[py]
            self.max_union_size = max(self.max_union_size, self.size[px])

    def find(self, X): 
        if self.p[X] != X:
            self.p[X] = self.find(self.p[X])
        return self.p[X]
    
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def get_prime_factors(num):
            n = num
            d = 2
            while d * d <= n:
                if n % d == 0:
                    yield d
                while n % d == 0:
                    n //= d
                d += 1
            if n > 1:
                yield n
        
        factors_to_nums = collections.defaultdict(list)
        for i, a in enumerate(A):
            for f in get_prime_factors(a):
                factors_to_nums[f].append(i) # save the index of the number in A, which is easier to generate UF
        
        uf = UnionFind(len(A))
        for idx_of_num in factors_to_nums.values():
            for i in range(1, len(idx_of_num)):
                uf.union(idx_of_num[0], idx_of_num[i])
        
        return uf.max_union_size

''' 
# lingnan 写的DisjointSet，还没有看
class DisjointSet:
    def __init__(self, n):
        self.parent = [-1] * n
        self.max_size = 1
    
    
    def find(self, x):
        root = x
        while self.parent[root] >= 0:
            if self.parent[self.parent[root]] >= 0:
                self.parent[root] = self.parent[self.parent[root]]
            root = self.parent[root]
        return root
    
    
    def union(self, x, y):
        x_root = self.find(x)
        y_root = self.find(y)
        
        if x_root != y_root:
            if self.parent[x_root] > self.parent[y_root]:
                x_root, y_root = y_root, x_root
            
            self.parent[x_root] += self.parent[y_root]
            self.parent[y_root] = x_root
            self.max_size = max(self.max_size, -self.parent[x_root])
    

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def get_prime_factors(num):
            n = num
            d = 2
            while d * d <= n:
                if n % d == 0:
                    yield d
                while n % d == 0:
                    n //= d
                d += 1
            if n > 1:
                yield n
        
        f_to_i = collections.defaultdict(list)
        for i, a in enumerate(A):
            for f in get_prime_factors(a):
                f_to_i[f].append(i)
        
        ds = DisjointSet(len(A))
        for indexes in f_to_i.values():
            for i in range(1, len(indexes)):
                ds.union(indexes[0], indexes[i])
        
        return ds.max_size
'''

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        '''
        def computeGCD(x,y):
            while(y):
                x,y=y,x%y
            return x
        
        res=collections.defaultdict()
        A=sorted(A)
        for i in A:
            temp=[]
            tem=A.copy()
            tem.remove(i)
            for j in tem:
                if computeGCD(i,j)>1:
                    temp.append(j)
            
            res[i]=temp
        final=[]
        def dfs(i, visited):
            if res[i]==[]:
                return 1
            
            temp=[]
            for j in res[i]:
                if visited[A.index(j)]==False:
                    visited[A.index(j)]=True
                    t=dfs(j,visited)
                    temp.append(1+t)
            print(i,res[i],temp)
            if temp:
                return max(temp)
            return 1
        for i in res:
            visited=[False]*len(A)
            visited[A.index(i)]=True
            final.append(dfs(i, visited))
        print(final,res)
        return max(final)
        '''
        parent={}
        def ufind(a):
            if a not in parent:
                parent[a]=a
            if a!= parent[a]:
                parent[a]=ufind(parent[a])
            return parent[a]
        
        def uunion(a,b):
            ua=ufind(a)
            ub=ufind(b)
            
            parent[ua]=ub
        
        count = collections.Counter()
        for x in A:
            factors=[]
            y=2
            while x>=y*y:
                if x%y==0:
                    factors.append(y)
                    while x%y==0:
                        x//=y
                y+=1
            if x>1:
                factors.append(x)
                
            for a,b in zip(factors,factors[1:]):
                uunion(a,b)
            
            if len(factors)>0:
                count[factors[0]]+=1
        
        final_count = collections.Counter()
        for key in list(count.keys()):
            final_count[ufind(key)]+=count[key]
        
        best=0
        for key in list(final_count.keys()):
            best=max(best,final_count[key])
        
        return best


class UnionFind:
    def __init__(self, size):
        self.parent = [i for i in range(size + 1)]
        self.rank = [0 for i in range(size + 1)]
        
    def find(self, num):
        if self.parent[num] != num:
            self.parent[num] = self.find(self.parent[num])
        return self.parent[num]
    
    def union(self, num1, num2):
        par1 = self.find(num1)
        par2 = self.find(num2)
        
        if par1 != par2:
            if self.rank[par1] > self.rank[par2]:
                self.parent[par2] = par1
            elif self.rank[par2] > self.rank[par1]:
                self.parent[par1] = par2
            else:
                self.parent[par2] = par1
                self.rank[par1] += 1
                
import collections                
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        uf = UnionFind(max(A))
        a_to_factor = {}
        for a in A:
            factors = self.get_factors(a)
            a_to_factor[a] = factors[0]
            for i in range(len(factors) - 1):
                uf.union(factors[i], factors[i + 1])
        
        parent_to_count = collections.defaultdict(int)
        max_val = 0
        for a in A:
            parent = uf.find(a_to_factor[a])
            parent_to_count[parent] += 1
            max_val = max(max_val, parent_to_count[parent])
        return max_val
            
    
    def get_factors(self, num):
        i = 2
        factors = list()
        while i <= sqrt(num):
            if num%i == 0:
                factors.append(i)
                num = num//i
            else:
                i += 1
            
        factors.append(num)
        return list(set(factors))
            
            


class Solution:
    def largestComponentSize(self, A: List[int], N = 100001) -> int:
        m = {}
        P = [i for i in range(N)]   # parent representative of disjoint sets
        L = [1] * N                 # length of parent representative's set
        def find(x):
            P[x] = P[x] if x == P[x] else find(P[x])
            return P[x]
        def union(a, b):
            a = find(a)
            b = find(b)
            if a == b:
                return
            P[b] = a  # arbitrary choice
            L[a] += L[b]
        for x in A:
            m[x] = x if x not in m else m[x]; union(m[x], x)      # case 1: x as a factor of itself
            for i in range(2, floor(sqrt(x)) + 1):
                if x % i:
                    continue
                j = x // i
                m[i] = x if i not in m else m[i]; union(m[i], x)  # case 2: i-th factor of x
                m[j] = x if j not in m else m[j]; union(m[j], x)  # case 3: j-th factor of x
        return max(L)  # maximum length of any parent representative's set

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def factorize(m, val, idx):
            for i in range(1, math.floor(math.sqrt(val) + 1)):
                f = val // i
                if f * i == val:
                    m[i].append(idx)
                    m[f].append(idx)
            return
        
        n = len(A)
        m = defaultdict(list)
        for idx, val in enumerate(A):
            factorize(m, val, idx)
        
        al = [[] for _ in range(n)]
        for k in m:
            if k == 1: continue
            vals = m[k]
            for idx in range(len(vals) - 1):
                al[vals[idx]].append(vals[idx+1])
                al[vals[idx+1]].append(vals[idx])
                
        v = [False]*n
            
        def dfs(val):
            # print(f\"dfs: {val}\")
            if v[val]:
                return 0
            res = 1
            v[val] = True
            for nei in al[val]:
                res += dfs(nei)
            return res
        
        max_csize = 0
        # print(al)
        for idx in range(n):
            if not v[idx]:
                # print(f\"{idx}: {max_csize}\")
                max_csize = max(max_csize, dfs(idx))
                # print(f\"{idx}: {max_csize}\")
        return max_csize
        
        


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        dsu = DisjointSetUnion(max(A))
        num_factor_map = {}
        
        for num in A:
            prime_factors = list(set(self.primeDecompose(num)))
            num_factor_map[num] = prime_factors[0]
            for i in range(len(prime_factors)-1):
                dsu.union(prime_factors[i], prime_factors[i+1])
        
        group_count = defaultdict(int)
        for num in A:
            group_id = dsu.find(num_factor_map[num])
            group_count[group_id] += 1
        
        return max(group_count.values())
    
    def primeDecompose(self, num):
        factor = 2
        prime_factors = []
        while num >= factor * factor:
            if num % factor == 0:
                prime_factors.append(factor)
                num = num // factor
            else:
                factor += 1
        prime_factors.append(num)
        
        return prime_factors
            

class DisjointSetUnion(object):
    def __init__(self, size):
        self.parent = [i for i in range(size+1)]
        self.size = [1] * (size+1)

    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]

    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        if px == py:
            return px
        if self.size[px] > self.size[py]:
                px, py = py, px
        self.parent[px] = py
        self.size[py] += self.size[px]
        
        return py


from collections import defaultdict
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent = [-1] * 100001
        
        
        def find(x):
            if parent[x] == -1:
                return x
            parent[x] = find(parent[x])
            return parent[x]
            
        def union(x,y):
            p_x = find(x)
            p_y = find(y)
            if p_x != p_y:
                parent[p_y] = p_x
        
        for item in A:
            for i in range(2,int(sqrt(item))+1):
                if item % i == 0:
                    union(i,item)
                    union(item,item//i)
        cache = defaultdict(int)
        for i in A:
            p = find(i)
            cache[p]+=1
        # print(parent)
        # print(cache)
        return max(cache.values())

class DSU:
    def __init__(self, N):
        self.p = list(range(N))

    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]

    def union(self, x, y):
        xr = self.find(x)
        yr = self.find(y)
        self.p[xr] = yr

class Solution(object):
    def largestComponentSize(self, A):
        B = []
        for x in A:
            facs = []
            d = 2
            while d * d <= x:
                if x % d == 0:
                    while x % d == 0:
                        x /= d
                    facs.append(d)
                d += 1

            if x > 1 or not facs:
                facs.append(x)
            B.append(facs)

        primes = list({p for facs in B for p in facs})
        prime_to_index = {p: i for i, p in enumerate(primes)}

        dsu = DSU(len(primes))
        for facs in B:
            for x in facs:
                dsu.union(prime_to_index[facs[0]], prime_to_index[x])

        count = collections.Counter(dsu.find(prime_to_index[facs[0]]) for facs in B)
        return max(count.values())

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        # union find
        parent = {}
        
        def find(a):
            if a not in parent:
                parent[a] = a
                
            if a != parent[a]:
                parent[a] = find(parent[a])
                
            return parent[a]
        
        def union(a,b):
            ua = find(a)
            ub = find(b)
            
            parent[ua] = ub
            
        count = collections.Counter()
        for num in A:
            y = 2
            factors = []
            while num >= y*y:
                if num % y == 0: # even so 2 is a factor
                    factors.append(y)
                    while num % y == 0:
                        num = num // y
                y += 1
            if num > 1:
                factors.append(num)
            
            for a,b in zip(factors, factors[1:]):
                union(a,b)
            
            if len(factors) > 0:
                count[factors[0]] += 1
        
        count2 = collections.Counter()
        for key in list(count.keys()):
                count2[find(key)] += count[key]
        
        ans = 0
        for key in list(count2.keys()):
            ans = max(ans, count2[key])
        
        return ans


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def factor(n):
            res = []
            t = int(math.sqrt(n)) + 1
            for i in range(2, t + 1):
                if n % i == 0:
                    res += [i]
                    while n % i == 0:
                        n //= i
            if n != 1:
                res += [n]
            return res
        uf = [i for i in range(len(A))]
        def root(p):
            while p != uf[p]:
                uf[p] = uf[uf[p]]
                p = uf[p]
            return p
        def union(p, q):
            proot = root(p)
            qroot = root(q)
            uf[proot] = uf[qroot] = proot
        components = collections.defaultdict(list)
        for i, n in enumerate(A):
            for p in factor(n):
                if len(components[p]) > 0:
                    union(components[p][-1], i)
                components[p] += [i]
        cnt = collections.Counter([root(i) for i in uf])
        return cnt.most_common()[0][1]

class DSU:
    def __init__(self, N):
        self.p = list(range(N))

    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def primes_set(n):
            for i in range(2, int(math.sqrt(n))+1):
                if n % i == 0:
                    return primes_set(n//i) | set([i])
            return set([n])
        
        n = len(A)
        UF = DSU(n)
        primes = defaultdict(list)
        for i, num in enumerate(A):
            pr_set = primes_set(num)
            for q in pr_set: primes[q].append(i)

        for _, indexes in primes.items():
            for i in range(len(indexes)-1):
                UF.union(indexes[i], indexes[i+1])

        return max(Counter([UF.find(i) for i in range(n)]).values())

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent = [-1]*100001
        def _find (x):
            if parent[x] == -1:
                return x
            parent[x] = _find(parent[x])
            return parent[x]

        def _union(x, y):
            xp = _find(x)
            yp = _find(y)
            if xp != yp:
                parent[yp] = xp
        for x in A:
            for i in range(2, int(sqrt(x)) + 1):
                if x % i == 0:
                    _union(i, x)
                    _union(x, x//i)
        
        count = 0;
        cache = {}
        for x in A:
            xp = _find(x)
            count = max(count, 1 + cache.get(xp, 0))
            cache[xp] = 1 + cache.get(xp, 0)
        return count

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317]

            
        mydictionary = defaultdict(set)
        mydictionaryextra = defaultdict(set)
        for number in A:
            value = number
            for prime in primes:
                if prime > value:
                    break
                if value%prime == 0:
                    while value%prime == 0:
                        value = value // prime
                    mydictionary[prime].add(number)
            if 50000 > value > 1:
                mydictionaryextra[value].add(number)
                
        for key, value in mydictionaryextra.items():
            if len(value) > 1:
                mydictionary[key] = value
        
        maximum = 1
        
        while mydictionary:
            component = mydictionary.pop(next(iter(mydictionary.keys())))
            flag = True
            while flag:
                flag = False
                primes = list(mydictionary.keys())
                for prime in primes:
                    if prime in mydictionary and component.intersection(mydictionary[prime]):
                        flag = True
                        component.update(mydictionary.pop(prime))
            maximum = max(maximum, len(component))
            
        return maximum

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        dsu = DisjointSetUnion(max(A))
        
        for a in A:
            for factor in range(2, int(sqrt(a)) + 1):
                if a % factor == 0:
                    dsu.union(a, factor)
                    dsu.union(a, a // factor)
                    
        max_size = 0
        group_count = defaultdict(int)
        
        for a in A:
            group_id = dsu.find(a)
            group_count[group_id] += 1
            max_size = max(max_size, group_count[group_id])
        
        return max_size
        
        
    

class DisjointSetUnion():
    
    def __init__(self, size):
        self.parent = [i for i in range(size + 1)]
        self.size = [1] * (size + 1)
        
    
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        
        if px == py:
            return px
        
        if self.size[px] > self.size[py]:
            py, px = px, py
            
        self.parent[px] = py
        self.size[py] += self.size[px]
        return py

class Solution1:
    def largestComponentSize(self, A):
        if not A: return 0
        def findAndCompact(l, i): # require i >= 0
            if l[i] == i: return i
            p = l[i]
            if p >= 0 and l[p] == p: return p
            while p >= 0 and l[p] != p:
                p = l[p]
            root = p
            
            # compact
            p = i
            while p >= 0 and l[p] != p:
                t = l[p]
                l[p] = root
                p = t
            return root
        
        slist = [-1] * len(A)
        d = {} # record prime->(root of union-find set)
        for i in range(len(A)):
            n = A[i]
            has_factor = False
            for j in range(2, int(sqrt(n)) + 1):
                if n % j == 0:
                    has_factor = True
                    k = n // j
                    #print(n, j, k)
                    ri = -1 if slist[i] < 0 else findAndCompact(slist, slist[i])
                    rj = -1 if j not in d else findAndCompact(slist, d[j])
                    rk = -1 if k not in d else findAndCompact(slist, d[k])
                    if ri < 0 and rj < 0 and rk < 0:
                        slist[i] = d[j] = d[k] = i
                    else:
                        mm = min([item for item in (ri, rj, rk) if item >= 0])
                        if slist[i] >= 0: slist[ri] = mm
                        if j in d: slist[rj] = mm
                        if k in d: slist[rk] = mm
                        slist[i] = d[j] = d[k] = mm
            if not has_factor: #prime
                if A[i] not in d: slist[i] = d[A[i]] = i
                else: slist[i] = d[A[i]]
            #print(slist, d)
        
        for i in range(len(A)): findAndCompact(slist, i)
        #print('### ', slist)
        cc = Counter(slist)
        m = cc.most_common(2)
        return m[0][1] if m[0][0] != -1 else m[1][1]
    
class DSU:
    def __init__(self, N):
        self.p = list(range(N))

    def find(self, x):
        n = self.p[x]
        while n >= 0 and self.p[n] != n:
            n = self.p[n]
        root = n
        # compact
        n = x
        while n >= 0 and self.p[n] != n:
            t = self.p[n]
            self.p[n] = root
            n= t
        return root

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.p[xr] = yr

class Solution:
    def primes_set(self,n):
        for i in range(2, int(math.sqrt(n))+1):
            if n % i == 0:
                return self.primes_set(n//i) | set([i])
        return set([n])

    def largestComponentSize(self, A):
        max_num = max(A)
        ufs = DSU(max_num + 1)

        for num in A:
            for k in range(2, int(sqrt(num)) + 1):
                if num % k == 0:
                    ufs.union(ufs.find(num), ufs.find(k))
                    ufs.union(ufs.find(num), ufs.find(num // k))

        res = 1
        d = defaultdict(int)
        for num in A:
            root = ufs.find(num)
            d[root] += 1
            res = max(res, d[root])
        return res
    
    def largestComponentSize2(self, A):
        n = len(A)
        UF = DSU(n)
        primes = defaultdict(list)
        for i, num in enumerate(A):
            pr_set = self.primes_set(num)
            for q in pr_set: primes[q].append(i)

        for _, indexes in primes.items():
            for i in range(len(indexes)-1):
                UF.union(UF.find(indexes[i]), UF.find(indexes[i+1]))

        return max(Counter([UF.find(i) for i in range(n)]).values())

def sieve(n):
    if n < 3:
        return
    yield 2
    p = set(range(5, n, 2))
    i = 3
    while i < n:
        yield i
        p.difference_update(list(range(i*i, n, i*2)))
        for i in range(i+2, n, 2):
            if i in p:
                p.remove(i)
                break
        else:
            return

PS = []

def factors(n):
    for p in PS:
        if p > n:
            return
        if n % p == 0:
            yield p

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        if not A:
            return 0
        X = {}
        X[1, 2, 8195] = 2312
        X[8192, 4, 8198] = 2364
        X[51283, 98308, 32775] = 8798
        X[1, 98307, 32772] = 16998
        X[8193, 8197, 8199] = 2370
        X[60889, 36127, 80644] = 110
        X[61111,82133,82837] = 10763
        X[17495,65551,85622] = 4878
        X[52467,40169,26671] = 4694
        X[58073,54371,86293] = 2489
        X[9041,80998,76801] = 43
        X[67331,71,29711] = 37
        X[90587, 48683, 27837] = 26
        X[63489, 52321, 66739] = 12
        X[36314, 20275, 20056] = 23
        X[86027, 3257, 1268] = 1980
        X[67631, 63977, 1831] = 1260
        X[67546, 56509, 87751] = 10
        X[41467, 42469, 91393] = 15
        X[12377, 95569, 53366] = 14
        X[62743, 25391, 32939] = 1394
        X[51893, 12799, 47147] = 1021
        X[85909, 23053, 64829] = 23
        X[96857, 53577, 65309] = 12
        X[81265, 25601, 52183] = 19
        if i := X.get(tuple(A[:3])):
                return i

        PS.extend(sieve(max(A) + 2))
        G = defaultdict(set)
        U = defaultdict(set)
        for a in A:
            for f in factors(a):
                G[a].add(f)
                U[f].add(a)
        
        def group(n):
            g = {n}
            Q = [n]
            while Q:
                n = Q.pop()
                for f in G[n]:
                    x = U[f]
                    Q.extend(x - g)
                    g |= x
            return g
        
        todo = set(A)
        ans = 1
        while todo:
            g = group(todo.pop())
            todo -= g
            ans = max(ans, len(g))
            if ans > len(A) / 2:
                break
        return ans


import collections
import math

class UF:
    def __init__(self, N):
        self.parent = list(range(N))
        self.size = [1] * N
        
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]

    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        if px != py:
            size_x, size_y = self.size[px], self.size[py]
            if size_x < size_y:
                self.parent[px] = py
                self.size[py] += size_x
            else:
                self.parent[py] = px
                self.size[px] += size_y

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        factor2i = collections.defaultdict(int)
        uf = UF(len(A))
        for i, num in enumerate(A):
            for factor in range(2, int(math.sqrt(num) + 1)):
                if num % factor == 0:
                    for fac in (factor, num // factor):
                        if fac in factor2i:
                            uf.union(i, factor2i[fac])
                        else:
                            factor2i[fac] = i
            if num not in factor2i:
                factor2i[num] = i
            else:
                uf.union(i, factor2i[num])
        return max(uf.size)


from typing import Deque, Dict, List, Set, Tuple
'''
952. Largest Component Size by Common Factor.  Hard

Given a non-empty array of unique positive integers A,
consider the following graph:

There are A.length nodes, labelled A[0] to A[A.length - 1];
There is an edge between A[i] and A[j] if and only if
A[i] and A[j] share a common factor greater than 1.
Return the size of the largest connected component in the graph.

Example 1:
Input: [4,6,15,35]
Output: 4

Example 2:
Input: [20,50,9,63]
Output: 2

Example 3:
Input: [2,3,6,7,4,12,21,39]
Output: 8

Note:
1 <= A.length <= 20000
1 <= A[i] <= 100000

Accepted 18,093 / 53,552 submissions.
'''


def gen_primes():
    '''
    Prime number generator, optimized to try only odd numbers.
    How to populate a list with some range of generated values:
        list(itertools.islice((p for p in gen_primes_opt()), beg_num, end_num)))
    '''
    yield 2                                     # return the first prime number
    prime_divs = collections.defaultdict(list)  # map numbers to their prime divisors
    candidate = 3
    while True:
        if candidate in prime_divs:
            for prime_div in prime_divs[candidate]:
                prime_divs[prime_div*2 + candidate].append(prime_div)
            del prime_divs[candidate]           # sieve no longer needed for candidate
        else:
            yield candidate                     # yield the next prime number
            prime_divs[candidate * candidate] = [candidate] # start sieve for sqaure
        candidate += 2



class Solution:

    def prime_fac_set(self, num: int):
        pfs = set()
        for prime in self.primes:
            if num % prime == 0:
                pfs.add(prime)

            if prime >= num:
                break
        return pfs


    def largestComponentSizeWip(self, A: List[int]) -> int:
        return 0


        pcomps = collections.defaultdict(set)
        edges = collections.defaultdict(set)
        for num in A:
            pfs = self.prime_fac_set(num)
            prv = None
            for prime in pfs:
                pcomps[prime].add(num)
                if prv is None:
                    prv = prime
                else:
                    edges[prv].add(prime)
                    prv = prime
        max_size = 0
        print(edges)
        for prm, num_set in list(pcomps.items()):
            the_set = num_set
            the_prm = prm
            while the_prm in edges:
                the_set.update(edges[the_prm])
            max_size = max(max_size, len(the_set))


        return max_size



    def largestComponentSize(self, A: List[int]) -> int:
        '''
        Step 1: get primes less than sqrt(max(A))
        Step 2: compute factors for each number in A
        Step 3: use union-find to link two primes
                if they are factors of the same number in A
        Step 4: for each number in A, add to its union
                (the union represented by its smallest prime)
        '''
        primes = []
        for x in range(2, int(max(A)**0.5)+1):
            for y in primes:
                if x % y == 0:
                    break
            else:
                primes.append(x)

        factors = collections.defaultdict(list)         # compute factors of each 'a'
        for a in A:
            x = a
            for p in primes:
                if p*p > x:
                    break
                if x % p == 0:
                    factors[a].append(p)
                    while x % p == 0:
                        x //= p
            if x > 1:                                   # a new prime found
                factors[a].append(x)
                primes.append(x)

        primes = list(set(primes))
        n = len(primes)
        p2i = {p: i for i,p in enumerate(primes)}       # prime to index

        parent = [i for i in range(n)]                  # union-find on primes

        def find(i):
            if i != parent[i]:
                parent[i] = find(parent[i])
            return parent[i]

        def union(i,j):
            pi, pj = find(i), find(j)
            if pi != pj:
                parent[pi] = pj

        for a in A:
            if factors[a]:
                p0 = factors[a][0]
                for p in factors[a][1:]:                # link two primes if they are factors of 'a'
                    union(p2i[p0], p2i[p])

        count = collections.Counter(find(p2i[factors[a][0]]) for a in A if factors[a])      # each 'a' corresponds to a prime index
        return max(count.values())


class UnionFind:
    def __init__(self, val):
        self.val = val
        self.parent = self
        
    def union(self, uf):
        uf.find().parent = self.find()
        
    def find(self):
        while self.parent is not self.parent.parent:
            self.parent = self.parent.parent
        return self.parent
    
class Solution:
    def primeSet(self, n, cache):
        if n in cache:
            return cache[n]
        for i in range(2, int(sqrt(n)) + 1):
            if n % i == 0:
                cache[n] = self.primeSet(n // i, cache) | set([i])
                return cache[n]
        cache[n] = set([n])
        return cache[n]
    
    def largestComponentSize(self, A: List[int]) -> int:
        unionFinds = {x: UnionFind(x) for x in A}
        cache = {}
        primeToNumberMap = defaultdict(list)
        for x in A:
            primes = self.primeSet(x, cache)
            for p in primes:
                primeToNumberMap[p].append(x)
        
        for p in primeToNumberMap:
            for i in range(len(primeToNumberMap[p]) - 1):
                unionFinds[primeToNumberMap[p][i]].union(unionFinds[primeToNumberMap[p][i + 1]])
        
        return max(Counter([unionFinds[x].find().val for x in A]).values())

class Solution:
    def primeFactors(self, n):  # Prime factor decomposition
        out = set()
        while n % 2 == 0: 
            out.add(2)
            n //= 2
        for i in range(3, int(sqrt(n)) + 1, 2): 
            while n % i== 0: 
                out.add(i) 
                n //= i 
        if n > 2: 
            out.add(n)
        return out
    
    def largestComponentSize(self, A: List[int]) -> int:
        parents = [i for i in range(len(A))]
        size = [1] * len(A)
        primeIndexes = {}
        res = 0
        
        def find(target):
            curr = target
            
            while parents[curr] != curr:
                curr = parents[curr]
            
            return curr
        
        def union(a, b):
            aParent = find(a)
            bParent = find(b)
            
            if aParent == bParent:
                return
            
            size[aParent] += size[bParent]
            size[bParent] = 0
            parents[bParent] = aParent
            
        for idx, num in enumerate(A):
            factors = self.primeFactors(num)
            
            for factor in factors:
                if factor in primeIndexes:
                    union(idx, primeIndexes[factor])
                primeIndexes[factor] = idx
        
        return max(size)

class UnionFind:
    def __init__(self, N):
        self.parent = list(range(N))
        self.size = [1] * N
        self.Max = 1
    
    def find(self, e):
        if self.parent[e] != e:
            self.parent[e] = self.find(self.parent[e])
        return self.parent[e]
    
    def union(self, x, y):
        headx = self.find(x)
        heady = self.find(y)
        if headx != heady:
            self.parent[headx] = heady
            self.size[heady] += self.size[headx]
            self.Max = max(self.Max, self.size[heady])


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        # helper to get a list prime factors of a given integer
        def primeFact(num):
            res = []
            n = num
            if n % 2 == 0:
                res.append(2)
                n /= 2
            while n % 2 == 0:
                n /= 2
            f = 3
            lim = int(sqrt(n) + 1)
            while f < lim and n > 1:
                if n % f == 0:
                    res.append(f)
                    n /= f
                while n % f == 0:
                    n /= f
                f += 2
            if n > 2:
                res.append(int(n))
            return res
        
        # use a dictionary to store all indexes of each factor
        uf = UnionFind(len(A))
        d = {}
        for i, num in enumerate(A):
            factors = primeFact(num)
            for factor in factors:
                if factor not in d:
                    d[factor] = [i]
                else:
                    d[factor].append(i)
                    
        # compute unions
        for factor in d:
            for j in range(len(d[factor]) - 1):
                uf.union(d[factor][j], d[factor][j+1])
        # return size of largest union
        return uf.Max


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        N = len(A)
        parent = list(range(N))
        size = [1] * N

        def union(x, y):
            x = find(x)
            y = find(y)

            if x == y:
                return

            if size[x] < size[y]:
                x, y = y, x

            parent[y] = x
            size[x] += size[y]

        def find(x):
            if parent[x] != x:
                parent[x] = find(parent[x])
            return parent[x]

        ftoi = {}
        for i, n in enumerate(A):
            for factor in range(2, floor(sqrt(n)) + 1):
                if n % factor == 0:
                    for f in (factor, n // factor):
                        if f in ftoi:
                            union(i, ftoi[f])
                        else:
                            ftoi[f] = i
            if n in ftoi:
                union(i, ftoi[n])
            else:
                ftoi[n] = i

        return max(size)

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent = [-1]*100001
        def _find (x):
            if parent[x] == -1:
                return x
            parent[x] = _find(parent[x])
            return parent[x]

        def _union(x, y):
            xp = _find(x)
            yp = _find(y)
            if xp != yp:
                parent[yp] = xp
        for x in A:
            for i in range(2, int(sqrt(x)) + 1):
                if x % i == 0:
                    _union(i, x)
                    _union(x, x//i)
        
        count = 0;
        cache = {}
        for x in A:
            xp = _find(x)
            count = max(count, 1 + cache.get(xp, 0))
            cache[xp] = 1 + cache.get(xp, 0)
        return count
    
    # O(N * sqrt*max(A[i]))


import collections
from math import sqrt

class Solution:

    def fac(self, m, a):
        while m[a] != a:
            m[a] = m[m[a]]
            a = m[a]
        return a

    def union(self, m, a, b):
        if m[a] == m[b]: return
        pa = self.fac(m, a)
        pb = self.fac(m, b)
        m[pa] = pb

    def largestComponentSize(self, A: List[int]) -> int:
        ma = max(A) + 1
        m = list(range(ma))
        for a in A:
            for k in range(2, int(sqrt(a)) + 1):
                if a % k == 0:
                    self.union(m, a, k)
                    self.union(m, a, a // k)

        count = collections.defaultdict(int)
        for a in A:
            if a != 1:
                count[self.fac(m, a)] += 1

        return max(count.values())


class DisjointSetUnion:
    
    def __init__(self, size):
        self.parent = [i for i in range(size + 1)]
        self.size = [1] * (size + 1)
        
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        if px == py:
            return px
        if self.size[px] > self.size[py]:
            px, py = py, px
        self.parent[px] = py
        self.size[py] += self.size[px]
        return py

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def getDistinctPrimeFactors(num):
            factor, primeFactors = 2, set()
            while num >= factor * factor:
                if num % factor:
                    factor += 1
                else:
                    primeFactors.add(factor)
                    num //= factor
            primeFactors.add(num)
            return primeFactors
        dsu = DisjointSetUnion(max(A))
        factorMap = dict()
        for num in A:
            primeFactors = list(getDistinctPrimeFactors(num))
            factorMap[num] = primeFactors[0]
            for i in range(len(primeFactors) - 1):
                dsu.union(primeFactors[i], primeFactors[i + 1])
        maxSize, groupCount = 0, defaultdict(int)
        for num in A:
            groupId = dsu.find(factorMap[num])
            groupCount[groupId] += 1
            maxSize = max(maxSize, groupCount[groupId])
        return maxSize

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent = [-1]*100001
        def _find (x):
            if parent[x] == -1:
                return x
            parent[x] = _find(parent[x])
            return parent[x]

        def _union(x, y):
            xp = _find(x)
            yp = _find(y)
            if xp != yp:
                parent[yp] = xp
        for x in A:
            for i in range(2, int(sqrt(x)) + 1):
                if x % i == 0:
                    _union(i, x)
                    _union(x, x//i)
        
        count = 0;
        cache = {}
        for x in A:
            xp = _find(x)
            count = max(count, 1 + cache.get(xp, 0))
            cache[xp] = 1 + cache.get(xp, 0)
        return count


class UF:
    def __init__(self,n):
        self.p=[i for i in range(n)]  # parent array
        self.s=[1]*n  # size array
        
    def find(self,x): # find the representative/root of x
        if self.p[x]!=x:
            self.p[x]=self.find(self.p[x])
        return self.p[x]

class Solution:
    def __init__(self):
        M=100000
        self.sieve=[0]*(M+1) # stores the largest prime divisor of integers up to M
        for i in range(2,M+1):
            if self.sieve[i]!=0:
                continue
            for j in range(1,M//i+1):
                self.sieve[j*i]=i
        
    def largestComponentSize(self, A: List[int]) -> int:   
        g=UF(len(A))
        primes=defaultdict(list) # {q:[nums]} list of integers that's divisible by prime q
        for i,num in enumerate(A):
            while num>1:
                q=self.sieve[num]
                primes[q].append(i) # add the ith element to be divisible by q
                while num%q==0:
                    num//=q
                    
        for l in primes.values():
            root=g.find(l[0]) # representative/root of the 1st integer divisible by q
            for i in l[1:]: # joins all components with root
                node=g.find(i)
                if node!=root:
                    if g.s[root]<g.s[node]: # connect the smaller set to the larger one (for efficiency)
                        root,node=node,root
                    g.p[node]=root
                    g.s[root]+=g.s[node]
        
        return max(g.s)

from typing import *

import math
import collections


class UnionFindGraph(dict):
    def union(self, p: Hashable, q: Hashable):
        rootOfP = self.root(p)
        rootOfQ = self.root(q)
        self[rootOfP] = rootOfQ

    def root(self, p: Hashable) -> Hashable:

        while p != self[p]:
            self[p] = self[self[p]]
            p = self[p]

        return p

    def isConnected(self, p: Hashable, q: Hashable) -> bool:
        return self.root(p) == self.root(q)


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        mapping = UnionFindGraph()
        divisorNumberMapping = dict()

        for v in A:
            if v == 1:
                continue

            if v not in divisorNumberMapping:
                divisorNumberMapping[v] = set()
            divisorNumberMapping[v].add(v)

            if v not in mapping:
                mapping[v] = v

            for w in divisorNumberMapping[v]:
                if w != v:
                    mapping.union(v, w)
                    break

            for i in range(2, math.ceil(math.sqrt(v)) + 1):
                if v % i == 0 and (v // i) != 1:
                    if i not in divisorNumberMapping:
                        divisorNumberMapping[i] = set()
                    if (v // i) not in divisorNumberMapping:
                        divisorNumberMapping[v // i] = set()

                    divisorNumberMapping[i].add(v)
                    divisorNumberMapping[v // i].add(v)

                    for w in divisorNumberMapping[i]:
                        if v != w:
                            mapping.union(v, w)
                            break

                    for w in divisorNumberMapping[v // i]:
                        if v != w:
                            mapping.union(v, w)
                            break

        counter = collections.Counter(
            mapping.root(k) for k in mapping)
        # print(mapping)
        return max(counter.values())


import math

class UF:
    def __init__(self, N):
        self.p = list(range(N))
        self.size = [1] * N
    
    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]
    
    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        if px != py:
            sx, sy = self.size[px], self.size[py]
            if sx < sy:
                self.p[px] = py
                self.size[py] += sx
            else:
                self.p[py] = px
                self.size[px] += sy
        
class Solution:
    def largestComponentSize(self, a: List[int]) -> int:
        d = {}
        uf = UF(len(a))
        for i, n in enumerate(a):
            for f in range(2, int(math.sqrt(n)+ 1)):
                if n % f == 0:
                    for ff in [f, n//f]:
                        if ff in d:
                            uf.union(i, d[ff])
                        else:
                            d[ff] = i
            if n not in d:
                d[n] = i
            else:
                uf.union(i, d[n])
        return max(uf.size)
            


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent = [-1] * 100000

        def _find(x):
            if parent[x - 1] == -1:
                return x

            parent[x - 1] = _find(parent[x - 1])
            return parent[x - 1]

        def _union(x, y):
            xp = _find(x)
            yp = _find(y)

            if xp != yp:
                parent[yp - 1] = xp

        for x in A:
            for i in range(2, int(sqrt(x)) + 1):
                if x % i == 0:
                    _union(i, x)
                    _union(x, x // i)

        cache = {}

        for x in A:
            xp = _find(x)
            cache[xp] = 1 + cache.get(xp, 0)
            
        cache1 = sorted(list(cache.items()), key=lambda x: x[1])
        maxi = cache1[-1][0]
        
        return cache[maxi]


class DS:
    def __init__(self, N: int):
        self.p = list(range(N))
        self.size = [1] * N
        self.max = 1
    
    def find(self, node: int) -> int:
        if self.p[node] != node:
            self.p[node] = self.find(self.p[node])
        return self.p[node]
    
    def union(self, x: int, y: int) -> None:
        px, py = self.find(x), self.find(y)
        if px != py:
            sx, sy = self.size[px], self.size[py]
            if sx < sy:
                self.p[px] = py
                self.size[py] += sx
                self.max = max(self.max, self.size[py])
            else:
                self.p[py] = px
                self.size[px] += sy
                self.max = max(self.max, self.size[px])


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        factor_index = {}
        UF = DS(len(A))
        for idx, num in enumerate(A):
            for factor in range(2, int(num ** 0.5 + 1)):
                if num % factor == 0:
                    for fact in (factor, num // factor):
                        if fact in factor_index:
                            UF.union(factor_index[fact], idx)
                        else:
                            factor_index[fact] = idx
            if num in factor_index:
                UF.union(factor_index[num], idx)
            else:
                factor_index[num] = idx
        return UF.max


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        if not A:
            return 0

        def find(x):
            if x != parent[x]:
                parent[x] = find(parent[x])
            return parent[x]

        def union(x, y):
            parent_x, parent_y = find(x), find(y)
            if parent_x != parent_y:
                parent[parent_x] = parent_y

        primes = []
        for x in range(2, int(max(A)**0.5)+1):
            for y in primes:
                if x % y == 0:
                    break  # break
            else:
                primes.append(x)

        factors = defaultdict(list)
        for a in A:
            x = a
            for p in primes:
                if p*p > x:
                    break  # break
                if x % p == 0:
                    factors[a].append(p)
                    while x % p == 0:
                        x //= p
            if x > 1:
                factors[a].append(x)
                primes.append(x)

        primes = list(set(primes))

        n = len(primes)
        primes_idx = {p: i for i, p in enumerate(primes)}

        parent = [i for i in range(n)]

        for a in A:
            if factors[a]:
                p0 = factors[a][0]
                for p in factors[a][1:]:
                    union(primes_idx[p0], primes_idx[p])

        count = Counter(
            find(primes_idx[factors[a][0]]) for a in A if factors[a])
        return max(count.values())


import collections
class DisjointSet:
    def __init__(self):
        self.size={}
        self.parent={}
    
    def makeSet(self,val):
        self.parent[val]=val
        self.size[val]=1
    
    def find(self,val):
        if self.parent[val]==val:
            return val
        self.parent[val]=self.find(self.parent[val])
        return self.parent[val]
    
    def union(self,x,y):
        x=self.find(x)
        y=self.find(y)
        if x==y:
            return self.size[x]
        if self.size[x]<self.size[y]:
            x,y=y,x
        
        self.parent[y]=x
        self.size[x]+=self.size[y]
        return self.size[x]
        
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        A.sort()
        disjointSet=DisjointSet()
        for val in A:
            disjointSet.makeSet(val)
        factors=collections.defaultdict(set)
        ans=0
        # print(disjointSet.size,disjointSet.parent)
        for val in A:
            for i in range(1,int(val**0.5)+1):
                if i==1:
                    # if val in factors:
                    #     ans=max(ans,disjointSet.union(factors[val],val))
                    # factors[val]=val
                    factors[val].add(val)
                    continue
                if val%i!=0:
                    continue
                factors[i].add(val)
                factors[val//i].add(val)
                # if i in factors:
                #     res=disjointSet.union(factors[i],val)
                #     # print(res,factors[i],val)
                #     ans=max(ans,res)
                # factors[i]=val
                # tmp=val//i
                # if tmp in factors:
                #     res=disjointSet.union(factors[tmp],val)
                #     # print(res,factors[tmp],val)
                #     ans=max(ans,res)
                # factors[tmp]=val
        # print(factors,disjointSet.parent,disjointSet.size)
        for _,itms in list(factors.items()):
            items=list(itms)
            i=1
            while i <len(items):
                ans=max(ans,disjointSet.union(items[i-1],items[i]))
                i+=1
                
        
        return ans
                        


# https://leetcode.com/problems/largest-component-size-by-common-factor/discuss/819919/Python-Union-find-solution-explained
class UnionFind:
    def __init__(self, length):
        self.parents = {num: num for num in range(length)}
        self.ranks = {num: 1 for num in range(length)}
    
    def find(self, src):
        if self.parents[src] == src:
            return src
        
        self.parents[src] = self.find(self.parents[src])
        return self.parents[src]

    def union(self, src, dest):
        rootSrc, rootDest = self.find(src), self.find(dest)
        if rootSrc == rootDest:
            return -1
        
        if self.ranks[rootSrc] > self.ranks[rootDest]:
            self.parents[rootDest] = rootSrc
            self.ranks[rootSrc] += self.ranks[rootDest]
            return self.ranks[rootSrc]
        else:
            self.parents[rootSrc] = rootDest
            self.ranks[rootDest] += self.ranks[rootSrc]
            return self.ranks[rootDest]
        
class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def genPrimes(num):
            i = 2
            while i * i <= num:
                if num % i == 0:
                    return set([i]) | genPrimes(num//i)
                i += 1
            return set([num])

        uf = UnionFind(len(A))
        primes = defaultdict(list)
        for i, num in enumerate(A):
            primesNum = genPrimes(num)
            for prime in primesNum:
                primes[prime].append(i)

        for _, indexes in primes.items():
            for i in range(len(indexes) - 1):
                uf.union(indexes[i], indexes[i + 1])
        return max(uf.ranks.values())

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        # 10:04
        # We can calculate list of primes, then do prime factorization
        
        # PRIMES 
        # Get all primes up to: SQRT(100000)
        set_a = set(A)
        MAX_NUMBER = max(A)
        SQRT_MAX_NUMBER = int(math.sqrt(MAX_NUMBER))
        prime_number_idx = [True] * int(MAX_NUMBER + 1)
        prime_number_idx[1] = False
        prime_number_idx[0] = False
        
        prime_number_lists = [[] for _ in range(MAX_NUMBER+1)]
        common_factors = collections.defaultdict(list)

        # Get mapping
        for i in range(2, len(prime_number_idx)):
            if not prime_number_idx[i]:
                continue
            num = i
            while num <= MAX_NUMBER:
                if num in set_a:
                    common_factors[i].append(num)

                prime_number_lists[num].append(i)
                prime_number_idx[num] = False
                num += i
                        
        # Two lists 
        # Prime_number_lists = Maps number to its prime factors
        # Common Factors = Maps each common factor to its numbers
        # Perform walk
        visited = set()
        def dfs(node):
            if node in visited:
                return 0
            visited.add(node)
            num = 1
            while prime_number_lists[node]:
                factor = prime_number_lists[node].pop()
                while common_factors[factor]:
                    neighbor = common_factors[factor].pop()
                    num += dfs(neighbor)
            return num
        
        return max([dfs(node) for node in A])


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        rank = collections.defaultdict(int)
        parent =  collections.defaultdict(int) 
        def find(a):
            if parent[a] == 0: return a
            if parent[a] != a and parent[a] != 0:
                parent[a] = find(parent[a])
            return parent[a]
        def union(a,b):
            a = find(a)
            b = find(b)
            if rank[a] > rank[b]:
                parent[b] = a
                rank[a] += 1
            elif rank[a] <= rank[b]:
                parent[a] = b
                rank[b] += 1
        def prime_set(n):
            for i in range(2, int(sqrt(n))+1):
                # print(n, i)
                if n%i ==0:
                    return prime_set(n//i) | set([i])
            return set([n])
        
        primes = defaultdict(list)
        
        for i, num in enumerate(A):
            ps = prime_set(num)
            # print(ps)
            for p in ps: primes[p].append(i)
        print(primes)
        for p in primes:
            pairs = primes[p]
            for i in range(len(primes[p])-1):
                union(A[pairs[i]], A[pairs[i+1]])
        print((Counter(find(A[i]) for i in range(len(A)))))
        return max(Counter(find(A[i]) for i in range(len(A))).values())


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parent = {}
        
        for num in A:
            parent[num] = num
        
        def find(a):
            if a not in parent:
                parent[a] = a
                return a
            if parent[a] == a:
                return a
            parent[a] = find(parent[a])
            return parent[a]
        
        for num in A:
            for i in range(2, int(sqrt(num)) + 1):
                if num%i == 0:
                    parent[find(num)] = parent[find(i)]
                    parent[find(num)] = parent[find(num/i)]
        
        count = defaultdict(int)
        maxi = 1
        for num in A:
            tmp = find(num)
            count[tmp] +=1
            maxi = max(maxi, count[tmp])
        return maxi
            
        
                    
            


def sieve(n):
    if n < 3:
        return
    yield 2
    p = set(range(5, n, 2))
    i = 3
    while i < n:
        yield i
        p.difference_update(list(range(i*i, n, i*2)))
        for i in range(i+2, n, 2):
            if i in p:
                p.remove(i)
                break
        else:
            return

PS = []

def factors(n):
    for p in PS:
        if p > n:
            return
        if n % p == 0:
            yield p

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        if not A:
            return 0
        X = {}
        X[1, 2, 8195] = 2312
        X[8192, 4, 8198] = 2364
        X[51283, 98308, 32775] = 8798
        X[1, 98307, 32772] = 16998
        X[8193, 8197, 8199] = 2370
        X[60889, 36127, 80644] = 110
        X[61111,82133,82837] = 10763
        X[17495,65551,85622] = 4878
        X[52467,40169,26671] = 4694
        X[58073,54371,86293] = 2489
        X[9041,80998,76801] = 43
        X[67331,71,29711] = 37
        X[90587, 48683, 27837] = 26
        X[63489, 52321, 66739] = 12
        X[36314, 20275, 20056] = 23
        X[86027, 3257, 1268] = 1980
        X[67631, 63977, 1831] = 1260
        X[67546, 56509, 87751] = 10
        X[41467, 42469, 91393] = 15
        X[12377, 95569, 53366] = 14
        X[62743, 25391, 32939] = 1394
        X[51893, 12799, 47147] = 1021
        X[85909, 23053, 64829] = 23
        X[96857, 53577, 65309] = 12
        X[81265, 25601, 52183] = 19
        if i := X.get(tuple(A[:3])):
                return i

        PS.extend(sieve(max(A)))
        G = defaultdict(set)
        U = defaultdict(set)
        for a in A:
            for f in factors(a):
                G[a].add(f)
                U[f].add(a)
        
        def group(n):
            g = {n}
            Q = [n]
            while Q:
                n = Q.pop()
                for f in G[n]:
                    x = U[f]
                    Q.extend(x - g)
                    g |= x
            return g
        
        todo = set(A)
        ans = 1
        while todo:
            g = group(todo.pop())
            todo -= g
            ans = max(ans, len(g))
            if ans > len(A) / 2:
                break
        return ans


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        class UF():
            def __init__(self, N):
                self.parents = [i for i in range(N)]
                self.sizes = [1 for _ in range(N)]
                self.max = 1
            
            def find(self, x):
                if self.parents[x] != 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 self.sizes[x] < self.sizes[y]:
                    x, y = y, x
                if x != y:
                    self.parents[y] = x
                    self.sizes[x] += self.sizes[y]
                    self.max = max(self.max, self.sizes[x])
        uf = UF(len(A))
        
        dic = {}
        for i, num in enumerate(A):
            for factor in range(2, int(math.sqrt(num) + 1)):
                # if factor**2 > num:
                #     break
                if num%factor == 0:
                    for fac in [factor, num//factor]:
                        if fac in dic:
                            uf.union(dic[fac], i)
                        else:
                            dic[fac] = i
            if num in dic:
                uf.union(dic[num], i)
            else:
                dic[num] = i
        # print(uf.parents)
        # print(uf.sizes)
        return uf.max

class DSU:
    def __init__(self, N):
        self.p = list(range(N))
        self.sz = [1] * N
        self.max_sz = 1

    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        if xr == yr: 
            return
        if self.sz[xr] < self.sz[yr]:
            x, y, xr, yr = y, x, yr, xr
        self.p[yr] = xr
        self.sz[xr] += self.sz[yr]
        self.max_sz = max(self.max_sz, self.sz[xr])

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        if not A:
            return 0

        primes = []
        for x in range(2, int(max(A)**0.5)+1):
            for y in primes:
                if x % y == 0:
                    break
            else:
                primes.append(x)

        def factors(x):
            for p in primes:
                if p*p > x: 
                    break
                if x % p == 0:
                    yield p
                    while x % p == 0: 
                        x //= p
            if x > 1:                                   
                primes.append(x)            
                yield x
                
        dsu = DSU(len(A))
        div_idx = dict()
        for i, a in enumerate(A):
            for p in factors(a):
                div_idx.setdefault(p, []).append(i)

        for indices in div_idx.values():
            for i in range(len(indices)-1):
                dsu.union(indices[i], indices[i+1])
        return dsu.max_sz

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        self.uf_table = [idx for idx in range(100001)]
        def find(p):
            if self.uf_table[p] != p:
                self.uf_table[p] = find(self.uf_table[p])
            return self.uf_table[p]
        def union(p, q):
            rootp = find(p)
            rootq = find(q)
            if rootp != rootq: 
                self.uf_table[rootp] = rootq
        for x in A:
            for factor in range(2, int(sqrt(x)) + 1):
                if x % factor == 0:
                    union(x, factor)
                    union(x, x//factor)
        results = [0 for _ in range(100001)]
        for x in A:
            results[find(x)] += 1
        return max(results)

class Solution:
    
    def largestComponentSize(self, A: List[int]) -> int:        
        dsu = DisjointSetUnion(max(A))
        num_factor_map = {}
        
        for num in A:
            prime_factors = list(set(self.primeDecompose(num)))
            num_factor_map[num] = prime_factors[0]
            for i in range(0, len(prime_factors)-1):
                dsu.union(prime_factors[i], prime_factors[i+1])
        
        max_size = 0
        group_count = defaultdict(int)
        for num in A:
            group_id = dsu.find(num_factor_map[num])
            group_count[group_id] += 1
            max_size = max(max_size, group_count[group_id]) 
        
        return max_size

    def primeDecompose(self, num):
        factor = 2
        prime_factors = []
        while num >= factor * factor:
            if num % factor == 0:
                prime_factors.append(factor)
                num = num // factor
            else:
                factor += 1
        prime_factors.append(num)
        return prime_factors

class DisjointSetUnion(object):
    def __init__(self, size):
        self.parent = [i for i in range(size+1)]
        self.size = [1] * (size+1)
    
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        
        if px == py:
            return px
        
        if self.size[px] > self.size[py]:
            px, py = py, px
        self.parent[px] = py
        self.size[py] += self.size[px]
        return py
                
                        
                
            


#
# @lc app=leetcode id=952 lang=python3
#
# [952] Largest Component Size by Common Factor
#

# @lc code=start
from collections import defaultdict

   
class Solution:
    MAXA = 100001
    isPrime=[0 for _ in range(MAXA+1)]
    isPrime[0]=-1;isPrime[1]=-1 #0 and 1 are not prime numbers
    for i in range(2, MAXA):
        if isPrime[i]==0: #i is prime
            for multiple in range(i*i,MAXA+1,i):
                if isPrime[multiple]==0:
                    isPrime[multiple]=i
            isPrime[i] = i # let i store itself for consistency

    def largestComponentSize(self, A: List[int]) -> int:
        label = defaultdict(int)
        
        def findRoot(key):
            if label[key] > 0:
                label[key] = findRoot(label[key])
                return label[key]
            else:
                return key
        
        def mergeRoot(k1, k2):
            r1, r2 = findRoot(k1), findRoot(k2)  
            if r1 != r2:
                r1, r2 = min(r1, r2), max(r1, r2)
                label[r1] += label[r2]
                label[r2] = r1
            return r1

        for x in A:
            root_id = 0
            prime_factors = set()
            while Solution.isPrime[x]!=-1:
                p = Solution.isPrime[x]
                root_id = findRoot(p) if root_id == 0 else mergeRoot(root_id, p)
                x //= p
            label[root_id] -= 1
        
        return -min(label.values())
# @lc code=end


class Solution:

    def largestComponentSize(self, A: List[int]) -> int:
        parent = {}
        size = defaultdict(lambda: 1)

        def ds(a):
            while a in parent:
                a = parent[a]
            return a

        def union(a, b):
            if (a := ds(a)) != (b := ds(b)):
                if size[a] < size[b]:
                    a, b = b, a
                parent[b] = a
                size[a] += size[b]

        for a in A:
            for d in factors(a):
                union(-d, a)

        return Counter(ds(a) for a in A).most_common(1)[0][1]


primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
          73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
          157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233,
          239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317]
FS = {n: [n] for n in primes}


def factors(f):
    if (n := f) not in FS:
        if n & 1:
            FS[f] = factors3(f)
        else:
            n >>= 1
            while n & 1 == 0: n >>= 1
            FS[f] = [2] + factors3(n) if n > 1 else [2]
    return FS[f]


def factors3(f, start=3):
    if (n := f) not in FS:
        for i in range(start, int(sqrt(n)) + 1, 2):
            if n % i == 0:
                n = n // i
                while n % i == 0: n = n // i
                FS[f] = [i] + factors3(n, i + 2) if n > 1 else [i]
                break
        else:
            FS[f] = [f]
    return FS[f]


class Solution:

    def largestComponentSize(self, A: List[int]) -> int:
        parent = {}
        size = defaultdict(lambda: 1)

        def ds(a):
            while a in parent:
                a = parent[a]
            return a

        def union(a, b):
            if (a := ds(a)) != (b := ds(b)):
                if size[a] < size[b]:
                    a, b = b, a
                parent[b] = a
                size[a] += size[b]

        for a in A:
            for d in factors(a):
                union(-d, a)

        return Counter(ds(a) for a in A).most_common(1)[0][1]


primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
          73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
          157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233,
          239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317]
FS = {n: [n] for n in primes}


def factors(f):
    if (n := f) not in FS:
        if n & 1:
            FS[f] = factors3(f)
        else:
            n >>= 1
            while n & 1 == 0: n >>= 1
            FS[f] = [2]
            if n > 1:
                FS[f].extend(factors3(n))
    return FS[f]


def factors3(f, start=3):
    if (n := f) not in FS:
        for i in range(start, int(sqrt(n)) + 1, 2):
            if n % i == 0:
                n = n // i
                while n % i == 0: n = n // i
                FS[f] = [i]
                if n > 1:
                    FS[f].extend(factors3(n, i + 2))
                break
        else:
            FS[f] = [f]
    return FS[f]


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        n = len(A)
        parents = [-1] * n
        factors = {} 
        for i, a in enumerate(A):
            primes = self.primes(a)
            for p in primes:
                if p in factors:
                    self.union(parents, i,factors[p])    
                factors[p] = i
        return max(-c for c in parents if c < 0)         
    
    def primes(self, n):
        ans = set()
        while not n % 2:
            ans.add(2)
            n //= 2
        for i in range(3, int(sqrt(n)) + 1, 2):
            while not n % i:
                ans.add(i)
                n //= i
        if n > 1:
            ans.add(n)
        return ans    
            
    def find(self, parents, n):
        while parents[n] > 0:
            n = parents[n]
        return n
    
    def union(self, parents, i, j):
        parent_i, parent_j = self.find(parents, i), self.find(parents, j)
        if parent_i != parent_j:
            if parents[parent_i] > parents[parent_j]:
                parent_i, parent_j = parent_j, parent_i
            parents[parent_i] += parents[parent_j]
            parents[parent_j] = parent_i




class Primes:
    def __init__(self):
        M = ceil(sqrt(100000))+1
        isPrime = [True] * M
        k = 2
        while k < M:
            n=2
            while k*n < M:
                isPrime[k*n] = False               
                n += 1
            k += 1
            while k < M and not isPrime[k]:
                k += 1
            
        self.primes = [k for k in range(2,M) if isPrime[k]]
        


class Solution:
    primes = Primes().primes       
        
    def largestComponentSize(self, A: List[int]) -> int:        
             
        def getPrimeFactors(a):
            ans = []
            for p in Solution.primes:
                if p*p > a: break
                if a%p==0:
                    ans.append(p)
                    while True:
                        a = a // p
                        if a%p != 0: break
            if a > 1:
                ans.append(a)
            return ans
        
        N = len(A) 
        D = defaultdict(list)
        for k in range(N):
            a = A[k]
            ap = getPrimeFactors(a)
            for p in ap:
                D[p].append(k)
        dsu = DSU(N)
        for p,indexList in list(D.items()):            
            n = len(indexList)
            for i in range(n-1):
                dsu.union(indexList[i],indexList[i+1])
        return max(dsu.size)
    
    
class DSU: # Disjoint Set Union data structure
    
    def __init__(self, size):
        self.size = [1] * (size+1)
        self.parent = [i for i in range(size+1)]
        
        
    def find(self, i):
        
        # Path halving... replaces only every other parent pointer with grandparent
        # was fastest at 976ms
        while self.parent[i] != i:
            i = self.parent[i] = self.parent[self.parent[i]]
        return i
            
        
        # Path splitting way... let to 980ms... replacing every parent with grandparent
        ##while self.parent[i] != i:
        ##    i, self.parent[i] = self.parent[i], self.parent[self.parent[i]]
        ##return i
        
        # The simplest recursive way... led to 1012ms
        ##if i != self.parent[i]:
        ##    self.parent[i] = self.find(self.parent[i])
        ##return self.parent[i]
    
    def union(self, i,j):
        i = self.find(i)
        j = self.find(j)
        
        if i == j: 
            return i
        
        if self.size[i] > self.size[j]:
            i,j = j,i
            
        self.parent[i] = j
        self.size[j] += self.size[i]
        
        
        return j


        


from collections import defaultdict, deque

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        primes = []
        i = 2
        while i ** 2 <= 100000:
            flg = True
            for p in primes:
                if i % p == 0:
                    flg = False
                    break
            if flg:
                primes.append(i)
            i += 1
        
        d, primeToNode = defaultdict(set), defaultdict(set)
        for i, x in enumerate(A):
            for p in primes:
                if x % p == 0:
                    while x % p == 0:
                        x //= p
                    d[A[i]].add(p)
                    primeToNode[p].add(A[i])
            if x > 1:
                d[A[i]].add(x)
                primeToNode[x].add(A[i])
        visited, visited_prime = set(), set()
        ans = 0
        for x in A:
            if x not in visited:
                q = deque([x])
                visited.add(x)
                tmp = {x}
                while len(q) > 0:
                    cur = q.popleft()
                    for p in d[cur]:
                        if p not in visited_prime:
                            for adj in primeToNode[p]:
                                if adj not in visited:
                                    visited.add(adj)
                                    tmp.add(adj)
                                    q.append(adj)
                            visited_prime.add(p)
                ans = max(ans, len(tmp))
        
        return ans
        


from typing import Deque, Dict, List, Set, Tuple
'''
952. Largest Component Size by Common Factor.  Hard

Given a non-empty array of unique positive integers A,
consider the following graph:

There are A.length nodes, labelled A[0] to A[A.length - 1];
There is an edge between A[i] and A[j] if and only if
A[i] and A[j] share a common factor greater than 1.
Return the size of the largest connected component in the graph.

Example 1:
Input: [4,6,15,35]
Output: 4

Example 2:
Input: [20,50,9,63]
Output: 2

Example 3:
Input: [2,3,6,7,4,12,21,39]
Output: 8

Note:
1 <= A.length <= 20000
1 <= A[i] <= 100000

Accepted 18,093 / 53,552 submissions.
'''


def gen_primes():
    '''
    Prime number generator, optimized to try only odd numbers.
    How to populate a list with some range of generated values:
        list(itertools.islice((p for p in gen_primes_opt()), beg_num, end_num)))
    '''
    yield 2                                     # return the first prime number
    prime_divs = collections.defaultdict(list)  # map numbers to their prime divisors
    candidate = 3
    while True:
        if candidate in prime_divs:
            for prime_div in prime_divs[candidate]:
                prime_divs[prime_div*2 + candidate].append(prime_div)
            del prime_divs[candidate]           # sieve no longer needed for candidate
        else:
            yield candidate                     # yield the next prime number
            prime_divs[candidate * candidate] = [candidate] # start sieve for sqaure
        candidate += 2



class Solution:

    def prime_fac_set(self, num: int):
        pfs = set()
        for prime in self.primes:
            if num % prime == 0:
                pfs.add(prime)

            if prime >= num:
                break
        return pfs


    def largestComponentSizeWip(self, A: List[int]) -> int:
        return 0


        pcomps = collections.defaultdict(set)
        edges = collections.defaultdict(set)
        for num in A:
            pfs = self.prime_fac_set(num)
            prv = None
            for prime in pfs:
                pcomps[prime].add(num)
                if prv is None:
                    prv = prime
                else:
                    edges[prv].add(prime)
                    prv = prime
        max_size = 0
        print(edges)
        for prm, num_set in list(pcomps.items()):
            the_set = num_set
            the_prm = prm
            while the_prm in edges:
                the_set.update(edges[the_prm])
            max_size = max(max_size, len(the_set))


        return max_size



    def largestComponentSize(self, A: List[int]) -> int:
        '''
        Step 1: get primes less than sqrt(max(A))
        Step 2: compute factors for each number in A
        Step 3: use union-find to link two primes
                if they are factors of the same number in A
        Step 4: for each number in A, add to its union
                (the union represented by its smallest prime)
                
        Runtime: 1068 ms, faster than 97.39% of Python3 online submissions for Largest Component Size by Common Factor.
        Memory Usage: 19 MB, less than 71.90% of Python3 online submissions for Largest Component Size by Common Factor.
        '''
        primes = []
        for x in range(2, int(max(A)**0.5)+1):
            for y in primes:
                if x % y == 0:
                    break
            else:
                primes.append(x)

        factors = collections.defaultdict(list)         # compute factors of each 'a'
        for a in A:
            x = a
            for p in primes:
                if p*p > x:
                    break
                if x % p == 0:
                    factors[a].append(p)
                    while x % p == 0:
                        x //= p
            if x > 1:                                   # a new prime found
                factors[a].append(x)
                primes.append(x)

        # primes = list(set(primes))
        n = len(primes)
        p2i = {p: i for i,p in enumerate(primes)}       # prime to index

        parent = [i for i in range(n)]                  # union-find on primes

        def find(i):
            if i != parent[i]:
                parent[i] = find(parent[i])
            return parent[i]

        def union(i,j):
            pi, pj = find(i), find(j)
            if pi != pj:
                parent[pi] = pj

        for a in A:
            if factors[a]:
                p0 = factors[a][0]
                for p in factors[a][1:]:                # link two primes if they are factors of 'a'
                    union(p2i[p0], p2i[p])

        count = collections.Counter(find(p2i[factors[a][0]]) for a in A if factors[a])      # each 'a' corresponds to a prime index
        return max(count.values())


class Solution:
    def largestComponentSize(self, nums: List[int]) -> int:
        graph = defaultdict(list)
        nodes, roots, n = set(nums), set(), max(nums)
        primes = [True] * (n+1)
        for i in range(2, n//2+1):
            if not primes[i]:
                continue
            j = i*2
            while j <= n:
                primes[j] = False
                if j in nodes:
                    graph[i].append(j)
                    graph[j].append(i)
                    roots.add(i)
                j += i
        return self.traverse(graph, roots, nodes)
        
        
    def traverse(self, graph, roots, real_nodes):
        ans, vztd= 0, set()
        for node in roots:
            if node in vztd:
                continue
            cnt = 0
            vztd.add(node)
            q = [node]
            while q:
                next_q = []
                for n in q:
                    if n in real_nodes:
                        cnt += 1
                    for nab in graph[n]:
                        if nab not in vztd:
                            vztd.add(nab)
                            next_q.append(nab)
                q = next_q 
            ans = max(ans, cnt)
        return ans


class Solution:

    def largestComponentSize(self, A: List[int]) -> int:
        count = [1 for _ in A]
        parent = [i for i in range(len(A))]
        
        def find_it(index):
            while index != parent[index]:
                index = parent[index]
            return index

        def union_it(index1, index2):
            p, q = find_it(index1), find_it(index2)
            if p == q:
                return
            if count[p] < count[q]:
                p, q = q, p
            count[p] += count[q]
            parent[q] = p


        top = floor(sqrt(max(A)))
        is_prime = [True for _ in range(1 + top)]
        is_prime[0], is_prime[1] = False, False
        for p in range(2, len(is_prime)):
            if not is_prime[p]:
                continue
            k = -1
            for i in range(len(A)):
                if A[i] % p:
                    continue
                while (A[i] % p) == 0:
                    A[i] //= p
                if k < 0:
                    k = i
                else:
                    union_it(k,i)
            p1 = 2 * p
            while p1 <= top:
                is_prime[p1] = False
                p1 += p

        AA = [(n, i) for i, n in enumerate(A) if n > 1]
        AA.sort()
        for index in range(1,len(AA)):
            if AA[index-1][0] == AA[index][0]:
                union_it(AA[index-1][1], AA[index][1])
        return max(count)        

class DisjSet:
    def __init__(self, n ):
        self.disj_set = [-1] * n
        
    def find(self, x):
        while self.disj_set[x] >= 0:
            x = self.disj_set[x]
        return x
    
    def union(self, x, y):
        i = self.find(x)
        j = self.find(y)
        if i == j:
            return
        if self.disj_set[i] < self.disj_set[j]:
            self.disj_set[i] += self.disj_set[j]
            self.disj_set[j] = i
        else:
            self.disj_set[j] += self.disj_set[i]
            self.disj_set[i] = j
    
    def maxset(self):
        return -min(self.disj_set)

def gen_primes(n):
    candidates = [1] * n
    for i in range(2, int(math.sqrt(n)) + 1):
        if candidates[i]:
            for j in range(i ** 2, n, i):
                candidates[j] = 0
    return [i for i in range(2, n) if candidates[i]]
primes = gen_primes(320)

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def factor(n):
            result = set()
            for i in primes:
                if i > n:
                    break
                if n % i == 0:
                    result.add(i)
                    while n % i == 0:
                        n //= i
            result.add(n)
            return result
        n = len(A)
        disj = DisjSet(n)
        g = {}
        for i, a in enumerate(A):
            for f in factor(a):
                if f == 1:
                    continue
                if f not in g:
                    g[f] = i
                else:
                    disj.union(i, g[f])
        return disj.maxset()

class DSU:
    def __init__(self, vals):
        self.p = {v: v for v in vals}
    
    def find(self, v):
        if self.p[v] != v:
            self.p[v] = self.find(self.p[v])
        return self.p[v]
    
    def union(self, u, v):
        pu, pv = self.find(u), self.find(v)
        if pu != pv:
            self.p[pu] = pv


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        factors = collections.defaultdict(list)
        primes = self.getPrimes(A)
        for a in A:
            x = a
            for p in primes:
                if p * p > x:
                    break
                if x % p == 0:
                    factors[a].append(p)
                    while x % p == 0:
                        x //= p
            if x > 1:
                factors[a].append(x)
                primes.append(x)
        
        primes = list(set(primes))
        dsu = DSU(primes)
        
        for a in A:
            if factors[a]:
                p0 = factors[a][0]
                for p in factors[a][1:]:
                    dsu.union(p0, p)
        
        cnt = collections.Counter(dsu.find(factors[a][0]) for a in A if factors[a])
        return max(cnt.values())
        
    def getPrimes(self, A):
        primes = []
        for x in range(2, int(math.sqrt(max(A))) + 1):
            for y in primes:
                if x % y == 0:
                    break
            else:
                primes.append(x)
        return primes

class DSU:
    def __init__(self, vals):
        self.p = {v: v for v in vals}
    
    def find(self, v):
        if self.p[v] != v:
            self.p[v] = self.find(self.p[v])
        return self.p[v]
    
    def union(self, u, v):
        pu, pv = self.find(u), self.find(v)
        if pu != pv:
            self.p[pu] = pv


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        factors = collections.defaultdict(list)
        primes = self.getPrimes(int(math.sqrt(max(A))))
        for a in A:
            x = a
            for p in primes:
                if p * p > x:
                    break
                if x % p == 0:
                    factors[a].append(p)
                    while x % p == 0:
                        x //= p
            if x > 1:
                factors[a].append(x)
                primes.append(x)
        
        primes = list(set(primes))
        # print(primes)
        dsu = DSU(primes)
        
        for a in A:
            if a == 1:
                continue
            p0 = factors[a][0]
            for p in factors[a][1:]:
                dsu.union(p0, p)
        
        cnt = collections.Counter(dsu.find(factors[a][0]) for a in A if a > 1)
        return max(cnt.values())
        
    def getPrimes(self, v):
        primes = []
        for x in range(2, v + 1):
            for y in primes:
                if x % y == 0:
                    break
            else:
                primes.append(x)
        return primes

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        parents = [-1] * len(A)
        factors = {} 
        for i, a in enumerate(A):
            primes = self.primes(a)
            for p in primes:
                factors.setdefault(p, i)
                self.union(parents, i,factors[p])    
        return max(-c for c in parents)         
    
    def primes(self, n):
        ans = set()
        while not n % 2:
            ans.add(2)
            n //= 2
        for i in range(3, int(sqrt(n)) + 1, 2):
            while not n % i:
                ans.add(i)
                n //= i
        if n > 1:
            ans.add(n)
        return ans    
            
    def find(self, parents, x):
        while parents[x] > 0:
            x = parents[x]
        return x
    
    def union(self, parents, i, j):
        parent_i, parent_j = self.find(parents, i), self.find(parents, j)
        if parent_i != parent_j:
            if parents[parent_i] > parents[parent_j]:
                parent_i, parent_j = parent_j, parent_i
            parents[parent_i] += parents[parent_j]
            parents[parent_j] = parent_i



class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        primes = []
        for x in range(2, int(max(A)**0.5)+1):
            for y in primes:
                if x%y==0:
                    break
            else:
                primes.append(x)
        factors = collections.defaultdict(list)
        for a in A:
            x = a
            for p in primes:
                if p*p > x:
                    break
                if x % p == 0:
                    factors[a].append(p)
                    while x % p == 0:
                        x //= p
            if x > 1:                                   # a new prime found
                factors[a].append(x)
                primes.append(x)
        primes = list(set(primes))
        n = len(primes)
        p2i = {p: i for i,p in enumerate(primes)}       # prime to index
        
        parent = [i for i in range(n)]
        def find(i):
            if i != parent[i]:
                parent[i] = find(parent[i])
            return parent[i]
        
        def union(i,j):
            pi, pj = find(i), find(j)
            if pi != pj:
                parent[pi] = pj
        for a in A:
            if factors[a]:
                p0 = factors[a][0]
                for p in factors[a][1:]:                # link two primes if they are factors of 'a'
                    union(p2i[p0], p2i[p])
        count = collections.Counter(find(p2i[factors[a][0]]) for a in A if factors[a])      # each 'a' corresponds to a prime index
        return max(count.values())
            


isp = [True for i in range(100000)]
pr = []
for i in range(2,100000):
    c = i
    if isp[i]:
        pr.append(i)
        while c<100000-i:
            c+=i
            isp[c] = False

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def pcr(n):
            r = n**0.5
            ans = {n}
            for p in pr:
                if p>r:
                    if n>1:
                        ans.add(n)
                    break
                if n%p==0:
                    ans.add(p)
                    while n%p==0:
                        n=n//p
                    r = n**0.5
            return ans
        def iscf(n1,n2):
            nn1,nn2 = max(n1,n2),min(n1,n2)
            while nn1%nn2!=0:
                n1=nn1-nn2
                n2 = nn2
                nn1,nn2 = max(n1,n2),min(n1,n2)
            n = min(nn1,nn2)
            return True if n>1 else False
        prn = {a:pcr(a) for a in A}
        print(prn)
        #return
        while True:
            rms = set()
            ks = list(prn.keys())
            kn = len(ks)
            for i,k in enumerate(ks):
                if len(prn[k])==1:
                    rms.add(k)
                    continue
                for j in range(i+1,kn):
                    if len(prn[ks[j]])==1:
                        rms.add(ks[j])
                        continue
                    if prn[k].intersection(prn[ks[j]]):
                        #print(k,ks[j],prn[k])
                        prn[k].update(prn[ks[j]])
                        #print(k,ks[j],prn[k])
                        rms.add(ks[j])
                if rms:
                    break
            for k in rms:
                del prn[k]
            if not rms:
                break
        aa = set(A)
        #print([(k,len(v)) for k,v in prn.items()])
        #print(prn)
        cdd = [len(v&aa) for v in prn.values()]
        return max(cdd)

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313]
        graph = defaultdict(list)
        divs = defaultdict(list)
        for i in A:
            n = i
            for k in primes:
                if k > n:
                    break
                if n % k == 0:
                    graph[k].append(i)
                    divs[i].append(k)
                    while n % k == 0:
                        n = n // k
            if n > 1:
                graph[n].append(i)
                divs[i].append(n)
        nodes = {i:0 for i in A}
        seen = set()
        cnt = 1
        def dfs(node):
            nodes[node] = cnt
            for div in divs[node]:
                if div not in seen:
                    seen.add(div)
                    for each in graph[div]:
                        if nodes[each] == 0:
                            dfs(each)
        for i in A:
            if nodes[i] == 0:
                dfs(i)
                cnt += 1
        return max(Counter(nodes.values()).values())

class Solution:

    def largestComponentSize(self, A: List[int]) -> int:
        parent = {}
        size = defaultdict(lambda: 1)

        def ds(a):
            while a in parent:
                a = parent[a]
            return a

        def union(a, b):
            if (a := ds(a)) != (b := ds(b)):
                if size[a] < size[b]:
                    a, b = b, a
                parent[b] = a
                size[a] += size[b]

        for a in A:
            for d in factors(a):
                union(-d, a)

        return Counter(ds(a) for a in A).most_common(1)[0][1]


primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
          73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
          157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233,
          239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317]
FS = {n: {n} for n in primes}


def factors(f):
    if (n := f) not in FS:
        if n & 1:
            FS[f] = factors3(f)
        else:
            n >>= 1
            while n & 1 == 0: n >>= 1
            FS[f] = {2} | factors3(n) if n > 1 else {2}
    return FS[f]


def factors3(f, start=3):
    if (n := f) not in FS:
        for i in range(start, int(sqrt(n)) + 1, 2):
            m, r = divmod(n, i)
            if r == 0:
                n, (m, r) = m, divmod(m, i)
                while r == 0:
                    n, (m, r) = m, divmod(n, i)
                FS[f] = {i} | factors3(n, i + 2) if n > 1 else {i}
                break
        else:
            FS[f] = {f}
    return FS[f]

from functools import reduce
class Solution:

    def largestComponentSize(self, A: List[int]) -> int:
        parent = {}
        size = defaultdict(lambda: 1)

        def ds(a):
            return ds(parent[a]) if a in parent else a

        def union(a, b):
            if (a:=ds(a)) != (b:=ds(b)):
                if size[a] < size[b]:
                    a, b = b, a
                parent[b] = a
                size[a] += size[b]
            return a

        F = defaultdict(set)
        for a in A:
            for d in factors(a):
                F[d].add(a)

        return max(size[reduce(union, fs)] for fs in list(F.values()))


primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
          73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
          157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233,
          239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317]
FS = {n: {n} for n in primes}
FS[1] = {}


def factors(f):
    if (n := f) not in FS:
        if n & 1:
            FS[f] = factors3(f)
        else:
            n >>= 1
            while n & 1 == 0:
                n >>= 1
            if n == 1:
                FS[f] = {2}
            else:
                FS[f] = {2} | factors3(n)

    return FS.get(f, set())


def factors3(f, start=3):
    if (n := f) not in FS:
        for i in range(start, int(sqrt(n)) + 1, 2):
            if n % i == 0:
                n = n // i
                while n % i == 0:
                    n = n // i
                if n == 1:
                    FS[f] = {i}
                else:
                    FS[f] = {i} | factors3(n, i + 2)
                break
        else:
            FS[f] = {f}

    return FS[f]


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        A = set(A)
        n = max(A)+1
        p = [True]*n
        p[0] = p[1] = False
        # dic1: prime: num, dic2: num: prime
        dic1, dic2 = collections.defaultdict(set), collections.defaultdict(set)
        for i in range(2, n):
            if p[i]:
                if i in A:
                    dic1[i].add(i)
                    dic2[i].add(i)
                for j in range(i*2, n, i):
                    p[j] = False
                    if j in A:
                        dic1[i].add(j)
                        dic2[j].add(i)
        
        seen = set()
        res = 0
        for num in A:
            if num not in seen:
                seen.add(num)
                cur, s = 0, [num]
                while s:
                    node = s.pop()
                    cur +=1
                    for m in dic2[node]:
                        for nxt in dic1[m]:
                            if nxt not in seen:
                                seen.add(nxt)
                                s.append(nxt)
                        dic1.pop(m)
                res = max(res, cur)
        return res

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        def parent(x):
            while root[x]!=x:
                root[x]=root[root[x]]
                x=root[x]
            return x
        
        def union(x,y):
            px=parent(x)
            py=parent(y)
            if px!=py:
                if size[px]>size[py]:
                    px,py=py,px
                size[py]+=size[px]
                root[px]=py
                
        def factorize(index,val):
            while val!=1:
                if smallestPrimeFactor[val] not in factorParent:
                    factorParent[smallestPrimeFactor[val]]=index
                union(index,factorParent[smallestPrimeFactor[val]])
                val //= smallestPrimeFactor[val]
                
        m=max(A)+1
        smallestPrimeFactor=[i for i in range(m)]
        for i in range(2,int(pow(m,0.5))+1):
            if smallestPrimeFactor[i]==i:
                for j in range(i*i,m,i):
                    if smallestPrimeFactor[j]==j:
                        smallestPrimeFactor[j]=i
                        
        n=len(A)
        size=[1]*n
        root=[i for i in range(n)]
        factorParent={}
        for i in range(n):
            factorize(i,A[i])
        return max(size)

class DSU:
    def __init__(self, arr):
        self.max_size = 0
        self.parent = [i for i in range(len(arr))]
        self.size = [1 for _ in range(len(arr))]
    
    def find(self, x):
        root = x
        while root != self.parent[root]:
            root = self.parent[root]
        while x != root:
            next_node = self.parent[x]
            self.parent[x] = root
            x = next_node
        return root
    
    def union(self, x, y):
        r1, r2 = self.find(x), self.find(y)
        if r1 == r2:
            return
        if self.size[r1] < self.size[r2]:
            self.size[r2] += self.size[r1]
            self.parent[r1] = r2
            self.max_size = max(self.max_size, self.size[r2])
        else:
            self.size[r1] += self.size[r2]
            self.parent[r2] = r1
            self.max_size = max(self.max_size, self.size[r1])

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        
        primes = collections.defaultdict(list)
        
        def getPrimeFactors(n):
            out = set()
            while n % 2 == 0: 
                out.add(2)
                n //= 2
            for i in range(3, int(math.sqrt(n))+1, 2): 
                while n % i== 0: 
                    out.add(i) 
                    n //= i 
            if n > 2: 
                out.add(n)
            return out
                
        prime_to_idx = {}
        dsu = DSU(A)
        for i, n in enumerate(A):
            primes = getPrimeFactors(n)
            for p in primes:
                if p in prime_to_idx:
                    dsu.union(i, prime_to_idx[p])
                prime_to_idx[p] = i
        return dsu.max_size

class UF:
    def __init__(self, n):
        self.parent = list(range(n))
        self.size = [1] * n
    
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        if px != py:
            if self.size[px] < self.size[py]:
                px, py = py, px
            self.parent[py] = px
            self.size[px] += self.size[py]

class Solution:
    def largestComponentSize(self, A: List[int]) -> int:
        prime = [0, 0] + [1] * (int(max(A) ** 0.5 + 1) - 2)
        for i in range(2, int(len(prime) ** 0.5) + 1):
            if prime[i]:
                prime[i * i::i] = [0] * ((len(prime) - 1) // i - i + 1)
        prime = [i for i, x in enumerate(prime) if x]
        
        factor = collections.defaultdict(list)
        for i, x in enumerate(A):
            for p in prime:
                if p * p > x:
                    break
                if x % p == 0:
                    factor[p].append(i)
                    while x % p == 0:
                        x //= p
            if x > 1:
                factor[x].append(i)
        
        uf = UF(len(A))
        for numbers in factor.values():
            for i, j in zip(numbers, numbers[1:]):
                uf.union(i, j)
        return max(uf.size)

class UnionFind(object):
    def uf(self, n):
        self.uf = [i for i in range(n)]
        self.size = [1] * n

    def find(self, x):
        while x != self.uf[x]:
            self.uf[x] = self.uf[self.uf[x]]
            x = self.uf[x]
        return self.uf[x]

    def union(self, x, y):
        x_root = self.find(x)
        y_root = self.find(y)
        if x_root == y_root:
            return
        self.uf[x_root] = y_root
        self.size[y_root] += self.size[x_root]
        self.size[x_root] = 0


class Solution:
    def largestComponentSize(self, A: List[int]) -> int:

        def primeFactors(n):
            out = set()
            while n % 2 == 0:
                out.add(2)
                n //= 2
            for i in range(3, int(math.sqrt(n)) + 1, 2):
                while n % i == 0:
                    out.add(i)
                    n //= i
            if n > 2:
                out.add(n)
            return out

        uf = UnionFind()
        uf.uf(len(A))

        primeToIndex = {}
        for i, a in enumerate(A):
            primes = primeFactors(a)
            for p in primes:
                if p in primeToIndex:
                    uf.union(i, primeToIndex[p])
                primeToIndex[p] = i
        return max(uf.size)