There are N cards placed face down in a row. On each card, an integer 1 or 2 is written.
Let A_i be the integer written on the i-th card.
Your objective is to guess A_1, A_2, ..., A_N correctly.
You know the following facts:
 - For each i = 1, 2, ..., M, the value A_{X_i} + A_{Y_i} + Z_i is an even number.
You are a magician and can use the following magic any number of times:
Magic: Choose one card and know the integer A_i written on it. The cost of using this magic is 1.
What is the minimum cost required to determine all of A_1, A_2, ..., A_N?
It is guaranteed that there is no contradiction in given input.

-----Constraints-----
 - All values in input are integers.
 - 2 \leq N \leq 10^5
 - 1 \leq M \leq 10^5
 - 1 \leq X_i < Y_i \leq N
 - 1 \leq Z_i \leq 100
 - The pairs (X_i, Y_i) are distinct.
 - There is no contradiction in input. (That is, there exist integers A_1, A_2, ..., A_N that satisfy the conditions.)

-----Input-----
Input is given from Standard Input in the following format:
N M
X_1 Y_1 Z_1
X_2 Y_2 Z_2
\vdots
X_M Y_M Z_M

-----Output-----
Print the minimum total cost required to determine all of A_1, A_2, ..., A_N.

-----Sample Input-----
3 1
1 2 1

-----Sample Output-----
2

You can determine all of A_1, A_2, A_3 by using the magic for the first and third cards.

Difficulty: interview

Starter code:

Solutions:
#!/usr/bin/env python3
import sys


def solve(N: int, M: int, X: "List[int]", Y: "List[int]", Z: "List[int]"):
    X = [x-1 for x in X]
    Y = [x-1 for x in Y]
    uf = UnionFind(N)
    for x, y in zip(X, Y):
        uf.union(x, y)
    return len(uf.roots())

# Generated by 1.1.7.1 https://github.com/kyuridenamida/atcoder-tools
def main():
    def iterate_tokens():
        for line in sys.stdin:
            for word in line.split():
                yield word
    tokens = iterate_tokens()
    N = int(next(tokens))  # type: int
    M = int(next(tokens))  # type: int
    X = [int()] * (M)  # type: "List[int]"
    Y = [int()] * (M)  # type: "List[int]"
    Z = [int()] * (M)  # type: "List[int]"
    for i in range(M):
        X[i] = int(next(tokens))
        Y[i] = int(next(tokens))
        Z[i] = int(next(tokens))
    print((solve(N, M, X, Y, Z)))

# https://note.nkmk.me/python-union-find/
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())

def test():
    import doctest
    doctest.testmod()

def __starting_point():
    #test()
    main()

__starting_point()

ma = lambda :map(int,input().split())
lma = lambda :list(map(int,input().split()))
tma = lambda :tuple(map(int,input().split()))
ni = lambda:int(input())
yn = lambda fl:print("Yes") if fl else print("No")
import collections
import math
import itertools
import heapq as hq
ceil = math.ceil
class unionfind():
    def __init__(self,n):
        self.n = n
        self.par = list(range(n))
        self.size = [1]*n
        self.rank = [0]*n

    def root(self,x):
        if self.par[x] == x:
            return x
        else:
            self.par[x] = self.root(self.par[x])
            return self.par[x]

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

    def unite(self,x,y):
        x = self.root(x)
        y = self.root(y)
        if x==y:return
        else:
            if self.rank[x] < self.rank[y]:
                 x,y = y,x
            if self.rank[x] == self.rank[y]:
                self.rank[x]+=1
            self.par[y] = x
            self.size[x] +=self.size[y]
    def get_size(self,x):
        x = self.root(x)
        return self.size[x]
    def parent_set(self):
        for x in range(self.n):
            self.root(x)
        s = set()
        for par in self.par:
            s.add(par)
        return s
n,m = ma()
uf = unionfind(n)
for i in range(m):
    x,y,z = ma()
    uf.unite(x-1,y-1)
s = uf.parent_set()
print(len(s))


class UnionFind():
    '''
    cited from https://note.nkmk.me/python-union-find/
    '''
    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 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())

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

u = UnionFind(N)
for i in range(M):
    x, y, z = list(map(int, input().split()))
    u.union(x-1,y-1)
    
print((u.group_count()))



import sys

input = sys.stdin.readline


class UnionFind:
    """Union Find class.

    "Path compression" and "Union by rank" are used.

    References:
        <https://en.wikipedia.org/wiki/Disjoint-set_data_structure>
    """

    def __init__(self, N):
        self.N = N
        self.__make_set()

    def __make_set(self):
        self._parent = list(range(self.N + 1))
        self._rank = [0] * (self.N + 1)
        self._size = [1] * (self.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):
        x_root = self.find(x)
        y_root = self.find(y)

        if x_root == y_root:
            return

        x_rank = self._rank[x_root]
        y_rank = self._rank[y_root]
        if x_rank > y_rank:
            self._parent[y_root] = x_root
            self._size[x_root] += self._size[y_root]
        elif x_rank < y_rank:
            self._parent[x_root] = y_root
            self._size[y_root] += self._size[x_root]
        else:
            self._parent[y_root] = x_root
            self._rank[x_root] += 1
            self._size[x_root] += self._size[y_root]

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

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


def main():
    N, M = list(map(int, input().split()))
    uf = UnionFind(N)
    for _ in range(M):
        X, Y, _ = list(map(int, input().split()))
        uf.union(X, Y)

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

    ans = len(s)
    print(ans)


def __starting_point():
    main()

__starting_point()

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

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

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

        if x == y:
            return

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

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

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

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

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

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

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

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

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

n,m=map(int,input().split())
a=[list(map(int,input().split())) for i in range(m)]
u=UnionFind(n)
for i in range(m):
    u.union(a[i][0]-1,a[i][1]-1)
print(u.group_count())

N, M = list(map(int,input().split()))
par = [i for i in range(N+1)]
size = [1 for _ in range(N+1)]

def find(x):
    if par[x] == x:
        return x
    else:
        par[x] = find(par[x])
        return par[x]

def unite(x,y):
    x = find(x)
    y = find(y)
    if x == y:
        return 1
    par[x] = y
    size[y] += size[x]
    size[x] = 0

for i in range(M):
    x, y, z= list(map(int,input().split()))
    unite(x,y)

Ans = 0
for j in size[1:]:
    if j != 0:
        Ans += 1
print(Ans)


import bisect, collections, copy, heapq, itertools, math, string, sys
input = lambda: sys.stdin.readline().rstrip() 
sys.setrecursionlimit(10**7)
INF = float('inf')
def I(): return int(input())
def F(): return float(input())
def SS(): return input()
def LI(): return [int(x) for x in input().split()]
def LI_(): return [int(x)-1 for x in input().split()]
def LF(): return [float(x) for x in input().split()]
def LSS(): return input().split()

def resolve():
    N, M = LI()
    G = collections.defaultdict(list)
    for _ in range(M):
        X, Y, _ = LI_()
        G[X].append(Y)
        G[Y].append(X)

    # A_XtoA_Yは片方が決まればもう片方も決まる よって連結成分数が答え
    visited = [False] * N
    def dfs(c):
        visited[c] = True
        for n in G[c]:
            if not visited[n]:
                dfs(n)

    ans = [0]
    for i in range(N):
        if not visited[i]:
            dfs(i)
            ans[0] += 1

    print((ans[0]))

def __starting_point():
    resolve()

__starting_point()

N, M = list(map(int,input().split()))
par = [i for i in range(N+1)]
size = [1 for _ in range(N+1)]

def find(x):
    if par[x] == x:
        return x
    else:
        par[x] = find(par[x])
        return par[x]

def unite(x,y):
    x = find(x)
    y = find(y)
    if x == y:
        return 0
    par[x] = y
    size[y] += size[x]
    size[x] = 0

for i in range(M):
    x, y, z= list(map(int,input().split()))
    unite(x,y)

Ans = 0
for j in size[1:]:
    if j != 0:
        Ans +=1
print(Ans)


N, M = map(int,input().split())
par = [i for i in range(N+1)]
size = [1 for _ in range(N+1)]

def find(x):
    if par[x] == x:
        return x
    else:
        par[x] = find(par[x])
        return par[x]

def unite(x,y):
    x = find(x)
    y = find(y)
    if x == y:
        return 0
    par[x] = y
    size[y] = size[x] + size[y]
    size[x] = 0
    
for i in range(M):
    x, y,  z= map(int,input().split())
    unite(x,y)
    
Ans =0
for j in size[1:]:
    if j != 0:
        Ans +=1
print(Ans)

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

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

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

        if x == y:
            return

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

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

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

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

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

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

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

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

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

N, M = map(int, input().split())
uf = UnionFind(N)
for _ in range(M):
    X, Y, Z = map(lambda x: int(x)-1, input().split())
    uf.union(X, Y)
print(len(uf.roots()))

N,M=list(map(int,input().split()))
root=[i for i in range(N)]
height=[0]*N
def find(a):
   f=a
   if a==root[a]:
      return a
   while a!=root[a]:
      a=root[a]
   root[f]=a
   return a
