stablegradients/pie-gem5-bysrc huggingface dataset:
// Original C++ solution (slower):
#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;

}


// Optimized solution to the same problem (faster):
#include <iostream>

#include<math.h>

#include<vector>

#include<map>

#include<set>

#include<queue>

#include<stack>

#include <algorithm>

#include<string.h>

#define ll long long

#define ull unsigned long long

using namespace std;

/* 

struct edge{

	int to, nxt;

}e[100005];

int head[100005], tot = 1, x, num[100005];

void add(int v, int u)

{

	e[tot].to = u, e[tot].nxt = head[v], head[v] = tot++;

}*/

int dis[100005], k, n, m;

int find(int x)

{

	if (dis[x] != x)	return dis[x] = find(dis[x]);

	return x;

}

void uni(int x, int y)

{

	int xx = find(x);

	int yy = find(y);

	if (xx != yy)

	{

		dis[xx] = yy;

	}

}

signed main() 

{

	while (~scanf("%d%d", &n, &m))

	{

		k = 0; 

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

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

		{

			int a, b, c;

			scanf("%d%d%d", &a, &b, &c);

			uni(a, b);

		}

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

			if (find(i) == i)	k++;

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

	}

}


// Fastest known solution for this problem:
// Original C++ solution (slower):
#include <bits/stdc++.h>

typedef long long int LL;

using namespace std;



// 插入此處



const int MAXN = 1e5 + 2;

bool vis[MAXN];

vector<int> adj[MAXN];



void dfs(int idx) {

    vis[idx] = true;

    for (auto x : adj[idx]) {

        if (!vis[x])  dfs(x);

    }

}



int main() {

    std::ios::sync_with_stdio(false);

    cin.tie(0);

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

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

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

        adj[x].push_back(y);

        adj[y].push_back(x);

    }

    int ans = 0;

    memset(vis, 0, sizeof(vis));

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

        if (vis[i])  continue;

        dfs(i);

        ++ans;

    }

    cout << ans << endl;

    return 0;

}


// Optimized solution to the same problem (faster):
#include <iostream>

#include<math.h>

#include<vector>

#include<map>

#include<set>

#include<queue>

#include<stack>

#include <algorithm>

#include<string.h>

#define ll long long

#define ull unsigned long long

using namespace std;

/* 

struct edge{

	int to, nxt;

}e[100005];

int head[100005], tot = 1, x, num[100005];

void add(int v, int u)

{

	e[tot].to = u, e[tot].nxt = head[v], head[v] = tot++;

}*/

int dis[100005], k, n, m;

int find(int x)

{

	if (dis[x] != x)	return dis[x] = find(dis[x]);

	return x;

}

void uni(int x, int y)

{

	int xx = find(x);

	int yy = find(y);

	if (xx != yy)

	{

		dis[xx] = yy;

	}

}

signed main() 

{

	while (~scanf("%d%d", &n, &m))

	{

		k = 0; 

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

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

		{

			int a, b, c;

			scanf("%d%d%d", &a, &b, &c);

			uni(a, b);

		}

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

			if (find(i) == i)	k++;

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

	}

}


// Fastest known solution for this problem:
// Original C++ solution (slower):
#include <bits/stdc++.h>

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

using namespace std;

typedef long long ll;



vector< vector< int > > to(100005);

vector<int> group(100005, 0);



void DFS( int v, int g ) {

  group[v] = g;

  for ( auto nv: to[v] ) {

    if (group[nv] != 0 ) continue;

    DFS(nv,g);

  }

}



int main() {

  int N,M;

  cin >> N >> M;

  REP(i,M) {

    int x,y,z;

    cin >> x >> y >> z;

    x--; y--;

    to[x].emplace_back(y);

    to[y].emplace_back(x);

  }

  int grp = 1;

  REP(i,N) {

    if (group[i] != 0 ) continue;

    DFS( i, grp );

    grp++;

  }

  

  cout << grp-1 << endl;

  

}




// Optimized solution to the same problem (faster):
// Union-Find木のテスト

//  ランクなし版



