import Control.Applicative
import Control.Monad
import Data.Maybe
import Data.List
import Data.Map
import Data.Set
import Debug.Trace
--import Data.HashMap
--import Data.Tuple.Extra

main = do
  [n, m] <- (fmap read) <$> words <$> getLine
  uvws <- readUvw m
  putStrLn $ show $ solve uvws n

xxx :: [(Int, Int, Int)] -> Int -> String
xxx uvws n = a
  where UnionFind u = Data.List.foldl (\x f -> f x) (newUnionFind [1..n]) [Main.union u v | (u, v, _) <- uvws]
        a = intercalate ", " $ fmap show $ Data.Map.toAscList u

solve :: [(Int, Int, Int)] -> Int -> Int
solve uvws n = numberOfRoots uf
  where uf = Data.List.foldl (\x f -> f x) (newUnionFind [1..n]) [Main.union u v | (u, v, _) <- uvws]

data UnionFind a = UnionFind (Map a a)

newUnionFind :: Ord a => [a] -> UnionFind a
newUnionFind xs = UnionFind $ Data.List.foldl (\x f -> f x) Data.Map.empty [Data.Map.insert x x | x <- xs]

find :: Ord a => a -> UnionFind a -> (a, UnionFind a)
--find x u | trace ("find: " ++ show x) False=undefined
find x u
  | Nothing == Data.Map.lookup x m = (x, u)
  | Just x == Data.Map.lookup x m = (x, u)
  | Just y == Data.Map.lookup x m = (root, UnionFind $ Data.Map.insert x root updated)
  where Just y = Data.Map.lookup x m
        (UnionFind m) = u
        (root, UnionFind updated) = Main.find y u

union :: Ord a => a -> a -> UnionFind a -> UnionFind a
union x y u = UnionFind $ Data.Map.insert xRoot yRoot m
  where (xRoot, UnionFind m) = Main.find x mShortenY
        (yRoot, mShortenY) = Main.find y u

numberOfRoots :: Ord a => UnionFind a -> Int
numberOfRoots u = uniqueSize $ [root | (root, _) <- fmap (\x -> Main.find x u) (Data.Map.keys m)]
  where UnionFind m = u

readUvw :: Int -> IO [(Int, Int, Int)]
readUvw 0 = return []
readUvw n = do
  [u, v, w] <- (fmap read) <$> words <$> getLine
  following <- readUvw $ n-1
  return $ (u, v, w):following

fst3 (a, _, _) = a

uniqueSize :: Ord a => [a] -> Int
uniqueSize = Data.Set.size . Data.Set.fromList