def union(a,b):
   A=find(a)
   B=find(b)
   if A==B:
      return
   if height[A]>height[B]:
      root[B]=root[A]
   else:
      root[A]=root[B]
      if height[A]==height[B]:
         height[B]+=1

for i in range(M):
   a,b,c=map(int,input().split())
   a-=1;b-=1
   union(a,b)
l=[0]*N
for j in range(N):
   l[find(j)]+=1
print(N-l.count(0))

def abc126_e():
    n, m = map(int, input().split())
    par = [x for x in range(n)]
    rank = [0]*n

    def find(x):
        if par[x] == x:
            return x
        else:
            par[x] = find(par[x])
            return par[x]

    def unite(x, y):
        x = find(x)
        y = find(y)
        if x == y: return
        if rank[x] < rank[y]:
            par[x] = y
        else:
            par[y] = x
            if rank[x] == rank[y]: rank[x] += 1

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

    for i in range(n):
        _ = find(i)

    ans = len(set(par))
    print(ans)

def __starting_point():
    abc126_e()
__starting_point()

#import sys
MOD = 10 ** 9 + 7
INFI = 10**10
#input = sys.stdin.readline
import math
from collections import deque
import itertools
import heapq
#import bisect
from fractions import Fraction
import copy
from functools import lru_cache
from collections import defaultdict
import pprint

#oo=list("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
# ko=list("abcdefghijklmnopqrstuvwxyz")

def sosuhante(n):
    for k in range(2, int(math.sqrt(n))+1):
        if n% k ==0:
            return False
    return True
def cmb(n, r):
    if n - r < r: r = n - r
    if r == 0: return 1
    if r == 1: return n

    numerator = [n - r + k + 1 for k in range(r)]
    denominator = [k + 1 for k in range(r)]

    for p in range(2,r+1):
        pivot = denominator[p - 1]
        if pivot > 1:
            offset = (n - r) % p
            for k in range(p-1,r,p):
                numerator[k - offset] /= pivot
                denominator[k] /= pivot

    result = 1
    for k in range(r):
        if numerator[k] > 1:
            result *= int(numerator[k])

    return result

def kingaku(a,b,n):
    keta=len(str(n))
    return a*n+b*keta

def my_index(l, x, default=False):
    if x in l:
        return l.index(x)
    else:
        return default

#    h,w,a,b = map(int, input().split())
#    c = [[0 for j in range(n)] for i in range(n)]

def ret(a):
    c=[None]*(len(a)-1)
    if len(a)==1:
        return a[0]
    elif len(a)==0:
        return 0
    for i in range(1,len(a)):
        c[i-1]=abs(a[i]-a[i-1])
    return ret(c)

def soinsubunkai(n):
    a = []
    i = 1
    while i*i <= n:
        if n % i == 0 and i!=1:
            a.append(i)
            n=n//i

        if n% i !=0 or i==1:
            i += 1
    nokori=[n]
    return a + nokori

