stablegradients/pie-gem5-pairs huggingface dataset:
// Slower C++ solution:
#include <bits/stdc++.h>

using namespace std;

//unionfind

typedef pair<int, int> P;

const int MAX_N = 100010;

int m, n;

int par[MAX_N];    //親

int deapth[MAX_N]; //木の深さ

int cnt[MAX_N];

int num;



vector<int> vec[MAX_N];

//n要素で初期化

void init(int n)

{

    for (int i = 0; i < n; i++)

    {

        par[i] = i;

        deapth[i] = 0;

        cnt[i] = 1;

    }

}

//木の根を求める

int find(int x)

{

    if (par[x] == x)

    {

        return x;

    }

    else

    {

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

    }

}



//xとyの属する集合を併合

void unite(int x, int y)

{

    x = find(x);

    y = find(y);

    if (x == y)

        return;

    if (deapth[x] < deapth[y])

    {

        par[x] = y;

        cnt[y] += cnt[x];

    }

    else

    {

        par[y] = x;

        cnt[x] += cnt[y];

        if (deapth[x] == deapth[y])

            deapth[x]++;

    }

}



bool same(int x, int y)

{

    return find(x) == find(y);

}



int main()

{

    cin >> n >> m;

    init(n + 1);

    vector<P> v;

    for (int i = 0; i < m; i++)

    {

        int x, y, z;

        cin >> x >> y >> z;

        unite(x, y);

    }

    int ans = 0;

    vector<bool> fl(n + 1, false);

    for (int i = 1; i <= n; i++)

    {

        if (fl[find(i)])

        {

            continue;

        }

        fl[find(i)] = true;

        ans++;

    }

    cout << ans << endl;

}


// Faster C++ solution for the same problem (measured speedup: 3.493829932119236x):
#include <bits/stdc++.h>

using namespace std;



class UnionFindTree

{

    vector<int> parent;

    vector<int> depth;

    vector<int> cnt;



public:

    UnionFindTree(int n) : parent(n), depth(n), cnt(n)

    {

        for (int i = 0; i < n; i++)

        {

            parent[i] = i;

            depth[i] = 0;

            cnt[i] = 1;

        }

    }



    //木の根を求める

    int find(int x)

    {

        if (parent[x] == x)

        {

            return x;

        }

        else

        {

            return parent[x] = find(parent[x]);

        }

    }



    //xとyの属する集合を併合

    void unite(int x, int y)

    {

        x = find(x);

        y = find(y);

        if (x == y)

            return;

        if (depth[x] < depth[y])

        {

            parent[x] = y;

            cnt[y] += cnt[x];

        }

        else

        {

            parent[y] = x;

            cnt[x] += cnt[y];

            if (depth[x] == depth[y])

                depth[x]++;

        }

    }

    // 同じ集合に属しているか判定

    bool same(int x, int y)

    {

        return find(x) == find(y);

    }

    // 集合のサイズを取得

    int size(int x)

    {

        return cnt[find(x)];

    }

};



int main()

