import sys

sys.setrecursionlimit(10**6)

# 連結成分

# UF tree



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

n_component = N



root = list(range(N+1))

depth = [0] * (N+1)



def find_root(x):

  y = root[x]

  if x == y:

    return x

  z = find_root(y)

  root[x] = z

  return z



def merge(x,y):

  global n_component

  xx = find_root(x)

  yy = find_root(y)

  if xx == yy:

    return

  n_component -= 1

  if depth[xx] >= depth[yy]:

    root[yy] = xx

    depth[xx] += 1

  else:

    root[xx] = yy

    depth[yy] += 1

  

for _ in range(M):

  x,y,z = [int(x) for x in input().split()]

  merge(x,y)



answer = n_component

print(answer)

import sys

read = sys.stdin.buffer.read

readline = sys.stdin.buffer.readline

readlines = sys.stdin.buffer.readlines



from scipy.sparse import csr_matrix

from scipy.sparse.csgraph import connected_components



# X,Y に辺を貼る -> 連結成分ごとに1回



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

m = list(map(int,read().split()))

XYZ = list(zip(m,m,m))



X,Y,Z = list(zip(*XYZ))



graph = csr_matrix(([1]*M,(X,Y)),(N+1,N+1))

Ncomp,_ = connected_components(graph,connection='weak')



answer = Ncomp - 1

print(answer)
import sys

sys.setrecursionlimit(10**6)
# 連結成分
# UF tree
N, M = list(map(int, input().split()))
n_component = N
root = list(range(N + 1))
depth = [0] * (N + 1)


def find_root(x):
    y = root[x]
    if x == y:
        return x
    z = find_root(y)
    root[x] = z
    return z


def merge(x, y):
    global n_component
    xx = find_root(x)
    yy = find_root(y)
    if xx == yy:
        return
    n_component -= 1
    if depth[xx] >= depth[yy]:
        root[yy] = xx
        depth[xx] += 1
    else:
        root[xx] = yy
        depth[yy] += 1


for _ in range(M):
    x, y, z = [int(x) for x in input().split()]
    merge(x, y)
answer = n_component
print(answer)

import sys

read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines
from scipy.sparse import csr_matrix
from scipy.sparse.csgraph import connected_components

# X,Y に辺を貼る -> 連結成分ごとに1回
N, M = list(map(int, readline().split()))
m = list(map(int, read().split()))
XYZ = list(zip(m, m, m))
X, Y, Z = list(zip(*XYZ))
graph = csr_matrix(([1] * M, (X, Y)), (N + 1, N + 1))
Ncomp, _ = connected_components(graph, connection="weak")
answer = Ncomp - 1
print(answer)

-sys.setrecursionlimit(10**6) -# 連結成分 -# UF tree -N, M = list(map(int, input().split())) -n_component = N -root = list(range(N + 1)) -depth = [0] * (N + 1) +read = sys.stdin.buffer.read +readline = sys.stdin.buffer.readline +readlines = sys.stdin.buffer.readlines +from scipy.sparse import csr_matrix +from scipy.sparse.csgraph import connected_components - -def find_root(x): -    y = root[x] -    if x == y: -        return x -    z = find_root(y) -    root[x] = z -    return z - - -def merge(x, y): -    global n_component -    xx = find_root(x) -    yy = find_root(y) -    if xx == yy: -        return -    n_component -= 1 -    if depth[xx] >= depth[yy]: -        root[yy] = xx -        depth[xx] += 1 -    else: -        root[xx] = yy -        depth[yy] += 1 - - -for _ in range(M): -    x, y, z = [int(x) for x in input().split()] -    merge(x, y) -answer = n_component +# X,Y に辺を貼る -> 連結成分ごとに1回 +N, M = list(map(int, readline().split())) +m = list(map(int, read().split())) +XYZ = list(zip(m, m, m)) +X, Y, Z = list(zip(*XYZ)) +graph = csr_matrix(([1] * M, (X, Y)), (N + 1, N + 1)) +Ncomp, _ = connected_components(graph, connection="weak") +answer = Ncomp - 1