CodeEff/ECCO huggingface dataset:
# Original solution
class UnionFind:
    def __init__(self, size):
        self.data = [-1 for _ in range(size)]
    def find(self, x):
        if self.data[x] < 0:
            return x
        else:
            self.data[x] = self.find(self.data[x])
            return self.data[x]
    def union(self, x, y):
        x, y = self.find(x), self.find(y)
        if x != y:
            if self.data[y] < self.data[x]:
                x, y = y, x
            self.data[x] += self.data[y]
            self.data[y] = x
        return (x != y)
    def same(self, x, y):
        return (self.find(x) == self.find(y))
    def size(self, x):
        return -self.data[self.find(x)]


N, M = [int(i) for i in input().split()]

uf = UnionFind(N + 1)
for x, y, z in [[int(i) for i in input().split()] for _ in range(M)]:
    uf.union(x, y)

s = set()
for i in range(1, N + 1):
    s.add(uf.find(i))

print((len(s)))

# Optimized solution
class UnionFind:
    def __init__(self, size):
        self.data = [-1 for _ in range(size)]
    def find(self, x):
        if self.data[x] < 0:
            return x
        else:
            self.data[x] = self.find(self.data[x])
            return self.data[x]
    def union(self, x, y):
        x, y = self.find(x), self.find(y)
        if x != y:
            if self.data[y] < self.data[x]:
                x, y = y, x
            self.data[x] += self.data[y]
            self.data[y] = x
        return (x != y)
    def same(self, x, y):
        return (self.find(x) == self.find(y))
    def size(self, x):
        return -self.data[self.find(x)]


N, M, *XYZ = list(map(int, open(0).read().split()))

uf = UnionFind(N + 1)
for x, y, _ in zip(*[iter(XYZ)] * 3):
    uf.union(x, y)

print((len({uf.find(i + 1) for i in range(N)})))
# Original solution
class UFT(): #Union-find tree class
    def __init__(self, N): 
        self.tree = [int(i) for i in range(N)] 
        self.rank = [0 for i in range(N)]

    def find(self, a):
        if self.tree[a] == a: return a
        else:
            self.tree[a] = self.find(self.tree[a])
            return self.tree[a]

    def unite(self, a, b):
        a = self.find(a)
        b = self.find(b)
        if a == b: return
        if self.rank[a] < self.rank[b]: self.tree[a] = b
        else:
            self.tree[b] = a
            if self.rank[a] == self.rank[b]: self.rank[a] += 1

N, M = list(map(int, input().split()))
parent = UFT(N)
for i in range(M):
    x, y, z = list(map(int, input().split()))
    parent.unite(x-1, y-1)
for i in range(N):
    parent.find(i)

print((len(set(parent.tree))))

# Optimized solution
import sys

class UFT: #Union-find tree class
    def __init__(self, N): 
        self.tree = [int(i) for i in range(N)] 
        self.rank = [0 for i in range(N)]

    def find(self, a):
        if self.tree[a] == a: return a
        else:
            self.tree[a] = self.find(self.tree[a])
            return self.tree[a]

    def unite(self, a, b):
        a = self.find(a)
        b = self.find(b)
        if a == b: return
        if self.rank[a] < self.rank[b]: self.tree[a] = b
        else:
            self.tree[b] = a
            if self.rank[a] == self.rank[b]: self.rank[a] += 1

def solve():
    input = sys.stdin.readline
    N, M = list(map(int, input().split()))
    parent = UFT(N)
    for i in range(M):
        x, y, z = list(map(int, input().split()))
        parent.unite(x-1, y-1)
    for i in range(N):
        parent.find(i)

    print((len(set(parent.tree))))
    
    return 0

if __name__ == "__main__":
    solve()
# Original solution
import sys
input = sys.stdin.readline
 
n,m = list(map(int,input().split()))
 
#Union Find

#xの根を求める
def find(x):
    if par[x] < 0:
        return x
    else:
        par[x] = find(par[x])
        return par[x]
#xとyの属する集合の併合
def unite(x,y):
    x = find(x)
    y = find(y)

    if x == y:
        return False
    else:
        #sizeの大きいほうがx
        if par[x] > par[y]:
            x,y = y,x
        par[x] += par[y]
        par[y] = x
        return True

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

#xが属する集合の個数
def size(x):
    return -par[find(x)]

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

###具体例###
for _ in range(m):
    x, y, z = [int(x) for x in input().split()]
    unite(x - 1, y - 1)

A = set()

for i in range(n):
    A.add(find(i))

print((len(A)))



# Optimized solution
import sys
input = lambda : sys.stdin.readline().rstrip()

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

