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

using namespace std;

const int N=100005;

typedef long long int LL;





vector<int >ve[N];

map< LL , int >ma;

LL a[N];

LL b=17;

LL ans;

void dfs(int u)

{

    a[u]=1;

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

    {

        int v=ve[u][i];

        dfs(v);

        a[u]+=a[v]*b;

    }

    ans+=ma[a[u]];

    ma[a[u]]++;

    return ;

}



int main()

{

    int n;

        cin>>n;

        int u,v;

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

        {

            cin>>u>>v;

            ve[u].push_back(v);

        }

        ans=0;

        dfs(1);

        cout<<ans<<endl;





    return 0;

}

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

#include<cstdio>

#include<algorithm>

#include<cstring>

#include<vector>

#include<queue>

#include<stack>

#include<cmath>

#include<set>

#include<map>

using namespace std;

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

#define per(i,a,n) for (int i=n-1;i>=a;i--)

#define pb push_back

#define fi first

#define se second

#define dbg(...) cerr<<"["<<#__VA_ARGS__":"<<(__VA_ARGS__)<<"]"<<endl;

typedef vector<int> VI;

typedef long long ll;

typedef pair<double,int> PII;

const ll p=998244353;

const ll mod=1e9+7;

const int maxn=1e5+100;

map<ll,int> mp;



struct node

{

    int to,next;

}e[maxn*2];



int tol=0;

int head[maxn];

void add(int u,int v)

{

    e[++tol].to=v,e[tol].next=head[u],head[u]=tol;

}

ll dfs(int u,int f)

{

    ll ans=1;

    for(int i=head[u];i;i=e[i].next)

    {

        int v=e[i].to;

        if(v==f) continue;

        ans=(ans+dfs(v,u)*mod%p)%p;

    }

    mp[ans]++;

    return ans;

}





int main()