{

    int n, m;

    cin >> n >> m;

    UnionFindTree utree(n + 10);

    for (int i = 0; i < m; i++)

    {

        int x, y, z;

        cin >> x >> y >> z;

        utree.unite(x, y);

    }

    set<int> s;

    for (int i = 1; i <= n; i++)

    {

        s.insert(utree.find(i));

    }

    cout << s.size() << endl;

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

using namespace std;



typedef long long int ll;

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



vector<int> E[100005];

bool check[100005];



void dfs(int fro, int to) {

  if (check[to] == 1) return;

  check[to] = 1;

  for(int& e:E[to]) {

    if (e != fro) dfs(to,e);

  }

}



int main() {

  int n,m,x,y,z;

  cin >> n >> m;

  for(int i = 0; i < m; i++) {

    cin >> x >> y >> z;

    E[x-1].push_back(y-1);

    E[y-1].push_back(x-1);

  }

  for(int i = 0; i < n; i++) check[i] = 0;

  int ans = 0;

  for(int i = 0; i < n; i++) {

    if (check[i] == 0) {

      ans++;

      dfs(-1,i);

    }

  }

  cout << ans << endl;

  return 0;

}


// Faster C++ solution for the same problem (measured speedup: 3.439930055606045x):
#include <bits/stdc++.h>

using namespace std;



typedef long long int ll;

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



struct UnionFind {

    vector<int> size, parents;

    UnionFind() {}

    UnionFind(int n) {  // make n trees.

        size.resize(n, 0);

        parents.resize(n, 0);

        for (int i = 0; i < n; i++) {

            makeTree(i);

        }

    }

    void makeTree(int x) {

        parents[x] = x;  // the parent of x is x

        size[x] = 1;

    }

    bool isSame(int x, int y) { return findRoot(x) == findRoot(y); }

    bool isRoot(int x) { return x == findRoot(x); }

    bool unite(int x, int y) {

        x = findRoot(x);

        y = findRoot(y);

        if (x == y) return false;

        if (size[x] > size[y]) {

            parents[y] = x;

            size[x] += size[y];

        } else {

            parents[x] = y;

            size[y] += size[x];

        }

        return true;

    }

    int findRoot(int x) {

        if (x != parents[x]) {

            parents[x] = findRoot(parents[x]);

        }

        return parents[x];

    }

    int treeSize(int x) { return size[findRoot(x)]; }

};



int main() {

  int n,m,x,y,z;

  cin >> n >> m;

  UnionFind U(n);

  for(int i = 0; i < m; i++) {

    cin >> x >> y >> z;

    U.unite(x-1,y-1);

  }

  int ans = 0;

  for(int i = 0; i < n; i++) {

    if (U.isRoot(i)) ans++;

  }

  cout << ans << endl;

  return 0;

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

using namespace std;

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

using ll = long long;

#define int long long

using P = pair<int,int>;

vector<int> graph[110000];

int visited[110000];



void dfs(int now,int last = -1){

    for(auto next:graph[now]){

        if(next == last)continue;

        if(visited[next])continue;

        visited[next] = 1;

        dfs(next,now);

    }

}

signed main(){

    

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

    rep(i,m){

        int a,b,c;

        cin >> a >> b >> c;

        a--;b--;

        graph[a].push_back(b);

        graph[b].push_back(a);

    }

    int ans = 0;

    rep(i,n){

        if(!visited[i]){

            dfs(i);

            ans++;

        }

    }

    cout << ans << endl;

    return 0;

}

// Faster C++ solution for the same problem (measured speedup: 3.6624151303805936x):
#include <bits/stdc++.h>

using namespace std;

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

using ll = long long;

#define int long long

using P = pair<int,int>;

struct UnionFind {

vector<int> d;

UnionFind(int n):d(n,-1){}

int root(int x){

    if(d[x] <0) return x;

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

}

bool unite(int x,int y){

    x = root(x),y = root(y);

    if(x == y) return false;

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

    d[x] += d[y];

    d[y] = x;

    return true;

}

int size(int x) {return -d[root(x)];}

bool same(int x,int y){return root(x) == root(y);}

};

int seen[110000];

signed main(){

    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);



    }

    int ans = 0;

    rep(i,n){

        auto hoge = uf.root(i);

        if(seen[hoge] == 0)ans++;

        seen[hoge] = 1;

    }

    cout << ans << endl;

    





    return 0;

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

using namespace std;

#define N 100010

#define ll long long

const ll mod =1e9+7;

vector<int>g[N];

int vis[N];

int sum=0;

void dfs(int x)

{

    int sz=g[x].size();

    for(int i=0;i<sz;i++)

    {

        int v=g[x][i];

        if(vis[v])continue;

        vis[v]=1;

        dfs(v);

    }

}

int main()

{

    int n,m,x,y,z;

    scanf("%d%d",&n,&m);



    for(int i=1;i<=m;i++)

    {

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

        g[x].push_back(y);

        g[y].push_back(x);

    }

    for(int i=1;i<=n;i++)

    {

        if(vis[i])

            continue;

        sum++;

        vis[i]=1;

        dfs(i);

    }

    cout<<sum<<endl;

    return 0;

}


// Faster C++ solution for the same problem (measured speedup: 3.548913088291507x):
#include<bits/stdc++.h>

using namespace std;

#define N 100010

#define ll long long

int f[N];

int get_fa(int x)

{

    return f[x]==x?x:f[x]=get_fa(f[x]);

}

int main()

{

    int n,m,x,y,z;

    scanf("%d%d",&n,&m);

    for(int i=1;i<=n;i++)f[i]=i;

    for(int i=1;i<=m;i++)

    {

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

        int fx=get_fa(x),fy=get_fa(y);

        if(fx!=fy)

            f[fy]=fx;

    }

    int cnt=0;

    for(int i=1;i<=n;i++)

        if(f[i]==i)cnt++;

    cout<<cnt;

    return 0;

}
// Slower C++ solution:
#include <iostream>

#include <vector>

using namespace std;



const int MAX_N = 1e5;

vector<vector<int> > graph(MAX_N + 1);

vector<bool> searched(MAX_N + 1, false);



void dfs(int f) {

    for (int a : graph[f]) {

        if (!searched[a]) {

            searched[a] = true;

            dfs(a);

        }

    }

}



int main() {

    int N, M; cin >> N >> M;

    for (int i = 0; i < M; i++) {

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

        graph[x].push_back(y);

        graph[y].push_back(x);

    }

    int ans = 0;

    for (int i = 1; i <= N; i++) {

        if (!searched[i]) {

            searched[i] = true;

            dfs(i);

            ans++;

        }

    }

    cout << ans << endl;

}


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

#include <vector>

#include <set>

using namespace std;



struct UnionFind {

    vector<int> parents;

    UnionFind(int N) : parents(N+1) {

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

    }

    int root(int x) {

        if (parents[x] == x) {

            return x;

        } else {

            parents[x] = root(parents[x]);

            return parents[x];

        }

    }

    void unite(int x, int y) {

        int rx = root(x);

        int ry = root(y);

        if (rx != ry) {

            parents[rx] = ry;

        }

    }

    bool same(int x, int y) {

        int rx = root(x);

        int ry = root(y);

        return rx == ry;

    }

};



int main() {

    int N, M; cin >> N >> M;

    UnionFind tree(N);

    for (int i = 0; i < M; i++) {

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

        tree.unite(x, y);

    }

    set<int> roots;

    for(int i = 1; i <= N; i++) {

        roots.insert(tree.root(i));

    }

    cout << roots.size() << endl;

}
// Slower C++ solution:
#include <iostream>

#include <vector>

using namespace std;



const int MAX_N = 1e5;

vector<vector<int> > graph(MAX_N + 1);

vector<bool> searched(MAX_N + 1, false);



void dfs(int f) {

    for (int a : graph[f]) {

        if (!searched[a]) {

            searched[a] = true;

            dfs(a);

        }

    }

}



int main() {

    int N, M; cin >> N >> M;

    for (int i = 0; i < M; i++) {

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

        graph[x].push_back(y);

        graph[y].push_back(x);

    }

    int ans = 0;

    for (int i = 1; i <= N; i++) {

        if (!searched[i]) {

            searched[i] = true;

            dfs(i);

            ans++;

        }

    }

    cout << ans << endl;

}


// Faster C++ solution for the same problem (measured speedup: 3.5310178985440337x):
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

typedef pair<ll, ll> Pll;



// unite, findはO(a),

#include <bits/stdc++.h>

using namespace std;



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)]);

    }



    bool same(int x, int y)

    {

        return find(x) == find(y);

    }

};