#Union Find

#xの根を求める
def find(x):
    if par[x] < 0:
        return x
    else:
        par[x] = find(par[x])
        return par[x]
#xとyの属する集合の併合
def unite(x,y):
    x = find(x)
    y = find(y)

    if x == y:
        return False
    else:
        #sizeの大きいほうがx
        if par[x] > par[y]:
            x,y = y,x
        par[x] += par[y]
        par[y] = x
        return True

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

#xが属する集合の個数
def size(x):
    return -par[find(x)]

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

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

ans = 0

for i in range(n):
    if find(i) == i:
        ans += 1

print(ans)
# Original solution
from collections import deque
N,M=list(map(int,input().split()))
even_list=[list(map(int,input().split())) for _ in range(M)]
#リストVのN番目には頂点Nがあり、そこには頂点Nとつながっている頂点が入っている。
    
#seen[i]は、頂点iを訪問済みの場合はTrue、未訪問の場合はFalse
seen=[False for i in range(N+1)]


count=0
graph=[[] for _ in range(N+1)]
for i in even_list:
    graph[i[0]].append(i[1])
    graph[i[1]].append(i[0])

def StackBFS(s):
    #graphのN番目には頂点Nがあり、そこには頂点Nとつながっている頂点が入っている。
    S=deque([s])
    C=set()
    
    while S:
        v=S.popleft()
        seen[v]=True #訪問済みの頂点をTrueにする
        if v not in C:
            C=C|{v}
            for i in graph[v]:
                S.append(i)

for i in range(1,N+1):
    if seen[i]==False:
        StackBFS(i)
        count+=1

print(count)

# Optimized solution
from collections import deque


N,M=list(map(int,input().split()))
graph=[[] for _ in range(N+1)]
for _ in range(M):
    a,b,c=list(map(int,input().split()))
    graph[a].append(b)
    graph[b].append(a)
    
#seen[i]は、頂点iを訪問済みの場合はTrue、未訪問の場合はFalse
seen=[False]*(N+1)


count=0

for i in range(1,N+1):
    if seen[i]==False:
        seen[i]=True
        S=deque([i])
        
        while S:
            v=S.popleft()
            #訪問済みの頂点をTrueにする
            for i in graph[v]:
                if seen[i]==False:
                    seen[i]=True
                    S.append(i)
        count+=1

print(count)
# Original solution
from functools import lru_cache
import sys
sys.setrecursionlimit(10**7)

n,m,*l=list(map(int,open(0).read().split()))
graph=[[]*n for _ in range(n)]
unvis=[True]*n

@lru_cache(maxsize=None)
def dfs(x):
	for y in graph[x]:
		if unvis[y]:
			unvis[y]=False
			dfs(y)
			
for i,j in zip(l[::3],l[1::3]):
	graph[i-1].append(j-1)
	graph[j-1].append(i-1)

ans=0
for x in range(n):
	if unvis[x]:
		unvis[x]=False
		dfs(x)
		ans+=1
print(ans)


# Optimized solution
import sys
sys.setrecursionlimit(200000)

n,m,*l=list(map(int,open(0).read().split()))
graph=[[]*n for _ in range(n)]
unvis=[True]*n

def dfs(x):
	for y in graph[x]:
		if unvis[y]:
			unvis[y]=False
			dfs(y)
			
for i,j in zip(l[::3],l[1::3]):
	graph[i-1].append(j-1)
	graph[j-1].append(i-1)

ans=0
for x in range(n):
	if unvis[x]:
		unvis[x]=False
		dfs(x)
		ans+=1
print(ans)
# Original solution
import collections

def main():
    n,m = list(map(int,input().split()))
    f = [False for _ in range(n)]
    a = [[] for _ in range(n)]
    res = 0

    for _ in range(m):
        x,y,z = list(map(int,input().split()))
        a[x-1].append(y-1)
        a[y-1].append(x-1)

    for i in range(n):
        if not f[i]:
            res += 1
            q=collections.deque()
            q.append(i)
            while q:
                t = q.pop()
                f[t] = True
                for g in a[t]:
                    if not f[g]:
                        q.append(g)
    print(res)
main()


# Optimized solution
import sys
sys.setrecursionlimit(10**7)
n,m = list(map(int,input().split()))
f = [False for _ in range(n)]
a = [[] for _ in range(n)]
res = 0

def dfs(k):
    f[k] = True
    for g in a[k]:
        if not f[g]:
            dfs(g)

for _ in range(m):
    x,y,z = list(map(int,input().split()))
    a[x-1].append(y-1)
    a[y-1].append(x-1)