{

    int n;

    scanf("%d",&n);

    rep(i,1,n)

    {

        int u,v;

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

        add(u,v),add(v,u);

    }

    mp.clear();

    dfs(1,0);

    ll ans=0;

    map<ll,int>::iterator it;

    for(it=mp.begin();it!=mp.end();it++) ans+=1ll*(it->se)*(it->se-1)/2;

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

    return 0;

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

using namespace std;

#define ull unsigned long long

#define ll long long

ll ans;

map<ull,ll>m;

const int maxn=200005;

vector<int>g[maxn];

ull dp[maxn];

const ull b=1000000007;

void dfs(int u,int p)

{

	dp[u]=1;

	for(int i=0;i<g[u].size();i++)

	{

		int v=g[u][i];

		if(v==p)

		continue;

		dfs(v,u);

		dp[u]+=dp[v]*b;

	}

	ans+=m[dp[u]];

	m[dp[u]]++;

}

int main()

{

	int n;

	scanf("%d",&n);

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

	{

		int u,v;

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

		g[u].push_back(v);

		g[v].push_back(u);

	}

	dfs(1,-1);

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

	return 0;

}

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

using namespace std;



const int P = 1e9 + 7;

const int N = 110000;



int modExp(int a, int n, int p) {

	int ret = 1;

	for (; n; n >>= 1, a = 1LL * a * a % p) if (n & 1) ret = 1LL * ret * a % p;

	return ret;

}



long long ret;



int dp[N], pw[N], qw[N];

map<int, int> H;



long long sum;



vector<int> adj[N];



void dfs(int u, int p) {

	dp[u] = dp[p] + 1;

	ret = (ret + pw[dp[u]]) % P;

	int ans = (P - ret) % P;

	for (int v : adj[u]) {

		if (v == p) continue;

		dfs(v, u);

	}

	ans = (ans + ret) * 1LL * qw[dp[u]] % P;

	sum += H[ans];

	H[ans]++;

}



int main() {

	ios_base::sync_with_stdio(0);

	int n; cin >> n;

	for (int i = 0; i <= n; i++) pw[i] = (i == 0 ? 1 : pw[i - 1] * 1LL * 999983) % P;

	for (int i = 0; i <= n; i++) qw[i] = modExp(pw[i], P - 2, P);

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

		int u, v; cin >> u >> v;

		adj[u].push_back(v);

		adj[v].push_back(u);

	}

	dp[0] = -1;

	dfs(1, 0);

	cout << sum << endl;

	return 0;

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



using namespace std;

 

#define lli long long int

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

#define MOD 1000000007

#define NUM 2520

#define INF (1LL<<50)

#define DEBUG 1

#define mp(a,b) make_pair(a,b)

#define SORT(V) sort(V.begin(),V.end())

#define PI 3.14159265358979



signed main(){



	lli n,m;

	cin>>n>>m;



	vector<lli> x(m),y(m),z(m);

	map<lli,vector<lli>> d;



	REP(i,0,m){

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

		x[i]--,y[i]--;

		d[x[i]].push_back(y[i]);

		d[y[i]].push_back(x[i]);

	}



	lli data[100100]={0};

	lli cnt=1;

	REP(i,0,n){

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



		queue<lli> q;

		q.push(i);

		data[i] = cnt;

		while(q.size()){

			lli top = q.front();

			q.pop();

			for(auto e:d[top]){

				if(data[e]!=0)continue;

				data[e] = cnt;

				q.push(e);

			}

		}

		cnt++;

	}

	cout<<cnt-1<<endl;



	return 0;

}

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

using namespace std;



#define lli long long int

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

#define MOD 1000000007

#define NUM 2520

#define INF (1LL<<50)

#define DEBUG 0

#define mp(a,b) make_pair(a,b)

#define SORT(V) sort(V.begin(),V.end())

#define PI (3.141592653589794)



typedef struct UnionFind{

	vector<lli> par; //par[i]:iの親番号 par[3] = 2 : 3の親が2

	vector<lli> size;//size[i]:iの大きさ 自分のみのときは1,根っこにsizeを持たせる*/



	UnionFind(int N){/*最初はすべてが根であると初期化*/

		REP(i,0,N){

			par.push_back(i);

			size.push_back(1);

		}

	}



	lli root(lli x){/*データxが属する木の根を再起で得る root(x) = {xの木の根}}*/

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

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

	}



	void unite(lli x,lli y){/*xとyの併合*/

		lli rx = root(x);

		lli ry = root(y);

		if(rx == ry)return;

		par[rx] = ry; /*xとyの根が同じじゃない: xの根をrxをyの根ryに変更する */

		lli resize = size[rx] + size[ry];

		size[rx] = resize;

		size[ry] = resize;

	}



	bool same(lli x,lli y){

		lli rx = root(x);

		lli ry = root(y);

		return rx == ry;

	}



	lli getSize(lli x){

		lli rx = root(x);

		return size[rx];

	}

};



void func(long long N, long long M, std::vector<long long> X, std::vector<long long> Y, std::vector<long long> Z){

    UnionFind uf(N);



    REP(i,0,M){

        uf.unite(X[i],Y[i]);

    }



    set<lli> s;

    REP(i,0,N){

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

    }



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

}



int main(){

    // cout << fixed << setprecision(5);



    long long N;

    scanf("%lld",&N);

    long long M;

    scanf("%lld",&M);

    std::vector<long long> X(M);

    std::vector<long long> Y(M);

    std::vector<long long> Z(M);

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

        scanf("%lld",&X[i]);

        scanf("%lld",&Y[i]);

        scanf("%lld",&Z[i]);

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

    }

    func(N, M, std::move(X), std::move(Y), std::move(Z));

    return 0;

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

using namespace std;

struct Fast {Fast() {std::cin.tie(0); ios::sync_with_stdio(false);}} fast;

using ll = long long;

using vi = vector<int>;

using vvi = vector<vi>;

using pii = pair<int, int>;

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

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

#define pb push_back

#define mp make_pair

#define MOD 1000000007





vi G[100004];

vector<bool> seen(100004);





void dfs(int v) {

    seen[v] = true;



    for (auto next : G[v]) {

        if (seen[next]) continue;

        dfs(next);

    }



}



int main() {

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



    rep(i, M) {

        int a, b, c;

        cin >> a >> b >> c;

        G[a].push_back(b); //1-origin

        G[b].push_back(a);

    }



    seen.assign(N + 1, false);



    int ans = 0;



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

        if (seen[i]) continue;

        dfs(i);

        ans++;

    }



    cout << ans << endl;



}


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