def make_divisors(n):
    lower_divisors , upper_divisors = [], []
    i = 1
    while i*i <= n:
        if n % i == 0:
            lower_divisors.append(i)
            if i != n // i:
                upper_divisors.append(n//i)
        i += 1
    return lower_divisors + upper_divisors[::-1]

def main():
    n,m=map(int,input().split())
    graph=[[] for _ in range(n+1)]
    for i in range(m):
        a,b,c=map(int,input().split())
        graph[a].append(b)
        graph[b].append(a)
    stack=[]
    visited=[0 for _ in range(n+1)]

    zones=0
    count=0
    def DFS():
        c=1
        while True:
            if len(stack)==0:
                break
            s=stack.pop()
            if visited[s]==0:
                for i in graph[s]:
                    if visited[i]==0:
                        stack.append(i)

                visited[s]=1
                c+=1
            if len(stack)==0:
                break
        return c
    for i in range(1,n+1):
        if visited[i]==0:
            visited[i]=1
            for j in graph[i]:
                stack.append(j)
            if len(stack)>0:
                count+=DFS()
                zones += 1
        else:
            continue

#    print(n,count,zones)
    print(n-count+zones)





def __starting_point():

    main()
__starting_point()

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

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

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

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

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

N,M=map(int,input().split())
uf=UnionFind(N)
for i in range(M):
    x,y,z=map(int,input().split())
    uf.unite(x,y)
s=set()
ans=0
for i in range(1,N+1):
    if uf.find(i) not in s:
        s.add(uf.find(i))
        ans+=1
print(ans)

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

class UnionFind:
    def __init__(self, n):
        self.par = [i for i in range(n)]
        self.rank = [0] * (n)
        self.size = [1] * (n)
    # 検索
    def find(self, x):
        if self.par[x] == x:
            return x
        else:
            self.par[x] = self.find(self.par[x])
            return self.par[x]
    # 併合
    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return
        if self.rank[x] < self.rank[y]:
            self.par[x] = y
            self.size[y] += self.size[x]
        else:
            self.par[y] = x
            self.size[x] += self.size[y]
            if self.rank[x] == self.rank[y]:
                self.rank[x] += 1
    # 同じ集合に属するか判定
    def same(self, x, y):
        return self.find(x) == self.find(y)
    # すべての頂点に対して親を検索する
    def all_find(self):
        for n in range(len(self.par)):
            self.find(n)

uf = UnionFind(n)

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

root = set([])

for i in range(n):
    root.add(uf.find(i))

print(len(root))

# UnionFind: https://note.nkmk.me/python-union-find/
class UnionFind():
    def __init__(self, n):
        self.n = n
        self.root = [-1] * (n + 1)
        
    def find(self, x):
        if self.root[x] < 0:
            return x
        else:
            self.root[x] = self.find(self.root[x])
            return self.root[x]
    
    def unite(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return False
        if self.root[x] > self.root[y]:
            x, y = y, x
        self.root[x] += self.root[y]
        self.root[y] = x
        
    def is_same(self, x, y):
        return self.find(x) == self.find(y)
    
    def size(self, x):
        return -self.root[self.find(x)]

n, m = map(int, input().split())
cards = UnionFind(n)
for i in range(m):
    x, y, z = map(int, input().split())
    cards.unite(x, y)
print(len({i + 1 for i in range(n) if cards.root[i + 1] < 0}))

import heapq
import sys
sys.setrecursionlimit(10**8)
n, m = map(int, input().split())
c = [0] * n
g = [[] for i in range(n)]
revealed = [False] * n
rn = 0

for i in range(m):
    x, y, z = map(int, input().split())
    x-=1; y-=1
    c[x]+=1
    c[y]+=1
    g[y].append(x)
    g[x].append(y)

hq = [(c[i], i) for i in range(n)]
heapq.heapify(hq)

def dfs(src):
    nonlocal rn
    rn += 1
    revealed[src] = True
    for nxt in g[src]:
        if not revealed[nxt]:
            dfs(nxt)

ans = 0
while rn < n:
    _, now = heapq.heappop(hq)
    if revealed[now]: continue
    revealed[now] = True
    ans += 1
    dfs(now)
print(ans)

N, M = map(int,input().split())
par = [i for i in range(N+1)]
size = [1 for _ in range(N+1)]
def find(x):
    if par[x] == x:
        return x
    else:
        par[x] = find(par[x]) #経路圧縮
        return par[x]
def same(x,y):
    return find(x) == find(y)
def unite(x,y):
    x = find(x)
    y = find(y)
    if x == y:
        return 0
    par[x] = y
    size[y] = size[x] + size[y]
    size[x] = 0
for i in range(M):
    x, y,  z= map(int,input().split())
    unite(x,y)
Ans =0
for j in size[1:]:
    if j != 0:
        Ans +=1
print(Ans)

import sys;sys.setrecursionlimit(10**9)
class UnionFind:
  def __init__(self,n):
    self.n=[-1]*n
    self.r=[0]*n
    self.siz=n
  def find_root(self,x):
    if self.n[x]<0:
      return x
    else:
      self.n[x]=self.find_root(self.n[x])
      return self.n[x]
  def unite(self,x,y):
    x=self.find_root(x)
    y=self.find_root(y)
    if x==y:return
    elif self.r[x]>self.r[y]:
      self.n[x]+=self.n[y]
      self.n[y]=x
    else:
      self.n[y]+=self.n[x]
      self.n[x]=y
      if self.r[x]==self.r[y]:
        self.r[y]+=1
    self.siz-=1
  def root_same(self,x,y):
    return self.find_root(x)==self.find_root(y)
  def count(self,x):
    return -self.n[self.find_root(x)]
  def size(self):
    return self.siz

n,m=map(int,input().split())
uf=UnionFind(n)
for i in range(m):
  x,y,z=map(int,input().split())
  uf.unite(x-1,y-1)
print(uf.size())

class UnionFind(object):
    def __init__(self, size):
        self.parent = [i for i in range(size)]
        self.rank = [0]*size    
    def find(self, x):
        if self.parent[x] == x:
            return x
        self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def unite(self, x, y):
        x, y = self.find(x), self.find(y)
        if x == y:
            return
        if self.rank[x] < self.rank[y]:
            self.parent[x] = y
        else:
            self.parent[y] = x
            if self.rank[x] == self.rank[y]:
                self.rank[x] += 1
    
    def same(self, x, y):
        return self.find(x) == self.find(y)
N,M = map(int,input().split())
uf = UnionFind(N)
for _ in range(M):
    x,y,z = map(int,input().split())
    uf.unite(x-1,y-1)
for i in range(N):
    uf.find(i-1)
s = set(uf.parent)
print(len(s))

n,m=map(int,input().split())
xy=[[] for _ in range(n+1)]
for _ in range(m):
    x,y,z=map(int,input().split())
    xy[x].append(y)
    xy[y].append(x)

from collections import deque

visited=[0]*(n+1)
count=0

for i in range(1,n+1):
    if visited[i]==0:
        stack=deque()
        stack.append(i)
        visited[i]+=1
        while stack:
            a=stack.pop()
            for j in xy[a]:
                if visited[j]==0:
                    visited[j]+=1
                    stack.append(j)
        count+=1
print(count)

def find(x): #要素がどの集合か判断
    if par[x] < 0:
        return x
    else:
        par[x] = find(par[x])
        return par[x]

def unite(x,y): #集合に結合
    x = find(x)
    y = find(y)
    if x == y: return False
    if par[x] > par[y]: x,y = y,x
    par[x] += par[y]
    par[y] = x
    return True

import bisect
n, m = map(int, input().split())
par = [-1]*n

for _ in range(m):
    x, y, z = map(int, input().split())
    unite(x-1, y-1)
par.sort()
print(bisect.bisect_left(par, 0))

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# 問題：https://atcoder.jp/contests/abc126/tasks/abc126_e

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

class Graph():

    def __init__(self):
        self.adjacency_dict = {}
    
    def add_vertex(self, v):
        self.adjacency_dict[v] = []

    def add_edge(self, v1, v2):
        self.adjacency_dict[v1].append(v2)
        self.adjacency_dict[v2].append(v1)

    def remove_edge(self, v1, v2):
        self.adjacency_dict[v1].remove(v2)
        self.adjacency_dict[v2].remove(v1)

    def remove_vertex(self,v):
        while self.adjacency_dict[v] != []:
            adjacency_vertex = self.adjacency_dict[v][-1]
            self.remove_edge(v, adjacency_vertex)
        del adjacency_vertex[v]

    def get_vertexes(self):
        return list(self.adjacency_dict.keys())

    def get_edges(self, v):
        return self.adjacency_dict[v]

    def print_graph(self):
        print((self.adjacency_dict))


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

g = Graph()
for i in range(n):
    g.add_vertex(i)
for i in range(m):
    g.add_edge(xyz[i][0]-1, xyz[i][1]-1)

res = 0
reached_nodes = [0 for _ in range(n)]
for i in g.get_vertexes():
    if reached_nodes[i] == 1:
        continue
    res += 1
    reached_nodes[i] = 1
    q = [i]
    while len(q) > 0:
        u = q.pop()
        for v in g.get_edges(u):
            if reached_nodes[v] == 1:
                continue
            q.append(v)
            reached_nodes[v] = 1

print(res)


N, M = map(int, input().split())
G = [[] for _ in range(N)]

for i in range(M):
    x, y, z = map(int, input().split())
    G[x-1].append(y-1)
    G[y-1].append(x-1)

lst = []
visited = [0]*N
for i in range(N):
    if visited[i] == 1:continue
    temp = [i]
    lst1 = [i]
    visited[i] = 1
    while temp:
        p = temp.pop()
        for q in G[p]:
            if visited[q] == 0:
                visited[q] = 1
                lst1.append(q)
                temp.append(q)
    if lst1 != []:lst.append(lst1)
    
print(len(lst))

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

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

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

        if x == y:
            return

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

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

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

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

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

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

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

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

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

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

uf = uf = UnionFind(n)

for x, y, z in XYZ:
  x -= 1
  y -= 1
  uf.union(x, y)
  
print(uf.group_count())

a = [int(s) for s in input().split()]
g = {i: [] for i in range(1, a[0] + 1)}

for i in range(a[1]):
    c = [int(s) for s in input().split()]
    g[c[0]].append(c[1])
    g[c[1]].append(c[0])

j = 0
d = {i: False for i in range(1, a[0] + 1)}

for i in range(1, a[0] + 1):
    if d[i] == False:
        j += 1 
        d[i] = True
        if g[i] != []:
            Q = [i]
            while(Q != []):
                r = Q.pop(0)
                if g[r] != []:
                    for m in g[r]:
                        if d[m] == False:
                            d[m] = True
                            Q.append(m)
print(j)

import sys
input = sys.stdin.readline
from collections import Counter


def read():
    N, M = list(map(int, input().strip().split()))
    XYZ = []
    for i in range(M):
        x, y, z = list(map(int, input().strip().split()))
        XYZ.append((x, y, z))
    return N, M, XYZ


class UnionFind():
    """Union-Find木の実装
    """

    def __init__(self, n):
        self.n = n
        self.parent = [x for x in range(n)]

    def find(self, x):
        """要素xが所属するグループを返す
        """
        if self.parent[x] == x:
            return x
        else:
            self.parent[x] = self.find(self.parent[x])
            return self.parent[x]

    def union(self, x, y):
        """要素x, yがそれぞれ所属するグループを併合する
        """
        x = self.find(x)
        y = self.find(y)
        if x > y:
            x, y = y, x
        self.parent[y] = x

    def parents(self):
        return [self.find(x) for x in range(self.n)]


def solve(N, M, XYZ):
    uf = UnionFind(N)
    for x, y, z in XYZ:
        uf.union(x-1, y-1)
    C = Counter(uf.parents())
    return len(C)


def __starting_point():
    inputs = read()
    print((solve(*inputs)))

__starting_point()

from math import ceil,floor,factorial,gcd,sqrt,log2,cos,sin,tan,acos,asin,atan,degrees,radians,pi,inf
from itertools import accumulate,groupby,permutations,combinations,product,combinations_with_replacement
from collections import deque,defaultdict,Counter
from bisect import bisect_left,bisect_right
from operator import itemgetter
from heapq import heapify,heappop,heappush
from queue import Queue,LifoQueue,PriorityQueue
from copy import deepcopy
from time import time
from functools import reduce, lru_cache
import string
import sys
sys.setrecursionlimit(10 ** 7)
def input() : return sys.stdin.readline().strip()
def INT()   : return int(input())
def MAP()   : return map(int,input().split())
def MAP1()  : return map(lambda x:int(x)-1,input().split())
def LIST()  : return list(MAP())
def LIST1() : return list(MAP1())

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

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

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

        if x == y:
            return

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

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

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

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

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

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

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

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

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

n, m = MAP()
uf = UnionFind(n) # 初期化

for i in range(m):
    x, y, z = MAP1()
    uf.union(x, y) # グループを併合

print(uf.group_count())

# -*- coding: utf-8 -*-
import sys 
sys.setrecursionlimit(10**6)
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines
#Union Find
def find(x):
    if par[x] < 0:
        return x
    else:
        par[x] = find(par[x])
        return find(par[x])

def union(x,y):
    x = find(x)
    y = find(y)
    if x==y:
        return False
    else:
        if par[x] > par[y]:
            x,y = y,x
        par[x] += par[y]
        par[y] = x
        return True

def same(x,y):
    return find(x) == find(y)        
    
N,M = map(int,readline().split())
par = [-1]*(N+1)
for i in range(M):
    x,y,z = map(int,readline().split())
    union(x,y)
print(sum(1 for i in par[1:] if i < 0))

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

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

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

        if x == y:
            return

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

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

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

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

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

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

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

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

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

N, M = map(int, input().split())
uf = UnionFind(N)
for _ in range(M):
    X, Y, Z = map(lambda x: int(x)-1, input().split())
    uf.union(X, Y)
ans = [uf.find(x) for x in uf.roots()]
print(len(set(ans)))

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

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

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

        if x == y:
            return

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

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

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

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

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

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

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

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

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

uf = UnionFind(N+1)

for s in range (M):
  X,Y,Z = map(int,input().split())
  uf.union(X,Y)

print(uf.group_count() -1)

import sys
import re
import math
import collections
import bisect
import itertools
import fractions
import functools
import copy
import heapq
import decimal
import statistics
import queue

# import numpy as np

sys.setrecursionlimit(10 ** 9)
INF = 10 ** 16
MOD = 10 ** 9 + 7
# MOD = 998244353

ni = lambda: int(sys.stdin.readline())
ns = lambda: list(map(int, sys.stdin.readline().split()))
na = lambda: list(map(int, sys.stdin.readline().split()))
na1 = lambda: list([int(x) - 1 for x in sys.stdin.readline().split()])


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

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

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

        if x == y:
            return

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

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

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

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

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

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

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

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

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


def main():
    n, m = ns()
    uf = UnionFind(n)

    for _ in range(m):
        x, y, z = ns()
        uf.union(x - 1, y - 1)

    ans = uf.group_count()
    print(ans)


def __starting_point():
    main()

__starting_point()

# E - 1 or 2
from typing import List


def main():
    def dfs(source: int) -> None:
        stack = [source]
        is_visited[source] = True
        while stack:
            u = stack.pop()
            for v in graph[u]:
                if is_visited[v]:
                    continue
                is_visited[v] = True
                stack.append(v)

    N, M, *X = list(map(int, open(0).read().split()))
    graph: List[List[int]] = [[] for _ in range(N + 1)]
    for x, y, _ in zip(*[iter(X)] * 3):
        graph[x].append(y), graph[y].append(x)

    is_visited = [False] * (N + 1)
    res = 0
    for i in range(1, N + 1):
        if is_visited[i]:
            continue
        res += 1
        dfs(i)
    print(res)


def __starting_point():
    main()

__starting_point()

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


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

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

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

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

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

    def num_union(self):
        return self.u


u = UnionFind(N)
for x, y, z in zip(*[iter(X)]*3):
    u.unite(x-1, y-1)
print((u.num_union()))


n,m=map(int,input().split())
class UnionFind:
    #def   -> foo=UnionFind(n,1)  <- 1-based index, default is 0
    #method -> foo.hoge(huga)
    __slots__ = ["_size", "_first_idx", "_parents"]
    def __init__(self, size: int, first_index: int = 0) -> None:
        self._size = size
        self._first_idx = first_index
        self._parents = [-1] * (size + first_index)
    def find(self, x: int) -> int:
        if self._parents[x] < 0:
            return x
        self._parents[x] = self.find(self._parents[x])
        return self._parents[x]
    def same(self, x: int, y: int) -> bool:
        return self.find(x) == self.find(y)
    def unite(self, x: int, y: int) -> bool:
        x, y = self.find(x), self.find(y)
        if x == y:
            return False
        if self._parents[x] > self._parents[y]:
            x, y = y, x
        self._parents[x] += self._parents[y]
        self._parents[y] = x
        return True
    def size(self, x: int) -> int:
        return -self._parents[self.find(x)]
    def group_count(self) ->int:
        return sum([1 for i in  self._parents if i<0])-self._first_idx
    def connected(self) ->bool:
        return self._parents[self.find(self._first_idx)]==-self._size

uf=UnionFind(n,1)
for i in range(m):
    x,y,z=map(int,input().split())
    uf.unite(x,y)
print(uf.group_count())

import sys
sys.setrecursionlimit(10 ** 5 + 10)
def input(): return sys.stdin.readline().strip()

def resolve():
    from scipy.sparse.csgraph import connected_components  # https://note.nkmk.me/python-scipy-connected-components/
    from scipy.sparse import csr_matrix
    
    N, M = map(int, input().split())  # 頂点数、辺数
    A, B, C = [0] * M, [0] * M, [1] * M  # A[i]からB[i]へコストC[i]の有向辺。
    # ただし、connected_components()では有向グラフも無向グラフとして扱われる
    for i in range(M):
        A[i], B[i] ,_= map(int, input().split())
        A[i] -= 1  # indexを調整
        B[i] -= 1
    
    csr = csr_matrix((C, (A, B)), shape=(N, N))
    # nは連結成分の個数。labelは各頂点が属する連結成分のラベル
    n, labels = connected_components(csr)
    print(n)

    
resolve()

# https://atcoder.jp/contests/abc126/tasks/abc126_e

class UnionFind():
    # https://www.slideshare.net/chokudai/union-find-49066733
    # 作りたい要素数nで初期化
    # 使用するインスタンス変数の初期化
    def __init__(self, n):
        self.n = n
        # root[x]<0ならそのノードが根かつその値が木の要素数
        # rootノードでその木の要素数を記録する
        # root[x]>=0の場合は、特に直接的な意味を持たない気がする。計算に寄与するので意味はあるのだろうが。
        self.root = [-1]*(n+1)
        # 木をくっつける時にアンバランスにならないように調整する
        # 無結合の時はRank=0,結合して1つ木が深くなると根がRank+=1
        self.rnk = [0]*(n+1)

    # ノードxのrootノードを見つける
    #
    def Find_Root(self, x):
        if(self.root[x] < 0):
            return x
        else:
            # ここで代入しておくことで、後の繰り返しを避ける
            self.root[x] = self.Find_Root(self.root[x])
            return self.root[x]

    # 木の併合、入力は併合したい各ノード
    def Unite(self, x, y):
        # 入力ノードのrootノードを見つける
        x = self.Find_Root(x)
        y = self.Find_Root(y)
        # すでに同じ木に属していた場合
        if(x == y):
            return
        # 違う木に属していた場合rnkを見てくっつける方を決める
        # (1)xのランクの方が大きい(位置が深い)場合
        elif(self.rnk[x] > self.rnk[y]):
            self.root[x] += self.root[y]
            self.root[y] = x

        # (2)yのランクの方が大きい(位置が深い)場合 or 等しい場合
        # また等しい場合、引数の2つめのyの方のランクを1つ増やす
        else:
            self.root[y] += self.root[x]
            self.root[x] = y
            # rnkが同じ（深さに差がない場合）は1増やす
            if(self.rnk[x] == self.rnk[y]):
                self.rnk[y] += 1

    # xとyが同じグループに属するか判断
    # Return: True or False
    def isSameGroup(self, x, y):
        return self.Find_Root(x) == self.Find_Root(y)

    # ノードxが属する木のサイズを返す
    def Count(self, x):
        return -self.root[self.Find_Root(x)]
    
#######################################################
N,M=map(int,input().split())
UN=UnionFind(N)
for _ in range(M):
    s,t,u = map(int,input().split())
    UN.Unite(s,t)
    
#print(UN.root)
ans=0
for i in UN.root:
    if i<0:
        ans +=1
print(ans-1)

from collections import deque


N,M=list(map(int,input().split()))
graph=[[] for _ in range(N+1)]
for _ in range(M):
    a,b,c=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)

N, M = 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 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())