int main() {

    int N, M; cin >> N >> M;

    UnionFind uf = UnionFind(N);

    while (M--) {

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

        uf.unite(x-1, y-1);

    }

    vector<bool> c(N,false);

    int ans = 0;

    for (int i = 0; i < N; i++) {

        if (!c[uf.find(i)]) {

            ans++;

            c[uf.find(i)] = true;

        }

    }

    cout << ans << endl;

}
// Slower C++ solution:
//#pragma GCC target("avx2")

//#pragma GCC optimize("O3")

   

//#include <x86intrin.h>

#include <bits/stdc++.h>   

#include <ext/pb_ds/assoc_container.hpp>

#include <ext/pb_ds/tree_policy.hpp>

 

using namespace __gnu_pbds;

using namespace std;



template<typename T> using ordered_set = tree <T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

     

#define F first

#define S second           

#define lb lower_bound               

#define ub upper_bound

#define pb push_back

#define pf push_front    

#define ppb pop_back

#define mp make_pair                                     

#define bpp __builtin_popcountll                                                                                        

#define sqr(x) ((x) * (x)) 

#define al 0x3F3F3F3F

#define sz(x) (int)x.size()

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

#define in insert

#define ppf pop_front

#define endl '\n'

//#define int long long

 

typedef unsigned long long ull;