#include <bits/stdc++.h>

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

using namespace std;

typedef long long ll;



struct UnionFind {

  vector<int> par;

  UnionFind( int n ) {

    par.resize(n);

    init(n);

  }

  void init( int n ) {

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

  }

  int root( int a ) {

    int pa = par[a];

    if ( pa == a ) return a;

    return par[a] = root(pa);

  }

  bool merge( int a, int b ) {

    int ra = root(a);

    int rb = root(b);

    if ( ra == rb ) return false;

    par[rb] = ra;

    return true;

  }

  bool isSame( int a, int b) {

    int ra = root(a);

    int rb = root(b);

    if ( ra == rb ) return true;

    else return false;

  }

  int CountRoot( int n ) {

    int cnt = 0;

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

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

    return cnt;

  }

};



int main() {

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

  }

  

  cout << uf.CountRoot(N) << endl;

  

}




// Fastest known solution for this problem:
// Original C++ solution (slower):
#include <bits/stdc++.h>

using namespace std;



const int MAX=100005;



int state[MAX],N;

vector<int> T[MAX],now(MAX);

stack<int> S;



void DFS(){

    int ans=0,count=0,z=0;

    while(count!=N){

        for(int j=z;j<N;j++){

            if(state[j]==0){

                S.push(j);

                state[j]=1;

                z=j;

                break;

            }

        }

    while(S.size()){

        int a=S.top();

        bool flag=true;

        for(int i=now[a];i<T[a].size();i++){

            if(state[T[a][i]]==0){

                S.push(T[a][i]);

                state[T[a][i]]=1;

                now[a]=i;

                flag=false;

                break;

            }

        }

            if(flag){

                state[a]=2;

                count++;

                S.pop();

            }

            

        }

        ans++;

    }

    cout<<ans<<endl;

}



int main(){

    

    int u,k,b,M;

    cin>>N>>M;

    

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

        state[i]=0;

        now[i]=0;

    }

    

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

        cin>>u>>k>>b;

        u--;

        k--;

        T[u].push_back(k);

        T[k].push_back(u);

        }

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

        sort(T[i].begin(),T[i].end());

    }

    DFS();

}


// Optimized solution to the same problem (faster):
#include <bits/stdc++.h>

using namespace std;



const int MAX=100005;



vector<int> par(MAX);



int root(int u){

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

    else return par[u]=root(par[u]);

}

void unite(int a,int b){

    int x=root(a);

    int y=root(b);

    if(x!=y) par[y]=x;

}

bool check(int a,int b){

    if(root(a)==root(b)) return 1;

    else return 0;

}



int main(){

    

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

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

        par[i]=i;

    }

    

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

        int a,b,c;cin>>a>>b>>c;

        a--;b--;

        unite(a,b);

    }

    

    set<int> S;

    

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

        S.insert(root(i));

    }

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

}


// Fastest known solution for this problem:
// Original C++ solution (slower):
#include<iostream>

#include<vector>

using namespace std;



const int MAX_N = 1e5 + 1;

const int MAX_M = 1e5 + 1;



int color[MAX_N];

vector<int> graph[MAX_N];



void dfs(int node, int c) {

    color[node] = c;

    for (int i = 0; i < graph[node].size(); i++) {

        if (color[graph[node][i]]) continue;

        dfs(graph[node][i], c);

    }

}



int main() {

    cin.tie(0);

    ios::sync_with_stdio(false);

    int N, M;

    cin >> N >> M;

    int x, y, z;

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

        cin >> x >> y >> z;

        x--, y--;

        graph[x].push_back(y);

        graph[y].push_back(x);

    }

    int now_color = 1;

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

        if (color[i]) continue;

        dfs(i, now_color);

        now_color++;

    }

    cout << now_color - 1 << endl;

    return 0;

}

// Optimized solution to the same problem (faster):
#include<iostream>

#include<vector>

#include<string>

#define rep(i, start, end) for (int i = (int)start; i < (int)end; ++i)

#define rrep(i, start, end) for (int i = (int)start - 1; i >= (int)end; --i)

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

