// Slower C++ solution:
//おまじない

#include <iostream>

#include<iomanip>

#include <algorithm>

#include <vector>

#include <string>

#include <utility>

#include <queue>

#define INF 1e9+7

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

#define NO cout<<"NO"<<endl;

#define YES cout << "YES"<<endl;

#define No cout << "No"<<endl;

#define Yes cout << "Yes"<<endl;

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

#define P pair<int,int>

using namespace std;

typedef long long int ll;

typedef unsigned long long int ull;

//(int)'a'は97 (int)'A'は65 (int)'1'は49

//おまじない



const int maxn = 100000;



//ans=nとして、つなげるたび、連結の最初の部分を見つけるたびにans--をする



int n,m;

int ans;

vector<vector<int>> v(maxn);

bool used[maxn];



void dfs(int s){

    queue<int> que;

    que.push(s);

    

    while(!que.empty()){

        int argv = que.front();

        que.pop();

        used[argv]=true;

        rep(j,v[argv].size()){

            if(!used[v[argv][j]]){

                //cout << argv << ' '<<v[argv][j]<<endl;

                que.push(v[argv][j]);

                used[v[argv][j]]=true;

                ans--;

            }

        }

    }

    return;

}



int main(){

    

    cin >> n>>m;

    ans=n;

    fill(used,used+n,false);

    rep(i,m){

        int x,y,z;

        cin >>x>>y>>z;

        x--;y--;

        v[x].push_back(y);

        v[y].push_back(x);

    }

    

    rep(i,n){

        if(!used[i]&&v[i].size()>0){

            dfs(i);

        }

    }

    

    cout << ans<<endl;

    

    return 0;

}


// Faster C++ solution for the same problem (measured speedup: 3.0951619627046476x):
//おまじない

//#include <bits/stdc++.h>

#include <iostream>

#include<iomanip>

#include <map>

#include <set>

#include <algorithm>

#include <vector>

#include <string>

#include <utility>

#include <queue>

#define INF 1e9+7

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

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

#define P pair<int,int>

#define space ' '

#define pll pair<ll,ll>

using namespace std;

typedef long long int ll;

typedef unsigned long long int ull;



//(int)'a'は97 (int)'A'は65 (int)'1'は49

//おまじない



const int maxn = 100000;



//UnionFind

class UnionFind {

public:

  //親の番号を格納する。親だった場合は-(その集合のサイズ)

  vector<int> Parent;



  UnionFind(int N) {

    Parent = vector<int>(N, -1);

  }



  //Aがどのグループに属しているか調べる

  int root(int A) {

    if (Parent[A] < 0) return A;

    return Parent[A] = root(Parent[A]);

  }



  //自分のいるグループの頂点数を調べる

  int size(int A) {

    return -Parent[root(A)];

  }



  //AとBをくっ付ける

  bool connect(int A, int B) {

    

    A = root(A);

    B = root(B);

    if (A == B) {

      

      return false;

    }

    if (size(A) < size(B)) swap(A, B);

    

    Parent[A] += Parent[B];

    Parent[B] = A;



    return true;

  }

};



int main(){

    

    int n,m;

    int x[maxn],y[maxn],z[maxn];

    bool used[maxn+1]={0};

    int ans = 0;

    int cnt = 0;

    

    cin >> n>>m;

    rep(i,m){

        scanf("%d%d%d",&x[i],&y[i],&z[i]);

    }

    

    UnionFind Uni(n+2);

    

    rep(i,m){

        Uni.connect(x[i],y[i]);

    }

    

    rep(i,n){

        if(Uni.size(i+1)==1)ans++;

        else{

            if(used[Uni.root(i+1)]==false){

                ans++;

                used[Uni.root(i+1)]=true;

            }

        }

    }

    

    cout << ans<<endl;

    

    return 0;

}