typedef long long ll;

typedef long double ld;

typedef pair <int, int> pii;

 

const int mod = (int)1e9 + 7;

const int N = (int)3e5 + 123;

const ll inf = (ll)1e18 + 1;



const double pi = acos (-1.0);

const double eps = 1e-7;                  

const int dx[] = {0, 0, 1, 0, -1};

const int dy[] = {0, 1, 0, -1, 0};



int n, m, x[N], y[N], z[N], ans;

vector <int> g[N];

bool used[N];



void dfs (int v) {

   used[v] = 1;

   for (auto to : g[v])

      if (!used[to])

         dfs (to);

}



inline void boost () {                    

   ios_base :: sync_with_stdio (NULL);

   cin.tie (NULL), cout.tie (NULL);          

}                                                     



inline void Solve () {

   cin >> n >> m;

   for (int i = 1; i <= m; i ++) {

      cin >> x[i] >> y[i] >> z[i];

      g[x[i]].pb (y[i]);

      g[y[i]].pb (x[i]);

   }

   for (int i = 1; i <= n; i ++)

      if (!used[i])

         dfs (i), ans ++;

   cout << ans;

}



main () {                                       

// freopen (".in", "r", stdin);    

// freopen (".out", "w", stdout);              

   boost ();

   int tt = 1;

   //cin >> tt;   

   while (tt --) {

      Solve ();

   }                                               

   return 0;      

}

                          

// Faster C++ solution for the same problem (measured speedup: 9.437778013609984x):
/*|In The Name Of Allah|*/



#include <bits/stdc++.h>



using namespace std;



const int N = 2e5+5;



int n;

int m;

bool mark[N];

int parent[N];



int getP(int u){

    if(parent[u] == u)

        return u;

    return parent[u] = getP(parent[u]);

}



void join(int u , int v){

    u = getP(u);

    v = getP(v);

    parent[u] = v;

}



int main(){

    scanf("%d%d" , &n , &m);

    for(int i = 1; i <= n; i++){

        parent[i] = i;

    }

    for(int i = 1; i <= m; i++){

        int u , v , w;

        scanf("%d%d%d" , &u , &v , &w);

        join(u , v);

    }

    int cnt = 0;

    for(int i = 1; i <= n; i++){

        if(mark[getP(i)])

            continue;

        cnt++;

        mark[getP(i)] = 1;

    }

    printf("%d\n" , cnt);

}
// Slower C++ solution:
#pragma GCC optimize(3,"Ofast","inline")

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

typedef unsigned long long ull;

const int N=1e5+5;

const int M=1e6+5;

const int INF=0x3f3f3f3f;

const ull sed=31;

const ll mod=1e9+7;

const double eps=1e-9;

typedef pair<int,int>P;

typedef pair<double,double>Pd;



int n,m,ans;

bool vis[N];

vector<int>E[N];



void dfs(int x)

{

    if(vis[x]) return ;

    vis[x]=true;

    for(int i=0;i<E[x].size();i++) dfs(E[x][i]);

}

int main()

{

    scanf("%d%d",&n,&m);

    for(int i=1;i<=m;i++)

    {

        int x,y,z;

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

        E[x].push_back(y);

        E[y].push_back(x);

    }

    for(int i=1;i<=n;i++)

    {

        if(vis[i]) continue;

        ans++;

        dfs(i);

    }

    printf("%d\n",ans);

    return 0;

}