uf = UnionFind(N)
for _ in range(M):
    x, y, z = map(int, input().split())
    uf.union(x-1, y-1)

print(len(uf.roots()))

#!/usr/bin/env python3
from collections import deque, Counter
from heapq import heappop, heappush
from bisect import bisect_right

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

    def find(self, x):
        if self.parents[x] == x:
            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:
            if self.size[x] < self.size[y]:
                x,y = y,x
            self.parents[y] = x
            self.size[x] += self.size[y]

def main():
    N, M = list(map(int, input().split()))
    uf = UnionFind(N)
    for _ in range(M):
        X, Y, Z = [int(x)-1 for x in input().split()]
        uf.union(X, Y)
    # print(len(set(uf.parents)))
    ans = [uf.find(x) for x in uf.parents]
    print((len(set(ans))))

def __starting_point():
    main()

__starting_point()

import sys,math,collections,itertools
input = sys.stdin.readline

N,M=list(map(int,input().split()))
road = [[] for _ in range(N+1)]

for _ in range(M):
    x,y,_ = list(map(int,input().split()))
    road[x].append(y)
    road[y].append(x)

no_visit = set(list(range(1,N+1)))
q = collections.deque([])
cnt = 0
while no_visit:
    q.append(no_visit.pop())
    cnt += 1
    while q:
        now = q.popleft()
        for nxt in road[now]:
            if nxt in no_visit:
                q.append(nxt)
                no_visit.discard(nxt)
print(cnt)
                



class Unionfind():  # 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]


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

uf = Unionfind(n)
for x, y, z in xyz:
    uf.union(x - 1, y - 1)
print((len(uf.roots())))


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

from collections import deque

visited=[0]*(n+1)
count=0

for i in range(1,n+1):
    if visited[i]==0:
        stack=deque()
        stack.append(i)
        visited[i]+=1
        while stack:
            a=stack.pop()
            for j in xy[a]:
                if visited[j]==0:
                    visited[j]+=1
                    stack.append(j)
        count+=1
print(count)


class UnionFind:
    def __init__(self, n):
        self.p = [i for i in range(n)]
        self.components = n

    def root(self, x):
        if self.p[x] == x:
            return x
        else:
            self.p[x] = self.root(self.p[x])
            return self.p[x]
    
    def unite(self, x, y):
        x, y = self.root(x), self.root(y)
        if x != y:
            self.p[x] = y
            self.components -= 1
    
    def same(self, x,y):
        return (self.root(x) == self.root(y))
N, M = map(int,input().split())

UF = UnionFind(N)

for _ in range(M):
    X, Y, Z = map(int,input().split())
    X, Y = X-1, Y-1
    UF.unite(X,Y)

print(UF.components)

#    Copyright 2016-2019 NetworkX developers.
#    Copyright (C) 2004-2019 by
#    Aric Hagberg <hagberg@lanl.gov>
#    Dan Schult <dschult@colgate.edu>
#    Pieter Swart <swart@lanl.gov>
#    All rights reserved.
#    BSD license.
"""
Union-find data structure.
"""

from networkx.utils import groups


