// Slower C++ solution:
#include <bits/stdc++.h>



#define rep(i, n) for(int i = 0, i##_len = (n); i < i##_len; ++i)

#define repp(i, m, n) for(int i = m, i##_len = (n); i < i##_len; ++i)

#define all(x) (x).begin(), (x).end()

#define clr(ar, val) memset(ar, val, sizeof(ar))

template <class T> bool chmax(T &a, const T &b) { if (a < b) { a = b; return 1; } return 0; }

template <class T> bool chmin(T &a, const T &b) { if (b < a) { a = b; return 1; } return 0; }

int gcd(int a,int b){return b?gcd(b,a%b):a;}

using namespace std;



typedef long long ll;

typedef unsigned long long ull;

typedef pair <int,int> P;

typedef long double ld;



struct UnionFind {

    vector<int> par; // par[i]:iの親の番号　(例) par[3] = 2 : 3の親が2



    UnionFind(int N) : par(N) { //最初は全てが根であるとして初期化

        for(int i = 0; i < N; i++) par[i] = i;

    }



    int root(int x) { // データxが属する木の根を再帰で得る：root(x) = {xの木の根}

        if (par[x] == x) return x;

        return par[x] = root(par[x]);

    }



    void unite(int x, int y) { // xとyの木を併合

				// cout << x << " " << y << endl; 

        int rx = root(x); //xの根をrx

        int ry = root(y); //yの根をry

        if (rx == ry) return; //xとyの根が同じ(=同じ木にある)時はそのまま

        if(rx > ry) par[rx] = root(ry); //xとyの根が同じでない(=同じ木にない)時：xの根rxをyの根ryにつける

				else par[ry] = root(rx);

    }



    bool same(int x, int y) { // 2つのデータx, yが属する木が同じならtrueを返す

        int rx = root(x);

        int ry = root(y);

        return rx == ry;

    }

};



int main(void)

{

	int n, m;

	cin >> n >> m;

	vector<int> list;

	rep(i, n) list.push_back(i);

	UnionFind tree(n);

	rep(i, m){

		int a, b, c;

		cin >> a >> b >> c;

		tree.unite(a - 1, b - 1);

	}

	ll ans = 0, y[100001] = {};

	rep(i, n){

		int x = i;

		// while(tree.par[x] != x) x = tree.par[x];

		x = tree.root(x);

		// cout << x << " ";

		y[x] = 1;

	}

	rep(i, 100001) ans += y[i];

	cout << ans << endl;

	return 0;

}	

// Faster C++ solution for the same problem (measured speedup: 1.8105012979897683x):
#include <iostream>

#include <cstdio>

#include <cstdlib>

#include <algorithm>

#include <cmath>

#include <vector>

#include <set>

#include <map>

#include <unordered_set>

#include <unordered_map>

#include <queue>

#include <ctime>

#include <cassert>

#include <complex>

#include <string>

#include <cstring>

#include <chrono>

#include <random>

#include <queue>

#include <bitset>

#include <stack>

#include <functional>



#ifdef LOCAL

    #define eprintf(...) fprintf(stderr, __VA_ARGS__)

#else

    #define eprintf(...) 42

#endif



#define rep_(i, a_, b_, a, b, ...) for (int i = (a), i##_len = (b); i < i##_len; ++i)

#define rep(i, ...) rep_(i, __VA_ARGS__, __VA_ARGS__, 0, __VA_ARGS__)

#define reprev_(i, a_, b_, a, b, ...) for (int i = (b-1), i##_min = (a); i >= i##_min; --i)

#define reprev(i, ...) reprev_(i, __VA_ARGS__, __VA_ARGS__, 0, __VA_ARGS__)

#define all(x) (x).begin(), (x).end()

template <class T> bool chmax(T &a, const T &b) { if (a < b) { a = b; return 1; } return 0; }

template <class T> bool chmin(T &a, const T &b) { if (b < a) { a = b; return 1; } return 0; }

template <class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }

using namespace std;



typedef long long ll;

typedef unsigned long long ull;

typedef pair <int,int> P;

typedef long double ld;



struct UnionFind {

  vector< int > data;

 

  UnionFind(int sz) {

    data.assign(sz, -1);

  }

 

  bool unite(int x, int y) {

    x = find(x), y = find(y);

    if(x == y) return (false);

    if(data[x] > data[y]) swap(x, y);

    data[x] += data[y];

    data[y] = x;

    return (true);

  }

 

  int find(int k) {

    if(data[k] < 0) return (k);

    return (data[k] = find(data[k]));

  }

 

  int size(int k) {

    return (-data[find(k)]);

  }

};



int main (void)

{

    cin.tie(0);

    ios::sync_with_stdio(false);

    int n, m; cin >> n >> m;

    UnionFind uf(n);

    rep (i, m) {

        int x, y, z; cin >> x >> y >> z;

        x--; y--;

        uf.unite(x, y);

    }

    

    map<int, int> mmm; rep (i, n) mmm[uf.find(i)]++;

    cout << mmm.size() << "\n";



    return 0;

}