// Faster C++ solution for the same problem (measured speedup: 3.874859891963917x):
#include <bits/stdc++.h>



using namespace std;

using ii = pair<int, int>;



class UFDS

{

private:

    std::vector<int> size, ps;

    int count;



public:

    UFDS(int N) : size(N + 1, 1), ps(N + 1), count(N)

    {

        std::iota(ps.begin(), ps.end(), 0);

    }



    int find_set(int x) 

    {

        return x == ps[x] ? x : (ps[x] = find_set(ps[x]));

    }



    bool same_set(int x, int y)

    {

        return find_set(x) == find_set(y);        

    }



    void union_set(int x, int y)

    {

        if (same_set(x, y))

            return;



        int p = find_set(x);

        int q = find_set(y);



        if (size[p] < size[q])

            std::swap(p, q);



        ps[q] = p;

        size[p] += size[q];

        --count;

    }



    int get_count() const { return count; }

};



int solve(int N, const vector<ii>& es)

{

    UFDS ufds(N);



    for (auto p : es)

    {

        auto x = p.first, y = p.second;



        ufds.union_set(x, y);

    }



    return ufds.get_count();

}



int main()

{

    ios::sync_with_stdio(false);



    int N, M;

    cin >> N >> M;



    vector<ii> es(M);



    for (int i = 0; i < M; ++i)

    {

        int x, y, z;

        cin >> x >> y >> z;



        es.push_back(ii(x, y));

    }



    cout << solve(N, es) << endl;



    return 0;

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



using namespace std;



typedef long long int lli;



int n, m, par[100001];



int root(int x) {

    if (par[x] == x) {

        return x;

    }

    else {

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

    }

}



void unite(int x, int y) {

    x = root(x);

    y = root(y);

    if (x == y) return;



    par[x] = y;

}



int main() {

    int x, y, z;



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



    cin >> n >> m;

    for (int i=0; i<m; i++) {

        cin >> x >> y >> z;

        unite(x, y);

    }



    int ans = 0;

    vector<bool> used(100001, false);

    for (int i=1; i<=n; i++) {

        int idx = root(i);

        if (!used[idx]) {

            ans++;

            used[idx] = true;

        }

    }



    cout << ans << endl;



    return 0;

}


// Faster C++ solution for the same problem (measured speedup: 1.3944779034261998x):
#include <bits/stdc++.h>



using namespace std;



typedef long long int lli;



class UnionFind {

private:

    vector<int> data;



public:

    UnionFind(int size) : data(size, -1) { }

    

    int root(int x) {

        return (data[x] < 0) ? x : data[x] = root(data[x]);

    }



    bool unite(int x, int y) {

        x = root(x);

        y = root(y);

        

        if (x != y) {

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

            data[x] += data[y];

            data[y] = x;

        }

        return x != y;

    }



    bool find(int x, int y) {

        return root(x) == root(y);

    }



    int size(int x) {

        return -data[root(x)];

    }

};



int main() {

    int n, m, x, y, z;



    cin >> n >> m;

    

    UnionFind uf(n+1);

    for (int i=0; i<m; i++) {

        cin >> x >> y >> z;

        uf.unite(x, y);

    }



    int ans = 0;

    for (int i=1; i<=n; i++) {

        if (uf.root(i) == i) ans++;

    }



    cout << ans << endl;



    return 0;

}
// Slower C++ solution:
#include<iostream>

#include<vector>

#include<string>

#include<cmath>

#include<algorithm>

#include <numeric>

#include<map>

#include<unordered_map>

#include <queue>

 

using namespace std;

using ll=long long;

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

#define all_map(itr,mp) for(auto itr=mp.begin();itr!=mp.end();itr++)

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

 

bool used[100010] = {false};

vector<vector<ll>> g(100010);



void dfs(ll pos){

    used[pos] = true;

    rep(i, g[pos].size()){

        if(!used[g[pos][i]])dfs(g[pos][i]);

    }

}

int main(){

    ll n, m;

    cin >> n >> m;

    rep(i, m){

        ll x, y, z;

        cin >> x >> y >> z;

        g[x].push_back(y);

        g[y].push_back(x);

    }

    ll ans = 0;

    rep(i, n){

        if(!used[i+1]){

            ans++;

            dfs(i+1);

        }

    }

    cout << ans << endl;

}

// Faster C++ solution for the same problem (measured speedup: 3.5085993072141144x):
#include <bits/stdc++.h>

 

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

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

 

using namespace std;

using ll  = long long;

using pll = pair<ll, ll>;

using pdd = pair<double, double>;

 

const ll MOD  = 1e9+7;

const ll LINF = 1LL << 60;

const int INF = 1e9 + 7;



int mvx[] = {1, 0, 0, -1};

int mvy[] = {0, 1, -1, 0};



//union find

struct UnionFind {

    vector<ll> parent;

    vector<ll> usize;

 

    UnionFind(int n) : parent(n), usize(n, 1LL){

        rep(i, n)parent[i]=i;

    }

    

    int root(int x){

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

        else return parent[x] = root(parent[x]);

    }

    

    bool issame(int x, int y){

        return root(x) == root(y);

    }

    

    bool merge(int x, int y) {

        x = root(x);

        y = root(y);

 

        if(x == y)return false;

 

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



        usize[x] += usize[y];

        parent[y] = x;

 

        return true;

    }

    

    int size(int x) {

        return usize[root(x)];

    }

};



int main(){

    ll n, m;

    cin >> n >> m;



    UnionFind uf(n);



    rep(i, m){

        int x, y, z;

        cin >> x >> y >> z;

        x--, y--;



        uf.merge(x, y);

    }



    set<ll> ans;

    rep(i, n){

        ans.insert(uf.root(i));

    }



    cout << ans.size() << endl;

}
// Slower C++ solution:
#include<iostream>

#include<vector>

#include<string>

#include<cmath>

#include<algorithm>

#include <numeric>

#include<map>

#include<unordered_map>

#include <queue>

 

using namespace std;

using ll=long long;

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

#define all_map(itr,mp) for(auto itr=mp.begin();itr!=mp.end();itr++)

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

 

bool used[100010] = {false};

vector<vector<ll>> g(100010);



void dfs(ll pos){

    used[pos] = true;

    rep(i, g[pos].size()){

        if(!used[g[pos][i]])dfs(g[pos][i]);

    }

}

int main(){

    ll n, m;

    cin >> n >> m;

    rep(i, m){

        ll x, y, z;

        cin >> x >> y >> z;

        g[x].push_back(y);

        g[y].push_back(x);

    }

    ll ans = 0;

    rep(i, n){

        if(!used[i+1]){

            ans++;

            dfs(i+1);

        }

    }

    cout << ans << endl;

}

// Faster C++ solution for the same problem (measured speedup: 3.4009055338633702x):
#include <bits/stdc++.h>

 

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

#define all_map(pos,mp) for(ll pos=mp.begin();pos!=mp.end();pos -++)

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



using namespace std;

using ll  = long long;

using pll = pair<ll, ll>;



const ll MOD  = 1e9 + 7;

const ll LINF = 1LL << 62;

const int INF = 1e9 + 7;



//union find

struct UnionFind {

    vector<ll> parent;

    vector<ll> usize;

 

    UnionFind(int n) : parent(n), usize(n, 1LL){

        rep(i, n)parent[i]=i;

    }

    

    int root(int x){

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

        else return parent[x] = root(parent[x]);

    }

    

    bool issame(int x, int y){

        return root(x) == root(y);

    }

    

    bool merge(int x, int y) {

        x = root(x);

        y = root(y);

 

        if(x == y)return false;

 

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



        usize[x] += usize[y];

        parent[y] = x;

 

        return true;

    }

    

    int size(int x) {

        return usize[root(x)];

    }

};



int main(){

    ll n, m;

    cin >> n >> m;



    UnionFind uf(n);

    rep(i, m){

        ll x, y, z;

        cin >> x >> y >> z;

        x--, y--;



        if(!uf.issame(x, y))uf.merge(x, y);

    }



    ll ans = 0;

    rep(i, n){

        if(i == uf.root(i))ans++;

    }



    cout << ans << endl;



}