class UnionFind:
    """Union-find data structure.

    Each unionFind instance X maintains a family of disjoint sets of
    hashable objects, supporting the following two methods:

    - X[item] returns a name for the set containing the given item.
      Each set is named by an arbitrarily-chosen one of its members; as
      long as the set remains unchanged it will keep the same name. If
      the item is not yet part of a set in X, a new singleton set is
      created for it.

    - X.union(item1, item2, ...) merges the sets containing each item
      into a single larger set.  If any item is not yet part of a set
      in X, it is added to X as one of the members of the merged set.

      Union-find data structure. Based on Josiah Carlson's code,
      http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/215912
      with significant additional changes by D. Eppstein.
      http://www.ics.uci.edu/~eppstein/PADS/UnionFind.py

    """

    def __init__(self, elements=None):
        """Create a new empty union-find structure.

        If *elements* is an iterable, this structure will be initialized
        with the discrete partition on the given set of elements.

        """
        if elements is None:
            elements = ()
        self.parents = {}
        self.weights = {}
        for x in elements:
            self.weights[x] = 1
            self.parents[x] = x

    def __getitem__(self, object):
        """Find and return the name of the set containing the object."""

        # check for previously unknown object
        if object not in self.parents:
            self.parents[object] = object
            self.weights[object] = 1
            return object

        # find path of objects leading to the root
        path = [object]
        root = self.parents[object]
        while root != path[-1]:
            path.append(root)
            root = self.parents[root]

        # compress the path and return
        for ancestor in path:
            self.parents[ancestor] = root
        return root

    def __iter__(self):
        """Iterate through all items ever found or unioned by this structure.

        """
        return iter(self.parents)

    def to_sets(self):
        """Iterates over the sets stored in this structure.

        For example::

            >>> partition = UnionFind('xyz')
            >>> sorted(map(sorted, partition.to_sets()))
            [['x'], ['y'], ['z']]
            >>> partition.union('x', 'y')
            >>> sorted(map(sorted, partition.to_sets()))
            [['x', 'y'], ['z']]

        """
        # Ensure fully pruned paths
        for x in list(self.parents.keys()):
            _ = self[x]  # Evaluated for side-effect only

        # TODO In Python 3.3+, this should be `yield from ...`.
        for block in list(groups(self.parents).values()):
            yield block

    def union(self, *objects):
        """Find the sets containing the objects and merge them all."""
        roots = [self[x] for x in objects]
        # Find the heaviest root according to its weight.
        heaviest = max(roots, key=lambda r: self.weights[r])
        for r in roots:
            if r != heaviest:
                self.weights[heaviest] += self.weights[r]
                self.parents[r] = heaviest


def main():
    N, M = list(map(int, input().split()))
    XYZ = [list(map(int, input().split())) for _ in range(M)]

    u = UnionFind(list(range(1, N + 1)))

    for x, y, z in XYZ:
        u.union(x, y)

    print((len(list(u.to_sets()))))


main()


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

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

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

        if x == y:
            return

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

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

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

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

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

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

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

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

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


N, M = map(int, input().split())
uf = UnionFind(N)

for _ in range(M):
  X, Y, Z = map(int, input().split())
  uf.union(X-1, Y-1)

print(uf.group_count())

import sys
import math
import itertools
import bisect
from copy import copy
from collections import deque,Counter
from decimal import Decimal
def s(): return input()
def i(): return int(input())
def S(): return input().split()
def I(): return list(map(int,input().split()))
def L(): return list(input().split())
def l(): return list(map(int,input().split()))
def lcm(a,b): return a*b//math.gcd(a,b)
sys.setrecursionlimit(10 ** 9)
INF = 10**9
mod = 10**9+7

N,M = I()
links = [[] for _ in range(N)]
for i in range(M):
    x,y,z = I()
    links[x-1].append(y-1)
    links[y-1].append(x-1)
ans = 0
visited = [0]*N
def dfs(n):
    if visited[n]:
        return
    visited[n] = 1
    for l in links[n]:
        dfs(l)
for i in range(N):
    if not visited[i]:
        dfs(i)
        ans += 1
print(ans)


N, M = list(map(int,input().split()))
par = [i for i in range(N+1)]
size = [1 for _ in range(N+1)]

def find(x):
    if par[x] == x:
        return x
    else:
        par[x] = find(par[x])
        return par[x]

def unite(x,y):
    x = find(x)
    y = find(y)
    if x == y:
        return 0
    par[x] = y
    size[y] += size[x]
    size[x] = 0

for i in range(M):
    x, y, z= list(map(int,input().split()))
    unite(x,y)

Ans = 0
for j in size[1:]:
    if j != 0:
        Ans += 1
print(Ans)


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())
      
(n, m), *q = [list(map(int, o.split())) for o in open(0)]
UF = UnionFind(n)
for x, y, _ in q:
    UF.union(x - 1, y - 1)
print(UF.group_count())

import sys
sys.setrecursionlimit(10**6)
n, m = map(int, input().split())
xy = []
for _ in range(m):
    x, y, _ = map(int, input().split())
    xy.append((x-1, y-1))

class UnionFind():
    def __init__(self, n):
        self.li = list(range(n))
    def root(self, x):
        if self.li[x]==x:
            return x
        self.li[x] = self.root(self.li[x])
        return self.li[x]
    def unite(self, x, y):
        rx = self.root(x)
        ry = self.root(y)
        if rx==ry:
            return
        self.li[ry] = rx
    def same(self, x, y):
        return self.root(x)==self.root(y)

uf = UnionFind(n)
for x, y in xy:
    uf.unite(x, y)
for i in range(n):
    uf.root(i)
print(len(set(uf.li)))

import sys
sys.setrecursionlimit(10**5+1)

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

edge = [[] for i in range(N)]
for i in range(M):
    x, y, _ = map(int, input().split())
    edge[x-1].append(y-1)
    edge[y-1].append(x-1)

visited = [False] * N

ans = 0
def dfs(x):
    nonlocal ans
    if not visited[x]:
        ans += 1
    visited[x] = True

    for x_next in edge[x]:
        if visited[x_next]:
           continue 
        visited[x_next] = True
        dfs(x_next)

for i in range(N):
    dfs(i)

print(ans)

import networkx as X
n,m=map(int,input().split())
g=X.Graph()
for i in range(n):g.add_node(i+1)
for i in range(m):x,y,z=map(int,input().split());g.add_edge(x,y)
print(X.number_connected_components(g))

import sys, re
from collections import deque, defaultdict, Counter
from math import ceil, sqrt, hypot, factorial, pi, sin, cos, radians, gcd
from itertools import accumulate, permutations, combinations, product, groupby, combinations_with_replacement
from operator import itemgetter, mul
from copy import deepcopy
from string import ascii_lowercase, ascii_uppercase, digits
from bisect import bisect, bisect_left
from heapq import heappush, heappop
from functools import reduce
import networkx as nx
from networkx.utils import union_find
def input(): return sys.stdin.readline().strip()
def INT(): return int(input())
def MAP(): return list(map(int, input().split()))
def LIST(): return list(map(int, input().split()))
def ZIP(n): return list(zip(*(MAP() for _ in range(n))))
sys.setrecursionlimit(10 ** 9)
INF = float('inf')
mod = 10 ** 9 + 7

N, M = MAP()
XYZ = [LIST() for _ in range(M)]

uf = union_find.UnionFind(list(range(1, N+1)))

for X, Y, Z in XYZ:
	uf.union(X, Y)

print((len(list(uf.to_sets()))))


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

parent = [i + 1 for i in range(n)]
rank = [0 for i in range(n)]

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

def unite(x, y):
    x = find(x)
    y = find(y)
    if x == y:
        return
    if rank[x - 1] < rank[y - 1]:
        parent[x - 1] = y
    else:
        parent[y - 1] = x
        if rank[x - 1] == rank[y - 1]:
            rank[x - 1] += 1

for i in range(m):
    x, y, z = map(int, input().split())
    unite(x, y)
ans = n
for i in range(n):
    if find(i + 1) != i + 1:
        ans -= 1
print(ans)

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

import networkx as nx

G=nx.Graph()

for i in range (1, N+1):
	G.add_node(i)

for i in range (0, M):
	A, B, C = map(int, input().split())
	G.add_edge(A,B)

print(nx.number_connected_components(G))

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 group_count(self):
        return len(self.roots())

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

uf = UnionFind(N)
for i in range(M):
    x,y,z = list(map(int, input().split()))
    uf.union(x-1,y-1)

print((uf.group_count()))




class UnionFind:
    def __init__(self,N):
        self.root = list(range(N))
        self.size = [1] * (N)
        
    def find_root(self,x):
        root = self.root
        while root[x] != x:
            root[x] = root[root[x]]
            x = root[x]
        return x
    
    def merge(self,x,y):
        x = self.find_root(x)
        y = self.find_root(y)
        if x == y:
            return
        sx,sy = self.size[x],self.size[y]
        if sx < sy:
            self.root[x] = y
            self.size[y] += sx
        else:
            self.root[y] = x
            self.size[x] += sy


n, m = map(int, input().split())
xyz = []
for i in range(m):
    xyz.append(list(map(int,input().split())))
    

uf = UnionFind(n)

answer = []
find_root = uf.find_root
merge = uf.merge
for i in range(m):
    x, y, z = xyz[i][0]-1, xyz[i][1]-1, xyz[i][2]
    merge(x,y)
s = set([])
for i in range(n):
    s.add(uf.find_root(i))
print(len(s))

import sys
sys.setrecursionlimit(10**9)

N, M = list(map(int, input().split()))
paths = [[] for _ in range(N)]

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

visited = [False] * N

def dfs(node, prev):
    if visited[node]:
        return
    visited[node] = True
    for n in paths[node]:
        if n != prev:
            dfs(n, node)