using namespace std;

using ll = long long;

template<typename T> inline bool chmax(T& a, T b) {if (a < b) {a = b; return true;} return 0;}

template<typename T> inline bool chmin(T& a, T b) {if (a > b) {a = b; return true;} return 0;}



void dfs(const vector<vector<int>>& graph, vector<bool>& visited, int node) {

    visited[node] = true;

    for (auto& next_node : graph[node]) {

        if (!visited[next_node]) {

            dfs(graph, visited, next_node);

        }

    }

}



int main() {

    cin.tie(0);

    ios::sync_with_stdio(false);

    int N, M;

    cin >> N >> M;

    vector<int> X(M), Y(M), Z(M);

    rep(i, 0, M) {

        cin >> X[i] >> Y[i] >> Z[i];

        --X[i], --Y[i];

    }

    vector<vector<int>> graph(N);

    rep(i, 0, M) {

        graph[X[i]].push_back(Y[i]);

        graph[Y[i]].push_back(X[i]);

    }

    int ans = 0;

    vector<bool> visited(N, false);

    rep(i, 0, N) {

        if (!visited[i]) {

            dfs(graph, visited, i);

            ++ans;

        }

    }

    cout << ans << endl;

    return 0;

}

// Fastest known solution for this problem:
// Original C++ solution (slower):
#define _GLIBCXX_DEBUG

#include <bits/stdc++.h>

using namespace std;

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

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

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

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

typedef long long ll;

typedef pair<ll,ll> l_l;

typedef pair<int,int> i_i;

const ll mod=1e9+7;

const int inf=1<<30;



struct unionfind{

  vector<int> par;

  vector<int> rank;

  unionfind(int n=1){

    init(n);

  }

  void init(int n=1){

      par.resize(n); rank.resize(n);

      for(int i=0;i<n;++i) par[i]=i,rank[i]=0;

  }

  int root(int x){

    if(par[x]==x){

      return x;

    }

    else{

      int r=root(par[x]);

      return par[x]=r;

    }

  }

  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(rank[x]<rank[y]) swap(x,y);

    if(rank[x]==rank[y]) ++rank[x];

    par[y]=x;

    return true;

  }

};



int main(){

  unionfind uf(1e5);

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

  rep(i,m){

    int a,b,c;

     cin >> a >> b >> c;

     a--; b--;

    uf.merge(a,b);

  }

  set<int> st;

  rep(i,n){

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

  }

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

}

// Optimized solution to the same problem (faster):
#define _GLIBCXX_DEBUG

#include <bits/stdc++.h>

using namespace std;

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

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

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

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

typedef long long ll;

typedef pair<ll,ll> pll;

typedef pair<int,int> pii;

const ll mod=1e9+7;

const int inf=1<<30;



struct unionfind{

  vector<int> par;

  vector<int> rank;

  unionfind(int n=1){

    init(n);

  }

  void init(int n=1){

      par.resize(n); rank.resize(n);

      for(int i=0;i<n;++i) par[i]=i,rank[i]=0;

  }

  int root(int x){

    if(par[x]==x){

      return x;

    }

    else{

      int r=root(par[x]);

      return par[x]=r;

    }

  }

  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(rank[x]<rank[y]) swap(x,y);

    if(rank[x]==rank[y]) ++rank[x];

    par[y]=x;

    return true;

  }

};



int main(){

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

  unionfind uf(n);

  rep(i,m){

    int a,b,c;

    cin >> a >> b >> c;

    a--; b--;

    uf.merge(a,b);

  }

  map<int,int> mp;

  rep(i,n){

    mp[uf.root(i)]++;

  }

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

}

// Fastest known solution for this problem:
// Original C++ solution (slower):
#include <bits/stdc++.h>

using namespace std;



int n, m;

const int N = 100010;

vector<int> G[N];

vector<bool> seen(N);



void dfs(int now){

    seen[now] = true;

    for(int i = 0; i < G[now].size(); i++){

        int to = G[now][i];

        if(seen[to]) continue;

        dfs(to);

    }

}