for i in range(n):
    if not f[i]:
        res += 1
        dfs(i)
print(res)
# Original solution
import sys
sys.setrecursionlimit(10**8)
N, M = list(map(int, input().split()))
edge = [[] for _ in range(N)]
for i in range(M):
  a,b,c = list(map(int, input().split()))
  edge[a-1].append(b-1)
  edge[b-1].append(a-1)

def dfs(v):
  if len(edge[v])==0:
    return 0
  for u in edge[v]:
    if visited[u]==False:
      visited[u]=True
      dfs(u)
  return 0

ans = 0
visited = [False]*N
for i in range(N):
  if visited[i]==False:
    visited[i]=True
    dfs(i)
    ans += 1
print(ans)

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

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

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

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

    if x == y:
      return

    if self.parents[x] > self.parents[y]:
            x, y = y, x

    self.parents[x] += self.parents[y]
    self.parents[y] = x

  def roots(self):
    return [i for i, x in enumerate(self.parents) if x < 0]

uf = UnionFind(N)

for _ in range(M):
  x,y,z = list(map(int, input().split()))
  uf.union(x-1,y-1)
  
ans = len(uf.roots())
  
print(ans)
# Original solution
N, M = list(map(int, input().split()))
edge = [[] for _ in range(N)]
for i in range(M):
  a,b,c = list(map(int, input().split()))
  edge[a-1].append(b-1)
  edge[b-1].append(a-1)

from collections import deque

ans = 0
visited = [False]*N
d = deque()
for i in range(N):
  if visited[i]==False:
    visited[i]=True
    d.append(i)
    while len(d)>0:
      v = d.popleft()
      for w in edge[v]:
        if visited[w]==False:
          visited[w]=True
          d.append(w)
    ans += 1
print(ans)

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

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

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

    if x == y:
      return

    if self.parents[x] > self.parents[y]:
          x, y = y, x

    self.parents[x] += self.parents[y]
    self.parents[y] = x

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

  def roots(self):
    return [i for i, x in enumerate(self.parents) if x < 0]

  def num_roots(self):
    return len([i for i, x in enumerate(self.parents) if x < 0])

  def members(self, x):
    root = self.find(x)
    return [i for i in range(self.n) if self.find(i) == root]

  def num_members(self,x):
    return abs(self.parents[self.find(x)])

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

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

print((uf.num_roots()))
# Original solution
n, m = list(map(int, input().split()))

card = [[] for _ in range(n)]

for _ in range(m):
    x, y, _ = list(map(int, input().split()))
    card[x-1].append(y-1)
    card[y-1].append(x-1)

checked = [False] * n

count = 0
import queue
q = queue.Queue()
for i in range(n):
    if checked[i]:
        continue
    count += 1
    q.put(i)
    while not q.empty():
        j = q.get()
        checked[j] = True
        for k in card[j]:
            if not checked[k]:
                q.put(k)

print (count)


    



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

card = [[] for _ in range(n)]

for _ in range(m):
    x, y, _ = list(map(int, input().split()))
    card[x-1].append(y-1)
    card[y-1].append(x-1)

checked = [False] * n

count = 0
from collections import deque
for i in range(n):
    if checked[i]:
        continue
    count += 1
    q = deque([i])
    while q:
        j = q.popleft()
        checked[j] = True
        for k in card[j]:
            if not checked[k]:
                q.append(k)
print (count)
# Original solution
n, m = list(map(int, input().split()))

card = [[] for _ in range(n)]

for _ in range(m):
    x, y, _ = list(map(int, input().split()))
    card[x-1].append(y-1)
    card[y-1].append(x-1)

checked = [False] * n

count = 0
from collections import deque
for i in range(n):
    if checked[i]:
        continue
    count += 1
    q = deque([i])
    while q:
        j = q.popleft()
        checked[j] = True
        for k in card[j]:
            if not checked[k]:
                q.append(k)
print (count) 



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

card = [[] for _ in range(n)]

for _ in range(m):
    x, y, _ = list(map(int, input().split()))
    card[x-1].append(y-1)
    card[y-1].append(x-1)

checked = [False] * n

count = 0
for i in range(n):
    if checked[i]:
        continue
    count += 1
    q = [i]
    while q:
        j = q.pop()
        checked[j] = True
        for k in card[j]:
            if not checked[k]:
                q.append(k)
print (count)
# Original solution
import sys
sys.setrecursionlimit(10**6)

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

global clasta
clasta = [-1 for i in range(n)]
path = [[] for i in range(n)]
used = [0 for i in range(n)]
for _ in range(m):
    x,y,z = list(map(int,input().split()))
    path[x-1].append(y-1)
    path[y-1].append(x-1)