count = 0
for i in range(N):
    if visited[i] == False:
        count += 1
        dfs(i,-1)

print(count)


class UnionFind():
    def __init__(self, n):
        # 正==子: 根の頂点番号 / 負==根: 連結頂点数
        self.n = n
        self.parents = [-1] * n
 
    def find(self, x):
        #要素xが属するグループの根を返す
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]
 
    def union(self, x, y):
        #要素xが属するグループと要素yが属するグループとを併合する
        x = self.find(x)
        y = self.find(y)
 
        if x == y:
            return
 
        if self.parents[x] > self.parents[y]:
            x, y = y, x
 
        self.parents[x] += self.parents[y]
        self.parents[y] = x
 
    def size(self, x):
        # 要素xが属するグループのサイズ（要素数）を返す
        return -self.parents[self.find(x)]
 
    def same(self, x, y):
        # 要素x, yが同じグループに属するかどうかを返す
        return self.find(x) == self.find(y)
 
    def members(self, x):
        # 要素xが属するグループに属する要素をリストで返す
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]
 
    def roots(self):
        # すべての根の要素をリストで返す
        return [i for i, x in enumerate(self.parents) if x < 0]
 
    def group_count(self):
        # グループの数を返す
        return len(self.roots())
 
    def all_group_members(self):
        # {ルート要素: [そのグループに含まれる要素のリスト], ...}の辞書を返す
        return {r: self.members(r) for r in self.roots()}
 
    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())

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

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

ans = u.group_count()
print(ans)

import sys
from collections import defaultdict
readline = sys.stdin.buffer.readline
# sys.setrecursionlimit(10**8)


def geta(fn=lambda s: s.decode()):
    return list(map(fn, readline().split()))


def gete(fn=lambda s: s.decode()):
    return fn(readline().rstrip())


class UnionFind:

    def __init__(self, N: int):
        # d[i] = <parent id> if i is a child,
        #       - <size of the group> if i is a root
        self.d = [-1 for _ in range(N)]

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

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

    def same(self, x: int, y: int) -> bool:
        return self.root(x) == self.root(y)

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

    def show(self):
        m = {}
        for n in range(len(self.d)):
            r = self.root(n)

            if r not in m:
                m[r] = [n]
            else:
                m[r].append(n)

        print("root -> childs")
        print("---------------------")
        for key in m:
            print(("{} -> {}".format(key, m[key])))


def main():
    n, m = geta(int)

    uf = UnionFind(2*n)

    ans = n

    for _ in range(m):
        x, y, z = geta(int)

        united = False
        if z & 1 == 0:
            united = uf.unite(2*x-2, 2*y-2) and uf.unite(2*x-1, 2*y-1)
        else:
            united = uf.unite(2*x-2, 2*y-1) and uf.unite(2*x-1, 2*y-2)

        if united:
            ans -= 1

    print(ans)


def __starting_point():
    main()

__starting_point()

N, M = map(int, input().split())
edge = [[] for _ in range(N)]
for i in range(M):
  a,b,c = 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)

from networkx.utils import UnionFind
def main():
    n,m=map(int, input().split())
    uf=UnionFind()
    for i in range(n):
        _=uf[i]
    for _ in range(m):
        x,y,z=map(int, input().split())
        uf.union(x-1,y-1)
    print(len(list(uf.to_sets())))
    
    
def __starting_point():
    main()
__starting_point()

#float型を許すな
#numpyはpythonで
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**7)
from collections import Counter, deque
from collections import defaultdict
from itertools import combinations, permutations, accumulate, groupby, product
from bisect import bisect_left,bisect_right
from heapq import heapify, heappop, heappush
from math import floor, ceil,pi,factorial
from operator import itemgetter
def I(): return int(input())
def MI(): return list(map(int, input().split()))
def LI(): return list(map(int, input().split()))
def LI2(): return [int(input()) for i in range(n)]
def MXI(): return [[LI()]for i in range(n)]
def SI(): return input().rstrip()
def printns(x): print(('\n'.join(x)))
def printni(x): print(('\n'.join(list(map(str,x)))))
inf = 10**17
mod = 10**9 + 7
#https://note.nkmk.me/python-union-find/

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=MI()
u=UnionFind(n)
for i in range(m):
    a,b,c=MI()
    u.union(a-1,b-1)
print((u.group_count()))


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

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

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

uf = UnionFind(n)

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

print((uf.group_count()))


import queue

n, m = list(map(int, input().split()))
dic = {}  
count = 0
q = queue.Queue()

for i in range(m):
  a, b, c = list(map(int, input().split()))
  if not a-1 in dic:
    dic[a-1]=[b-1]
  else:
    dic[a-1].append(b-1)
  
  if not b-1 in dic:
    dic[b-1]=[a-1]
  else:
    dic[b-1].append(a-1)

dp = [0]*n

#print(dic)

for i in range(n):
  if dp[i]==0:
    count += 1
    dp[i]=count
    if i in dic:
      for j in dic[i]:
        dp[j]=count
        q.put(j)
    #print(dp)
    while not q.empty():
      temp = q.get()
      #print(temp)
      if temp in dic:
        for j in dic[temp]:
          if dp[j] == 0:
            dp[j]=count
            q.put(j)
#print(dp)
print(count)

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

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

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

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

    def count(self, x):
        return -self.root[self.find(x)-1]
    def num(self):
        return self.n

N,M=list(map(int,input().split()))
uf=UnionFind(N)
for i in range(M):
    x,y,z=list(map(int,input().split()))
    uf.unite(x,y)
print((uf.num()))


import sys
import itertools
# import numpy as np
import time
import math
 
sys.setrecursionlimit(10 ** 7)
 
from collections import defaultdict
 
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines


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

adj = [[] for _ in range(N)]
for i in range(M):
    x, y, z = map(int, readline().split())
    x -= 1
    y -= 1
    adj[x].append(y)
    adj[y].append(x)

visited = [False for _ in range(N)]
def dfs(v):
    if visited[v]:
        return False
    visited[v] = True
    for u in adj[v]:
        dfs(u)
    return True


ans = 0
for i in range(N):
    if dfs(i):
        ans += 1
print(ans)

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) # n: 頂点数

for i in range(m):
    x, y, z = list(map(int, input().split()))

    uf.union(x-1, y-1)

print((uf.group_count()))


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


par = [-1]*(n)
def find(x):
    if par[x] < 0:
        return x
    else:
        par[x] = find(par[x]) #経路圧縮
        return par[x]
def same(x,y):
    return find(x) == find(y)
def unite(x,y):
    x = find(x)
    y = find(y)
    if x == y:
        return 0
    else:
      if par[x] > par[y]:x,y = y,x
      par[x] += par[y]
      par[y] = x
def size(x):
    return -par[find(x)]


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


ans = 0
# print(par)
for i in range(n):
  if par[i] <0:
    ans += 1
print(ans)

class UnionFind:

    def __init__(self, n):
        self.par = [-1] * n


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


    def root(self, x):
        path = []
        while self.par[x] >= 0:
            path.append(x)
            x = self.par[x]
        for y in path:
            self.par[y] = x
        return x


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


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


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

a = [0] * n
for i in range(n):
    a[uni.root(i)] = 1

print(sum(a))

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

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

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

        if x == y:
            return

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

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

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

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

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

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

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

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

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

N, M = map(int, input().split())
uf = UnionFind(N)
for _ in range(M):
    X, Y, Z = map(lambda x: int(x)-1, input().split())
    uf.union(X, Y)
print(uf.group_count())

N,M=list(map(int,input().split()))
par=[-1]*N

def find(x):
    if par[x]<0:
        return x
    else:
        par[x]=find(par[x])
        return par[x]
def union(x,y):
    p,q=find(x),find(y)
    if p==q:
        return
    if p>q:
        p,q=q,p
    par[p]+=par[q]
    par[q]=p   

for _ in range(M):
    X,Y,_=list(map(int,input().split()))
    X,Y=X-1,Y-1
    union(X,Y)
ans=0
for i in range(N):
    if par[i]<0:
        ans+=1
print(ans)


import sys
def input(): return sys.stdin.readline().rstrip()

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

def main():
    n,m=map(int, input().split())
    uf=UnionFind(n)
    for _ in range(m):
        x,y,z=map(int, input().split())
        uf.union(x-1,y-1)
    print(uf.group_count())




 
def __starting_point():
    main()
__starting_point()

class UnionFind:
    def __init__(self, N):
        self.root = [-1 for _ in range(N)]
        self.size = [1 for _ in range(N)]

    def find(self, x):
        while self.root[x] >= 0:
            x = self.root[x]
        return x

    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return
        if self.size[x] < self.size[y]:
            self.root[x] = y
            self.size[y] += self.size[x]
        else:
            self.root[y] = x
            self.size[x] += self.size[y]

N, M = [int(_) for _ in input().split()]
uf = UnionFind(N)

for i in range(M):
    X, Y, Z = [int(_) for _ in input().split()]
    uf.union(X-1, Y-1)

ans = set()
for i in range(N):
    ans.add(uf.find(i))
print((len(ans)))


from collections import Counter

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