int main(){

    cin.tie(nullptr);

    ios::sync_with_stdio(false);



    cin >> n >> m;

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

        int x, y, z;

        cin >> x >> y >> z;

        x--; y--;

        G[x].push_back(y);

        G[y].push_back(x);

    }



    int ans = 0;

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

        if(!seen[i]){

            dfs(i);

            ans++;

        }

    }



    cout << ans << endl;



    return 0;

}

// Optimized solution to the same problem (faster):
#include <bits/stdc++.h>

using namespace std;



struct UnionFind{

    vector<int> par;

    UnionFind(int N) : par(N){

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

            par[i] = -1;

        }

    }

    int root(int x){

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

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

    }

    void unite(int x, int y){

        int rx = root(x);

        int ry = root(y);

        if(rx == ry) return;

        else{

            if(par[rx] > par[ry]) swap(rx, ry);

            par[rx] += par[ry];

            par[ry] = rx;

       }

    }

    bool same(int x, int y){

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

    }

    void check(){

        for(auto x : par){

            cout << x << " ";

        }

        cout << endl;

    }

};



int main(){

    cin.tie(nullptr);

    ios::sync_with_stdio(false);



    int n, m;

    cin >> n >> m;



    UnionFind uf(n);

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

        int a, b, x;

        cin >> a >> b >> x;

        a--; b--;

        uf.unite(a, b);

    }



    set<int> st;

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

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

    }



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





    return 0;

}

// Fastest known solution for this problem:
// Original C++ solution (slower):
#include <bits/stdc++.h>

using namespace std;

vector<vector<int>> adj(100001);

int ret=0;

vector<bool> vu(100001);



void dfs(int node){

	for (auto& i:adj[node]){

		if (!vu[i]){

			vu[i]=true;

			dfs(i);

		}

	}

}



int main(){

	int n,m;

	cin >> n >> m;

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

		int a,b,c;

		cin >> a >> b >> c;

		adj[a].emplace_back(b);

		adj[b].emplace_back(a);

	}

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

		if (!vu[i]){

			vu[i]=true;

			++ret;

			dfs(i);

		}

	}

	cout << ret;

}


// Optimized solution to the same problem (faster):
#include <bits/stdc++.h>

using namespace std;

int getComp(vector<int>& comp,int i){

  if(comp[i] != i) comp[i] = getComp(comp,comp[i]);

  return comp[i];

}

void merge(vector<int>& comp,vector<int>& level,int a,int b){

  a = getComp(comp,a);

  b = getComp(comp,b);

  if(level[a] > level[b]) swap(a,b);

  else if(level[a] == level[b]) ++level[b];

  comp[a] = b;

}

int main(){

  ios::sync_with_stdio(0);

  cin.tie(0);

  int n,m,x,y,z;

  cin >> n >> m;

  vector<int> comp(n+1),level(n+1);

  iota(begin(comp),end(comp),0);

  while(m--){

    cin >> x >> y >> z;

    merge(comp,level,x,y);

  }

  set<int> st;

  for(int i = 1; i <= n; ++i) st.insert(getComp(comp,i));

  cout << st.size();

  return 0;

}

// Fastest known solution for this problem:
// Original C++ solution (slower):
#include <iostream>

#include <vector>

using namespace std;



vector<int> comp(100001);



int find_comp(int a){

	int compa=comp[a];

	while (compa != comp[compa]) compa=comp[compa];

	comp[a]=compa;

	return compa;

}



int main(){

	int n,m;

	cin >> n >> m;

	int cnt=n;

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

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

		int x,y,z;

		cin >> x >> y >> z;

		int a=find_comp(x),b=find_comp(y);

		if (a != b){

			comp[b]=a;

			--cnt;

		}

	}

	cout << cnt;

	return 0;

}

// Optimized solution to the same problem (faster):
#include <bits/stdc++.h>

using namespace std;

int getComp(vector<int>& comp,int i){

  if(comp[i] != i) comp[i] = getComp(comp,comp[i]);

  return comp[i];

}