def dfs(now,color):
    for y in path[now]:
        if clasta[y] == -1:
            clasta[y] = color
            dfs(y,color)
            
ans = 0
for idx,i in enumerate(clasta):
    if i == -1:
        clasta[idx] = idx
        if path[idx]:
            dfs(idx,idx)
        ans += 1

print(ans)

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

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

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

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

        if x == y:
            return

        if self.parents[x] > self.parents[y]:
            x, y = y, x

        self.parents[x] += self.parents[y]
        self.parents[y] = x

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

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

    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]

    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

    def group_count(self):
        return len(self.roots())

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

    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())
        
        
n,m = list(map(int,input().split()))

uf = UnionFind(n)
for _ in range(m):
    x,y,z = list(map(int,input().split()))
    uf.union(x-1, y-1)
    
print((uf.group_count()))
# Original solution
import sys
sys.setrecursionlimit(10**5)
n, m = list(map(int, input().split()))
adjacent_list = [[] for i in range(n + 1)]
for i in range(m):
    x, y, z = list(map(int,input().split()))
    adjacent_list[x].append(y)
    adjacent_list[y].append(x)
##結局、グラフが何個あるか数える
finished = set()
ans = 0
def dfs(node):
    global finished
    finished.add(node)
    for i in adjacent_list[node]:
        if i not in finished:
            dfs(i)

while len(finished) != n:
    for i in range(1,n+1):
        if i not in finished:
            dfs(i)
            ans += 1
        
print(ans)




# Optimized solution
import sys
sys.setrecursionlimit(10**6)
n, m = list(map(int, input().split()))
adjacent_list = [[] for i in range(n + 1)]
for i in range(m):
    x, y, z = list(map(int,input().split()))
    adjacent_list[x].append(y)
    adjacent_list[y].append(x)
##結局、グラフが何個あるか数える
finished = set()
ans = 0
def dfs(node):
    global finished
    finished.add(node)
    for i in adjacent_list[node]:
        if i not in finished:
            dfs(i)

while len(finished) != n:
    for i in range(1,n+1):
        if i not in finished:
            dfs(i)
            ans += 1
print(ans)
# Original solution
import collections