class UnionFind:
    def __init__(self, n):
        self.par = [i for i in range(n)]
        self.rank = [0] * (n)
        self.size = [1] * (n)
    # 検索
    def find(self, x):
        if self.par[x] == x:
            return x
        else:
            self.par[x] = self.find(self.par[x])
            return self.par[x]
    # 併合
    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return
        if self.rank[x] < self.rank[y]:
            self.par[x] = y
            self.size[y] += self.size[x]
        else:
            self.par[y] = x
            self.size[x] += self.size[y]
            if self.rank[x] == self.rank[y]:
                self.rank[x] += 1
    # 同じ集合に属するか判定
    def same(self, x, y):
        return self.find(x) == self.find(y)
    # すべての頂点に対して親を検索する
    def all_find(self):
        for n in range(len(self.par)):
            self.find(n)

uf = UnionFind(n)

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

root = set([])

for i in range(n):
    root.add(uf.find(i))

print(len(root))

import sys
import collections

input_methods=['clipboard','file','key']
using_method=0
input_method=input_methods[using_method]

tin=lambda : map(int, input().split())
lin=lambda : list(tin())
mod=1000000007

#+++++

def main():
	#a = int(input())
	n, m = tin()
	#s = input()
	is_open=[-1]*n
	graph = [[] for _ in range(n)]
	for _ in range(m):
		x, y, _ = tin()
		graph[x-1].append(y-1)
		graph[y-1].append(x-1)
		
	ret = 0
	for i in range(n):
		if is_open[i] > 0:
			continue
		ret += 1
		q=collections.deque()
		q.append(i)
		is_open[i] = 1
		while q:
			pos = q.pop()
			for t in graph[pos]:
				if is_open[t] > 0:
					continue
				is_open[t] = 1
				q.append(t)
	return ret
		
	
	
#+++++
isTest=False

def pa(v):
	if isTest:
		print(v)
		
def input_clipboard():
	import clipboard
	input_text=clipboard.get()
	input_l=input_text.splitlines()
	for l in input_l:
		yield l

def __starting_point():
	if sys.platform =='ios':
		if input_method==input_methods[0]:
			ic=input_clipboard()
			input = lambda : ic.__next__()
		elif input_method==input_methods[1]:
			sys.stdin=open('inputFile.txt')
		else:
			pass
		isTest=True
	else:
		pass
		#input = sys.stdin.readline
			
	ret = main()
	if ret is not None:
		print(ret)
__starting_point()

import sys
import heapq
import math
import fractions
import bisect
import itertools
from collections import Counter
from collections import deque
from operator import itemgetter
def input(): return sys.stdin.readline().strip()
def mp(): return map(int,input().split())
def lmp(): return 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 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=mp()
uf = UnionFind(n)
for i in range(m):
    X,Y,Z=mp()
    uf.union(X-1,Y-1)
print(len(uf.roots()))

def main():
    n,m = list(map(int,input().split()))
    cards = [-1 for i in range(n)]
    mg = {}
    for i in range(n):
        mg[i+1] = []
    for i in range(m):
        x,y,z = list(map(int,input().split()))
        mg[x].append(y)
        mg[y].append(x)
    ans = 0
    for i in range(n):
        if cards[i]==-1:
            ans += 1
            cards[i] = 0
            que = [i]
            while len(que)>0:
                s = que.pop(0)
                for v in mg[s+1]:
                    if cards[v-1] == 0:
                        continue
                    cards[v-1] = 0
                    que.append(v-1)
    print(ans)

def __starting_point():
    main()

__starting_point()

# Union Find 木
from sys import setrecursionlimit


def find(parent, i):
    t = parent[i]
    if t < 0:
        return i
    t = find(parent, t)
    parent[i] = t
    return t


def unite(parent, i, j):
    i = find(parent, i)
    j = find(parent, j)
    if i == j:
        return
    parent[j] += parent[i]
    parent[i] = j


setrecursionlimit(10 ** 6)

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

parent = [-1] * N
for _ in range(M):
    X, Y, Z = list(map(int, input().split()))
    unite(parent, X - 1, Y - 1)
print((len([x for x in parent if x < 0])))


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

	def merge(self, x, y):
		x = self.root(x)
		y = self.root(y)
		if x == y: return False

		if self.data[x] < self.data[y]:
			x, y = y, x

		self.data[y] += self.data[x]
		self.data[x] = y
		return True

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

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

def main():
	N, M = map(int, input().split())
	uf = UnionFind(N)
	for i in range(M):
		x, y, z = map(int, input().split())
		uf.merge(x-1, y-1)

	cnt = 0
	for i in range(N):
		if uf.root(i) == i:
			cnt += 1

	print(cnt)

def __starting_point():
	main()
__starting_point()

import sys, collections

stdin = sys.stdin
n, m = map(int, stdin.readline().split())

par = [i for i in range(n)]
size = [1] * n  # size of tree
rank = [1] * n  # distance from parent


def find(x, par):
    if par[x] == x:
        return x
    else:
        return find(par[x], par)


def unite(x, y):
    x = find(x, par)
    y = find(y, par)

    if x != y:
        # xとyの属している集合が異なる時
        if rank[x] < rank[y]:
            par[x] = y
            size[y] += size[x]
        else:
            par[y] = x
            size[x] += size[y]
            if rank[x] == rank[y]:
                rank[x] += 1


for _ in range(m):
    x, y, z = map(int, stdin.readline().split())
    unite(x - 1, y - 1)
    
ans = set()
for i in range(n):
    ans.add(find(i, par))
print(len(ans))

from collections import deque

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

edge = [[] for i in range(N)]
for i in range(M):
    x, y, _ = map(int, input().split())
    edge[x-1].append(y-1)
    edge[y-1].append(x-1)

visited = [False] * N

ans = 0
for i in range(N):
    if visited[i]:
        continue
    else:
        ans += 1

    q = deque([i])
    while q:
        cur = q.pop()
        visited[cur] = True

        for next in edge[cur]:
            if visited[next]:
                continue
            visited[next] = True
            q.append(next)

print(ans)

class UnionFind:
    """
    size の要素数の UnionFind を管理する
    data 中の負数の要素が根となる
    """

    def __init__(self, size):
        # 根は子を含む集合のデータ数を負数でもつ
        self.data = [-1] * size

    def merge(self, x, y):
        x = self.root(x)
        y = self.root(y)
        if x == y: return False

        # y の方がデータ数を多く
        if self.data[x] < self.data[y]:
            x, y = y, x

        # y に x をつなげる
        self.data[y] += self.data[x]
        self.data[x] = y
        return True

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

    def size(self, x):
        """
        根は負数でデータ数を管理しているのでそれを返す
        """
        return -self.data[self.root(x)]

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

    cnt=0
    for i in range(N):
        if uf.root(i)==i:
            cnt+=1
    print(cnt)


def __starting_point():
    main()

__starting_point()

# E - 1 or 2
from typing import Set


class UnionFind:
    """Union-Find: O(α(N))"""

    __slots__ = ["_data_size", "_first_idx", "_parents"]

    def __init__(self, data_size: int, is_zero_origin: bool = True) -> None:
        self._data_size = data_size
        self._first_idx = 0 if is_zero_origin else 1
        self._parents = [-1] * (data_size + self._first_idx)

    def __getitem__(self, x: int) -> int:
        """Find the group (root) of vertex x."""
        if self._parents[x] < 0:
            return x
        self._parents[x] = self[self._parents[x]]
        return self._parents[x]

    def __len__(self) -> int:
        """Count the number of groups (roots)."""
        return len(self.groups)

    @property
    def groups(self) -> Set[int]:
        """Return the set of groups (roots)."""
        return {
            self[x] for x in range(self._first_idx, self._data_size + self._first_idx)
        }

    def is_connected(self, x: int, y: int) -> bool:
        """Return whether two vertices x and y are connected or not."""
        return self[x] == self[y]

    def unite(self, x: int, y: int) -> None:
        """Unite two groups of vertices x and y."""
        x, y = self[x], self[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 main():
    N, _, *X = list(map(int, open(0).read().split()))
    tree = UnionFind(N, is_zero_origin=False)
    for x, y, _ in zip(*[iter(X)] * 3):
        tree.unite(x, y)
    print((len(tree)))


def __starting_point():
    main()

__starting_point()

import sys
sys.setrecursionlimit(10**8)
N, M = map(int, input().split())
edge = [[] for _ in range(N)]
for i in range(M):
  a,b,c = 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)

import sys
sys.setrecursionlimit(10**9)

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

class Union_Find:
    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 self.parent[x] == x:
            return x
        else:
            return self.find(self.parent[x])
    
    def unite(self, x, y):
        px = self.find(x)
        py = self.find(y)
        if px == py:
            return
        else:
            if self.rank[px] == self.rank[py]:
                self.parent[py] = px
                self.rank[px] += 1
            elif self.rank[px] > self.rank[py]:
                self.parent[py] = px
            else:
                self.parent[px] = py
uftree = Union_Find(N+1)

for i in range(M):
    x, y, _ = list(map(int, input().split()))
    uftree.unite(x, y)

result = 0
for i in range(1, N+1):
    if uftree.find(i) == i:
        result += 1

print(result)