using namespace std;

struct Fast {Fast() {std::cin.tie(0); ios::sync_with_stdio(false);}} fast;

using ll = long long;

using vi = vector<int>;

using vvi = vector<vi>;

using pii = pair<int, int>;

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

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

#define pb push_back

#define mp make_pair

#define MOD 1000000007



struct UnionFind {

    vector<int> par, rank;



    UnionFind(int n) : par(n , -1), rank(n, 0) { }

    void init(int n) { par.assign(n, -1), rank.assign(n, 0); }



    int root(int x) {

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

        else return par[x] = root(par[x]); //ここで経路圧縮

    }



    bool same(int x, int y) {

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

    }



    bool unite(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 tree(N);



    rep(i, M) {

        int a, b, c;

        cin >> a >> b >> c;

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

    }



    int ans = 0;



    rep(i, N) {

        if (tree.par[i] == -1) ans++;

    }



    cout << ans << endl;





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

#include <algorithm>

#include <iomanip>

#include <string>

#include <vector>

#include <math.h>

#include <queue>

#include <deque>

#include <map>

const int MOD = 1e9+7;

typedef long long ll;

using namespace std;



vector<int> graph[100001];

bool reached[100001];



void dfs(int x){

	reached[x] = true;

	for (auto y : graph[x]){

		if (!reached[y]){

			dfs(y);

		}

	}

	return;

}



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 (!reached[i]){

			dfs(i);

			ans++;

		}

	}

	cout << ans << endl;

	return 0;

}


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

#include <algorithm>

#include <iomanip>

#include <string>

#include <vector>

#include <math.h>

#include <queue>

#include <deque>

#include <stack>

#include <map>

const int MOD = 1e9+7;

#define PI 3.14159265359

typedef long long ll;

using namespace std;



int P[100010];

int used[100010];



void init(int N){ 

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

}



int root(int a){ 

	if (P[a] == a) return a; 

	return (P[a] = root(P[a])); 

}



bool is_same_set(int a, int b){ 

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

}



void unite(int a, int b){ 

	P[root(a)] = root(b);

}



int main(){

	int n, m;

	cin >> n >> m;

	init(n);

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

		int x, y, z;

		cin >> x >> y >> z;

		unite(x-1, y-1);

	}

	int ans = 0;

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

		if (!used[root(P[i])]){

			used[root(P[i])] = true;

			ans++;

		}

	}

	cout << ans << endl;

	return 0;

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

#define cout16 cout << setprecision(16) 

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

#define rep2(i,f,n) for(int i=f;i<n;i++ )

#define MAX(A) *max_element(A.begin(),A.end())

#define MIN(A) *min_element(A.begin(),A.end())

#define SORT(A) sort(A.begin(),A.end())

#define REV(A) reverse(A.begin(),A.end())

typedef long long int ll;

using vi = std::vector<int>;

using vvi = std::vector<std::vector<int>>;

using vll = std::vector<ll>;

using vvll = std::vector<std::vector<ll>>;

using P = std::pair<int,int>;

using vp = std::vector<P>;

using namespace std;

#define INF 1001001001

#define LL_INF 1001001001001001001



vi root(100005);

int find(int x){

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

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

}

bool same(int x, int y){

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

}	