class UnionFind:
    def __init__(self, max_size):
        self.parent = [i for i in range(max_size+1)]
        self.depth = [0 for _ in range(max_size+1)]
        self.cnt = [1 for i in range(max_size+1)]
    # 菲再起にしたい　Whileでスタックに突っこみながら見てスタックの中身全部に代入
    '''
    # 実はこっちのほうが速かったなんで？
    def find(self, x):
        t = x
        while t!=self.parent[t]:
            t = self.parent[t]
        self.parent[x]=t
        return t
    '''

    def find(self, x):
        de = collections.deque()
        t = x
        while t != self.parent[t]:
            de.append(t)
            t = self.parent[t]
        while de:
            tmp = de.pop()
            self.parent[tmp] = t
        return t

    def unite(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return
        elif self.depth[x] < self.depth[y]:
            self.parent[x] = y
            self.cnt[y] += self.cnt[x]
        else:
            self.parent[y] = x
            self.cnt[x] += self.cnt[y]
            if self.depth[x] == self.depth[y]:
                self.depth[x] += 1

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

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


n, m = list(map(int, input().split()))
utree = UnionFind(n+10)
for _ in range(m):
    x, y, z = list(map(int, input().split()))
    utree.unite(x, y)
s = {utree.find(i) for i in range(1, n+1)}
print((len(s)))


# Optimized solution
import collections
class UnionFind:
    def __init__(self, max_size):
        self.parent = [i for i in range(max_size+1)]
        self.depth = [0 for _ in range(max_size+1)]
        self.cnt = [1 for i in range(max_size+1)]
    def find(self, x):
        deque = collections.deque()
        t = x
        while t != self.parent[t]:
            deque.append(t)
            t = self.parent[t]
        while deque:
            tmp = deque.pop()
            self.parent[tmp] = t
        return t
    def unite(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return
        elif self.depth[x] < self.depth[y]:
            self.parent[x] = y
            self.cnt[y] += self.cnt[x]
        else:
            self.parent[y] = x
            self.cnt[x] += self.cnt[y]
            if self.depth[x] == self.depth[y]:
                self.depth[x] += 1
    def same(self, x, y):
        return self.find(x) == self.find(y)
    def size(self, x):
        return self.cnt[self.find(x)]
n, m = list(map(int, input().split()))
utree = UnionFind(n+10)
for _ in range(m):
    x, y, z = list(map(int, input().split()))
    utree.unite(x, y)
s = {utree.find(i) for i in range(1, n+1)}
print((len(s)))
# Original solution
import sys
from collections import deque
sys.setrecursionlimit(10**9)
input = sys.stdin.readline
n, m = list(map(int, input().split()))
memo = set(list(range(n)))
E = [[] for i in range(n)]
for i in range(m):
    x, y, z = list(map(int, input().split()))
    E[x-1].append(y-1)
    E[y-1].append(x-1)
def dfs(cur, pre):
    stack = deque([[cur, pre]])
    while stack:
        cur, pre = stack.pop()
        if pre != -1:
            memo.discard(cur)
        for e in E[cur]:
            if e != pre and e in memo:
                stack.append([e, cur])
ans = 0
while len(memo):
    cur = memo.pop()
    dfs(cur, -1)
    ans += 1
print(ans)


# Optimized solution
import sys
from collections import deque
sys.setrecursionlimit(10**9)
input = sys.stdin.readline
n, m = list(map(int, input().split()))
memo = set(list(range(n)))
E = [[] for i in range(n)]
for i in range(m):
    x, y, z = list(map(int, input().split()))
    E[x-1].append(y-1)
    E[y-1].append(x-1)
def dfs(cur, pre):
    stack = deque([[cur, pre]])
    while stack:
        cur, pre = stack.pop()
        memo.discard(cur)
        for e in E[cur]:
            if e != pre and e in memo:
                stack.append([e, cur])
ans = 0
for i in range(n):
    if i in memo:
        dfs(i, -1)
        ans += 1
print(ans)
# Original solution
import sys
from collections import deque
sys.setrecursionlimit(10**9)
input = sys.stdin.readline
n, m = list(map(int, input().split()))
memo = set(list(range(n)))
E = [[] for i in range(n)]
for i in range(m):
    x, y, z = list(map(int, input().split()))
    E[x-1].append(y-1)
    E[y-1].append(x-1)
def dfs(cur, pre):
    stack = deque([[cur, pre]])
    while stack:
        cur, pre = stack.pop()
        memo.discard(cur)
        for e in E[cur]:
            if e != pre and e in memo:
                stack.append([e, cur])
ans = 0
for i in range(n):
    if i in memo:
        dfs(i, -1)
        ans += 1
print(ans)


# Optimized solution
import sys
from collections import deque
sys.setrecursionlimit(10**9)
input = sys.stdin.readline
n, m = list(map(int, input().split()))
memo = [1 for _ in range(n)]
E = [[] for _ in range(n)]
for i in range(m):
    x, y, z = list(map(int, input().split()))
    E[x-1].append(y-1)
    E[y-1].append(x-1)
def dfs(cur, pre):
    stack = deque([[cur, pre]])
    while stack:
        cur, pre = stack.pop()
        memo[cur] = 0
        for e in E[cur]:
            if e != pre and memo[e]:
                stack.append([e, cur])
ans = 0
for i in range(n):
    if memo[i]:
        dfs(i, -1)
        ans += 1
print(ans)
# Original solution
def search(n):
    while A[n-1] != n:
        n = A[n-1]

    return n

N, M = list(map(int, input().split()))
A = [i for i in range(1, N+1)]
ans = 0

for i in range(M):
    X, Y, Z = list(map(int, input().split()))
    X_root, Y_root = search(X), search(Y)

    if X_root != Y_root:
        A[X_root-1] = Y_root
        ans += 1

print((N-ans))

# Optimized solution
def search(n):
    idx = n
    while A[n-1] != n:
        n = A[n-1]
    A[idx-1] = n

    return n

N, M = list(map(int, input().split()))
A = [i for i in range(1, N+1)]
ans = 0

for i in range(M):
    X, Y, Z = list(map(int, input().split()))
    X_root, Y_root = search(X), search(Y)

    if X_root != Y_root:
        A[X_root-1] = Y_root
        ans += 1

print((N-ans))
# Original solution
r=lambda x:x if u[x]<0else r(u[x])
n,m,*t=list(map(int,open(0).read().split()))
u=[-1]*-~n
for x,y in zip(t[::3],t[1::3]):
 x,y=sorted((r(x),r(y)))
 if x!=y:u[x]+=u[y];u[y]=x
print((sum(i<0for i in u)-1))

# Optimized solution
r=lambda x:x*(u[x]<0)or r(u[x])
n,m,*t=list(map(int,open(0).read().split()))
u=[-1]*-~n
for x,y in zip(t[::3],t[1::3]):
 x,y=sorted((r(x),r(y)))
 if x!=y:u[x]+=u[y];u[y]=x
print((sum(i<0for i in u)-1))