module Main where

import Data.List
import Control.Monad
import Debug.Trace
import qualified Data.ByteString.Char8 as BC
import Data.Maybe (fromJust)
import Data.List
import Control.Monad
import Debug.Trace
import Data.Bits
import Data.Array.MArray
import Data.Array.ST
import Control.Monad.ST
import Data.STRef
import qualified Data.Set as S
import Control.Monad
import qualified Data.Vector.Mutable as MV
import Control.Applicative (liftA2)
import Control.Monad.Primitive (PrimMonad, PrimState)

data UnionFind s = UnionFind {offset :: Int, graph :: MV.MVector s (Maybe Int), total :: MV.MVector s Int}

newUnionFind :: PrimMonad m => Int -> Int -> m (UnionFind (PrimState m))
newUnionFind start end = liftA2 (UnionFind start) (MV.replicate num Nothing) (MV.replicate num 1)
    where
        num = end - start + 1

convertIndex :: UnionFind s -> Int -> Int
convertIndex u i = i - offset u

root :: PrimMonad m => UnionFind (PrimState m) -> Int -> m Int
root u i = do
    let convertedI = convertIndex u i
    parent <- MV.read (graph u) convertedI 
    parent <- case parent of
        Nothing -> do
            MV.write (graph u) convertedI $ Just i
            pure i
        Just p ->
            pure p
    if parent == i then pure parent
    else do
        parent' <- root u parent
        MV.write (graph u) convertedI (Just parent')
        pure parent'

unite :: PrimMonad m => UnionFind (PrimState m) -> Int -> Int -> m ()
unite u ix iy = do
    rx <- root u ix
    ry <- root u iy 
    if rx == ry then pure ()
    else do 
        sizex <- size u rx
        sizey <- size u ry
        if sizex < sizey then do
            -- yが高い yが親
            MV.write (graph u) (convertIndex u rx) (Just ry)
            MV.write (total u) (convertIndex u ry) (sizex + sizey) 
        else do
            -- xが高い xが親
            MV.write (graph u) (convertIndex u ry) (Just rx)
            MV.write (total u) (convertIndex u rx) (sizex + sizey)

same :: PrimMonad m => UnionFind (PrimState m) -> Int -> Int -> m Bool
same u x y = liftA2 (==) (root u x) (root u y)

size :: PrimMonad m =>  UnionFind (PrimState m) -> Int -> m Int
size u i = root u i >>= MV.read (total u) . convertIndex u

readTuple2 :: IO (Int, Int)
readTuple2 = do
    [a, b] <- map (fst . fromJust . BC.readInt) . BC.words <$> BC.getLine
    return (a, b)

readTuple3 :: IO (Int, Int, Int)
readTuple3 = do
    [a, b, c] <- map (fst . fromJust . BC.readInt) . BC.words <$> BC.getLine
    return (a, b, c)

readInt :: IO Int
readInt = fst . fromJust . BC.readInt <$> BC.getLine
    


solve :: Int -> [(Int, Int, Int)] -> Int
solve n xyzs = runST $ do
    uf <- newUnionFind 1 n
    forM_ xyzs $ \(x,y,_) ->
        unite uf x y
    roots <- forM [1..n] $ \i->
        root uf i
    pure . S.size . S.fromList $ roots
    


main = do
    (n, m) <- readTuple2
    xyzs <- replicateM m readTuple3
    print $ solve n xyzs
    