import sys
breadline = sys.stdin.buffer.readline
bread = sys.stdin.buffer.read
readline = sys.stdin.readline
read = sys.stdin.read
printout = sys.stdout.write
sprint = sys.stdout.flush
sys.setrecursionlimit(10 ** 7)

INF = 1 << 50
EPS = 1e-8
mod = 10 ** 9 + 7

def getnum(t=int): return t(breadline())
def numline(t=int): return map(t, breadline().split())
def numread(t=int): return map(t, bread().split())
def getstr(): return readline().strip()
def strline(): return readline().strip().split()
def strread(): return read().strip().split()

def dfs(c, to, seen):
    for n in to[c]:
        if not seen[n]:
            seen[n] = 1
            dfs(n, to, seen)

def run():
    N,M = numline()
    to = [[] for _ in range(N+1)]
    for _ in range(M):
        x,y,z = numline()
        to[x].append(y)
        to[y].append(x)

    G = []
    seen = [0] * (N+1)
    for i in range(1, N+1):
        if not seen[i]:
            seen[i] = 1
            dfs(i, to, seen)
            G.append(i)
    #print(G)
    print(len(G))



def __starting_point():
    run()
__starting_point()

from collections import deque

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

edge = [[] for i in range(N)]
for i in range(M):
    x, y, _ = map(int, input().split())
    edge[x-1].append(y-1)
    edge[y-1].append(x-1)

visited = [False] * N

ans = 0
for i in range(N):
    if visited[i]:
        continue
    else:
        ans += 1

    q = deque([i])
    while q:
        cur = q.popleft()
        visited[cur] = True

        for next in edge[cur]:
            if visited[next]:
                continue
            visited[next] = True
            q.append(next)

print(ans)

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

import sys
sys.setrecursionlimit(10**9) #再帰の上限をあげる

root=[-1 for i in range(n+1)] #自分が親ならグループの人数のマイナス倍を、そうでないなら（元）親の番号を示す
dep=[1]*(n+1)
def r(x):   #親は誰？
    if root[x]<0:
        return x
    else:
        root[x]=r(root[x])
        return root[x]

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

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


g=[0]*(n+1)
for i in range(1,n+1):
    g[r(i)]+=1
ans=0
for i in range(n+1):
    if g[i]>0:
        ans+=1
print(ans)



from collections import defaultdict

N, M = list(map(int, input().split()))
edges = defaultdict(list)
for _ in range(M):
    x, y, z = list(map(int, input().split()))
    x-=1
    y-=1
    edges[x].append(y)
    edges[y].append(x)

is_visited = [False] * N

def dfs(i):
    stack = [i]
    while stack:
        i = stack.pop()
        if is_visited[i]:
            continue
        is_visited[i] = True
        for j in edges[i]:
            stack.append(j)

islands = 0
for i in range(N):
    if is_visited[i] == False:
        islands += 1
        dfs(i)
print(islands)



class UnionFind:

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

    def root(self, node):
        parent_node = self.parents[node]
        if parent_node == node:
            return node
        root_node = self.root(parent_node)
        self.parents[node] = root_node  # reduction
        return root_node

    def union(self, one_node, other_node):
        one_root = self.root(one_node)
        other_root = self.root(other_node)
        if one_root == other_root:
            return
        if self.ranks[one_root] < self.ranks[other_root]:
            self.parents[one_root] = other_root
        else:
            self.parents[other_root] = one_root
            if self.ranks[one_root] == self.ranks[other_root]:
                self.ranks[one_root] += 1


def main():
    N, M = list(map(int, input().split(' ')))
    tree = UnionFind(N)
    for _ in range(M):
        x, y, _ = list(map(int, input().split(' ')))
        tree.union(x - 1, y - 1)
    roots = list(map(lambda n: tree.root(n), range(N)))
    print(len(set(roots)))


def __starting_point():
    main()
__starting_point()

import sys
sys.setrecursionlimit(10**9)
n,m = map(int, input().split())

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

ans = [-1]*n
def hoge(parent, pos):
  for i in rel[pos]:
    if ans[i] >= 0:
      continue
    ans[i] = pos
    hoge(pos, i)
  return

cnt = 0
for i in range(n):
  if ans[i] < 0:
    hoge(0, i)
    cnt += 1

print(cnt)

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

print(uf.num_roots())

# UnionFind: https://note.nkmk.me/python-union-find/
class UnionFind():
    def __init__(self, n):
        self.n = n
        self.root = [-1] * (n + 1)
        
    def find(self, x):
        if self.root[x] < 0:
            return x
        else:
            self.root[x] = self.find(self.root[x])
            return self.root[x]
    
    def unite(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return False
        if self.root[x] > self.root[y]:
            x, y = y, x
        self.root[x] += self.root[y]
        self.root[y] = x
        
    def is_same(self, x, y):
        return self.find(x) == self.find(y)
    
    def size(self, x):
        return -self.root[self.find(x)]

n, m = map(int, input().split())
cards = UnionFind(n)
for i in range(m):
    x, y, z = map(int, input().split())
    cards.unite(x, y)
print(sum(cards.find(i) == i for i in range(1, n + 1)))

class UnionFind:
    def __init__(self, node):
        self.parent = [-1 for _ in range(node)]

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

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

    def union(self, x, y):
        root_x = self.find(x)
        root_y = self.find(y)
        if root_x == root_y:
            return
        if self.parent[root_x] > self.parent[root_y]:
            root_x, root_y = root_y, root_x
        self.parent[root_x] += self.parent[root_y]
        self.parent[root_y] = root_x

    def get_size(self, x):
        return -self.parent[self.find(x)]

    def get_root(self):
        return [i for i, root in enumerate(self.parent) if root < 0]


def main():
    n, m = list(map(int, input().split()))
    uf = UnionFind(n)
    for _ in range(m):
        x, y, _ = [int(x) - 1 for x in input().split()]
        uf.union(x, y)
    print((len(uf.get_root())))


def __starting_point():
    main()

__starting_point()

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

uf=[i for i in range(n+1)]

def uf_find(x):
    while uf[x]!=x:
        x=uf[x]
    return x

for i in range(m):
    x,y,z=list(map(int,input().split()))
    a,b=uf_find(x),uf_find(y)
    if a>b:
        a,b=b,a
    uf[b]=a

c=set()
for i in range(1,n+1):
    c.add(uf_find(i))
print((len(c)))


class UnionFind():
    def __init__(self, n):
        self.par = [i for i in range(n)]
        self.rank = [0] * n

    def root(self, x):
        if self.par[x] == x:
            return x
        else:
            self.par[x] = self.root(self.par[x])
            return self.par[x]

    def union(self, x, y):
        x = self.root(x)
        y = self.root(y)
        if x != y:
            if self.rank[x] < self.rank[y]:
                self.par[x] = y
            else:
                self.par[y] = x
                if self.rank[x] == self.rank[y]:
                    self.rank[x] += 1

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

n, m = [int(x) for x in input().split()]
A = UnionFind(n)
ans = n
for i in range(m):
    x, y, _ = [int(z) - 1 for z in input().split()]
    if not A.samegrp(x, y):
        ans -=1
    A.union(x, y)

print(ans)


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


class UF:
    def __init__(self, n):
        self.n = n
        self.g = list(range(n))
        self.vertices = list(range(n))

    def union(self, i0, i1):
        g0, g1 = self.find(i0), self.find(i1)
        g0, g1 = min(g0, g1), max(g0, g1)
        self.g[g1] = g0

    def find(self, i):
        path = []
        while self.g[i] != i:
            path.append(i)
            i = self.g[i]

        for j in path:
            self.g[j] = i

        return i

uf = UF(n)

for x, y in xy:
    uf.union(x, y)

g = set()
for x in range(n):
    g.add(uf.find(x))

answer = len(g)
print(answer)


import sys
readline = sys.stdin.readline

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

# by size
# 0-indexed
class UnionFind:
  N=0
  parent=None
  size=None
  def __init__(self,N):
    self.N=N
    self.parent=[i for i in range(self.N)]
    self.size=[1]*self.N
    
  def root(self,x):
    while x!=self.parent[x]:
      self.parent[x]=self.parent[self.parent[x]]
      x=self.parent[x]
    return x
  
  def same(self,x,y):
    return self.root(x)==self.root(y)
  
  def unite(self,x,y):
    x=self.root(x)
    y=self.root(y)
    if x==y:
      return
    if self.size[x]>self.size[y]:
      # 大きい方にくっつける
      self.parent[y]=x
      self.size[x]+=self.size[y]
    else:
      self.parent[x]=y
      self.size[y]+=self.size[x]
      
  def get_group_size(self,x):
    return self.size[self.root(x)]
  
  def get_roots(self):
    r=set()
    for i in range(self.N):
      r.add(self.root(i))
    return r
  
  def show_parent(self):
    print((self.parent))
    
  def show_size(self):
    print((self.size))
    
UF = UnionFind(N)

for i in range(M):
  x,y,z = list(map(int,readline().split()))
  UF.unite(x - 1, y - 1)
  
print((len(UF.get_roots())))


N,M=map(int,input().split())
List = []
for i in range (M):
  List.append(list(map(int, input().split())))
List.sort()

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

uf = UnionFind(N)
for i in range(M):
  uf.union(List[i][0]-1, List[i][1]-1)
print(uf.group_count())