void merge(vector<int>& comp,vector<int>& level,int a,int b){

  a = getComp(comp,a);

  b = getComp(comp,b);

  if(level[a] > level[b]) swap(a,b);

  else if(level[a] == level[b]) ++level[b];

  comp[a] = b;

}

int main(){

  ios::sync_with_stdio(0);

  cin.tie(0);

  int n,m,x,y,z;

  cin >> n >> m;

  vector<int> comp(n+1),level(n+1);

  iota(begin(comp),end(comp),0);

  while(m--){

    cin >> x >> y >> z;

    merge(comp,level,x,y);

  }

  set<int> st;

  for(int i = 1; i <= n; ++i) st.insert(getComp(comp,i));

  cout << st.size();

  return 0;

}

// Fastest known solution for this problem:
// Original C++ solution (slower):
#include <bits/stdc++.h>

using namespace std;



int N, M;

bool flag[100005] = {};

vector < int > G[100005];



void coloring(int v)

{

        if ( flag[v] ) return;

        flag[v] = true;

        

        for ( auto &x : G[v] ) {

                coloring(x);

        }

}



int main()

{

        cin >> N >> M;

        while ( M-- ) {

                int a, b, c;

                cin >> a >> b >> c; --a, --b;

                G[a].push_back(b);

                G[b].push_back(a);

        }

        

        int cnt = 0;

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

                if ( !flag[i] ) {

                        cnt++;

                        coloring(i);

                }

        }



        cout << cnt << endl;



        return ( 0 );

}


// Optimized solution to the same problem (faster):
#include <bits/stdc++.h>

using namespace std;



using ll = long long;

using Pi = pair<int, int>;

using Pl = pair<ll, ll>;

using vint = vector<int>;

using vvint = vector<vint>;

using vvvint = vector<vvint>;

using vdouble = vector<double>;

using vvdouble = vector<vdouble>;

using vvvdouble = vector<vvdouble>;

using vll = vector<ll>;

using vvll = vector<vll>;

using vvvll = vector<vvll>;

using uint = unsigned int;

using ull = unsigned long long;



template<typename T> using uset = unordered_set<T>;

template<typename T1, typename T2> using umap = unordered_map<T1, T2>;



constexpr int INF = (1 << 30) - 1;

constexpr ll LLINF = 1LL << 60;

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

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

constexpr char el = '\n';

constexpr int mod = 1000000007;



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

template<typename T> T lcm(T a, T b) { return (a / gcd(a, b) * b); }

template<typename T1, typename T2>

inline bool chmin(T1 &a, T2 b) { return (a > b && (a = b, true)); }

template<typename T1, typename T2>

inline bool chmax(T1 &a, T2 b) { return (a < b && (a = b, true)); }



template<typename T>

ostream& operator <<(ostream &os, vector<T> &v) {

	os << v[0];

	for (int i = 1; i < v.size(); i++) os << " " << v[i];

	return (os);

}



template<typename T>

istream& operator >>(istream &is, vector<T> &v) {

	for (auto &u : v) is >> u; return (is);

}



template<typename T1, typename T2>

istream& operator >>(istream &is, pair<T1, T2> &p) {

	return (is >> p.first >> p.second);

}



vvint G;

bitset<100005> flag;



void dfs(int u) {

	if (flag[u]) return;

	flag[u] = true;

	for (auto &v : G[u]) dfs(v);

}

void Main() {

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

	G = vvint(N);

	while (M--) {

		int a, b, c; cin >> a >> b >> c; --a, --b;

		G[a].push_back(b);

		G[b].push_back(a);

	}

	int cnt = 0;

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

		if (!flag[i]) {

			dfs(i); cnt++;

		}

	}

	cout << cnt << endl;

}



int main() {

	cin.tie(0);

	ios::sync_with_stdio(0);

	cout << fixed << setprecision(20);

	Main();

	return (0);

}


// Fastest known solution for this problem:
// Original C++ solution (slower):
#include <iostream>

#include <cstdio>

#include <vector>



using namespace std;



int n, m;

vector<int> ve[100005];

int cnt;

bool v[100005];



void dfs(int p)