void union_tree(int x,int y, int &n_trees){

	if(same(x,y)) return;

	int rt_x = root[x];

	int rt_y = root[y];	

	root[rt_y] = rt_x;

	n_trees--;

}



int main(void) {

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

	int n_trees = n;

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

	rep(i,m){

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

		x--; y--;

		union_tree(x,y,n_trees);

	}

	cout << n_trees << endl;

}






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

#define cout16 cout << setprecision(16) 

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

#define rep2(i,f,n) for(int i=f;i<n;i++ )

#define MAX(A) *max_element(A.begin(),A.end())

#define MIN(A) *min_element(A.begin(),A.end())

#define SORT(A) sort(A.begin(),A.end())

#define REV(A) reverse(A.begin(),A.end())

typedef long long int ll;

using vi = std::vector<int>;

using vvi = std::vector<std::vector<int>>;

using vll = std::vector<ll>;

using vvll = std::vector<std::vector<ll>>;

using P = std::pair<int,int>;

using vp = std::vector<P>;

using namespace std;

#define INF 1001001001

#define LL_INF 1001001001001001001



class UnionFindTrees{

	public:

		UnionFindTrees(int _n){

			n = _n;

			root = vector<int>(_n);

			rep(i,_n) root[i] = i;

		}

		int find(int x){

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

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

		}

		bool same(int x, int y){

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

		}

		void union_tree(int x, int y){

			if(same(x,y)) return;

			int rt_x = root[x];

			int rt_y = root[y];	

			root[rt_y] = rt_x;

			n--;			

		}

		int forest_size(){return n;}

	private:

		vector<int> root;

		int n;



};



int main(void) {

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

	UnionFindTrees uft(n);

	rep(i,m){

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

		x--; y--;

		uft.union_tree(x,y);

	}

	cout << uft.forest_size() << endl;

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

#define ll long long

#define ld long double

#pragma 03

using namespace std;

bool accessed[100005];

vector <int> adjacent[100005];

void dfs(int i){

	if (accessed[i]) return;

	accessed[i] = true;

	for (int j = 0; j<adjacent[i].size(); j++) dfs(adjacent[i][j]);

}

int main(){

	int n, m, x, y, z;

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

		accessed[i] = false;

		adjacent[i].clear();

	}

	cin >> n >> m;

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

		cin >> x >> y >> z;

		adjacent[x].push_back(y);

		adjacent[y].push_back(x);

	}

	int components = 0;

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

		if (!accessed[i]){

			dfs(i);

			components++;

		}

	}

	cout << components << endl;

	return 0;

}

// Faster C++ solution for the same problem (measured speedup: 3.758288890987838x):
#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);

	}

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

using namespace std;

const int N = 1e5 + 25, M = 1e6 + 25, oo = 1e9+7, mxmsk = 1 << 16;

const long long OO = 1e18+25;

    

#define f first

#define s second



int n, m, u, v,x,cnt, vis[N];

vector <int> g[N];



void visit_it(int node)

{

    if(vis[node]) return;

    vis[node] = 1;

    for(int to : g[node])

    {

        visit_it(to);

    }

}



int main() {

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

    while(m--)

    {

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

        g[u].push_back(v);

        g[v].push_back(u);

    }

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

    {

        if(vis[i]) continue;

        cnt++;

        visit_it(i);

    }

    printf("%d",cnt);

    return 0;

}

// Faster C++ solution for the same problem (measured speedup: 3.509365518520609x):
#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);

	}

}
// 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.971795459189457x):
#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);

	}

}
// Slower C++ solution:
#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;

}


// Faster C++ solution for the same problem (measured speedup: 3.641226452827273x):
#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);

	}

}
// Slower C++ solution:
#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;

  

}




// Faster C++ solution for the same problem (measured speedup: 3.9369510680223048x):
// 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;

  

}
// Slower C++ solution:
#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();

}


// Faster C++ solution for the same problem (measured speedup: 2.791050142855457x):
#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;

}