{

    if(v[p]) return;

    v[p] = true;

    for(int i = 0; i < ve[p].size(); i++)

    {

        dfs(ve[p][i]);

    }

}



int main()

{

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

    while(m--)

    {

        int t1, t2;

        scanf("%d%d%*d", &t1, &t2);

        ve[t1].push_back(t2);

        ve[t2].push_back(t1);

    }

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

    {

        if(!v[i]) dfs(i), cnt++;

    }

    printf("%d", cnt);

    return 0;

}


// Optimized solution to the same problem (faster):
#include <iostream>

#include <cstdio>

#include <vector>



using namespace std;



int n, m, cnt;

int cp[100005];



int fnd(int p)

{

    if(cp[p] == p) return p;

    return cp[p] = fnd(cp[p]);

}



int main()

{

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

    cnt = n;

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

    while(m--)

    {

        int t1, t2;

        scanf("%d%d%*d", &t1, &t2);

        if(fnd(t1) != fnd(t2)) cp[fnd(t1)] = fnd(t2), cnt--;

    }

    printf("%d", cnt);

    return 0;

}


// Fastest known solution for this problem:
// Original C++ solution (slower):
#include<iostream>

using namespace std;

typedef long long ll;

#define NODE_MAX 200000

ll par[NODE_MAX],rk[NODE_MAX];

void init(){

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

    par[i]=i;

    rk[i]=0;

  }

}

int root(int x){

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

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

}

void unite(int x,int y){

  x = root(x);

  y = root(y);

  if(x==y) return;



  if(rk[x]<rk[y]){

    par[x] = y;

  }else{

    par[y] = x;

    if(rk[x]==rk[y]) rk[x]++;

  }

}

bool same(int x,int y){

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

}

int main(){

  ll n,m,cnt=0,rt;

  cin >> n >> m;

  init();

  ll x[NODE_MAX],y[NODE_MAX],z[NODE_MAX];

  bool know[NODE_MAX];

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

    know[i]=false;

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

    x[i]--;

    y[i]--;

    unite(x[i],y[i]);

  }

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

    rt = root(i);

    if(know[rt]==false){

      know[rt]=true;

      cnt++;

    }

  }

  cout << cnt <<endl;

}


// Optimized solution to the same problem (faster):
// I SELL YOU...! 

#include<iostream>

#include<vector>

#include<algorithm>

#include<functional>

#include<queue>

#include<chrono>

#include<iomanip>

#include<map>

#include<set>

using namespace std;

using ll = long long;

using P = pair<ll,ll>;

using TP = tuple<ll,ll,ll>;

class union_find{

  int n;

  vector<int> par,rk,size;

  public:

  union_find(int max_n){

    n = max_n+1;

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

      par.emplace_back(i);

      rk.emplace_back(0);

      size.emplace_back(1);

    }

  }

  int root(int x){

    vector<int> nodes;

    while(x!=par[x]){

      nodes.emplace_back(x);

      x = par[x];

    }

    for(auto v:nodes){

      par[v] = x;

    }

    return x;

  }

  void unite(int x,int y){

    x = root(x);

    y = root(y);

    if(x==y) return;

    if(rk[x]<rk[y]){

      par[x] = y;

      size[y] += size[x];

    }else{

      par[y] = x;

      if(rk[x]==rk[y]) rk[x]++;

      size[x] += size[y];

    }

  }

  bool same(int x,int y){

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

  }

  int treesize(int x){

    return size[root(x)];

  }

};

void init_io(){

  cin.tie(0);

  ios::sync_with_stdio(false);

  cout << fixed << setprecision(18);

}

signed main(){

  init_io();

  ll n,m,x,y,z,ans=0;

  cin >> n >> m;

  union_find uf(n);

  vector<bool> mark(n,false);

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

    cin >> x >> y >> z;

    x--;

    y--;

    uf.unite(x,y);

  }

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

    ll p = uf.root(i);

    if(!mark[p]){

      ans++;

      mark[p] = true;

    }

  }

  cout << ans << endl;

}


// Fastest known solution for this problem: