There are N cards placed face down in a row. On each card, an integer 1 or 2 is written.
Let A_i be the integer written on the i-th card.
Your objective is to guess A_1, A_2, ..., A_N correctly.
You know the following facts:
 - For each i = 1, 2, ..., M, the value A_{X_i} + A_{Y_i} + Z_i is an even number.
You are a magician and can use the following magic any number of times:
Magic: Choose one card and know the integer A_i written on it. The cost of using this magic is 1.
What is the minimum cost required to determine all of A_1, A_2, ..., A_N?
It is guaranteed that there is no contradiction in given input.

-----Constraints-----
 - All values in input are integers.
 - 2 \leq N \leq 10^5
 - 1 \leq M \leq 10^5
 - 1 \leq X_i < Y_i \leq N
 - 1 \leq Z_i \leq 100
 - The pairs (X_i, Y_i) are distinct.
 - There is no contradiction in input. (That is, there exist integers A_1, A_2, ..., A_N that satisfy the conditions.)

-----Input-----
Input is given from Standard Input in the following format:
N M
X_1 Y_1 Z_1
X_2 Y_2 Z_2
\vdots
X_M Y_M Z_M

-----Output-----
Print the minimum total cost required to determine all of A_1, A_2, ..., A_N.

-----Sample Input-----
3 1
1 2 1

-----Sample Output-----
2

You can determine all of A_1, A_2, A_3 by using the magic for the first and third cards.

Difficulty: MEDIUM

Solutions:
class UnionFind:

	def __init__(self, n):
		self.n = n
		self.parents = [-1] * n

	def find(self, x):
		if self.parents[x] < 0:
			return x
		else:
			self.parents[x] = self.find(self.parents[x])
			return self.parents[x]

	def union(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return
		if self.parents[x] > self.parents[y]:
			(x, y) = (y, x)
		self.parents[x] += self.parents[y]
		self.parents[y] = x

	def size(self, x):
		return -self.parents[self.find(x)]

	def same(self, x, y):
		return self.find(x) == self.find(y)

	def members(self, x):
		root = self.find(x)
		return [i for i in range(self.n) if self.find(i) == root]

	def roots(self):
		return [i for (i, x) in enumerate(self.parents) if x < 0]

	def group_count(self):
		return len(self.roots())

	def all_group_members(self):
		return {r: self.members(r) for r in self.roots()}

	def __str__(self):
		return '\n'.join(('{}: {}'.format(r, self.members(r)) for r in self.roots()))
(N, M) = map(int, input().split())
uf = UnionFind(N)
for _ in range(M):
	(X, Y, Z) = map(lambda x: int(x) - 1, input().split())
	uf.union(X, Y)
print(len(uf.roots()))


import sys
input = sys.stdin.readline
sys.setrecursionlimit(10 ** 7)
(n, m) = map(int, input().split())
F = [[] for _ in range(n)]
for _ in range(m):
	(x, y, z) = map(int, input().split())
	x -= 1
	y -= 1
	F[x].append(y)
	F[y].append(x)
seen = [False] * n

def dfs(v):
	seen[v] = True
	for nv in F[v]:
		if seen[nv]:
			continue
		dfs(nv)
ans = 0
for v in range(n):
	if not seen[v]:
		ans += 1
		dfs(v)
print(ans)


(n, m) = map(int, input().split())
xyz = [list(map(int, input().split())) for i in range(m)]
ans = [0 for i in range(n + 1)]
h = [[] for i in range(n + 1)]
for i in xyz:
	(x, y, z) = i
	h[x].append(y)
	h[y].append(x)
fa = 0
i = 1
while i <= n:
	if ans[i] == 0:
		q = [i]
		ans[i] = 1
		fa += 1
		while len(q) > 0:
			t = q.pop()
			for j in h[t]:
				if ans[j] == 0:
					q.append(j)
					ans[j] = 1
		i += 1
	else:
		i += 1
print(fa)


from collections import deque, Counter
from heapq import heappop, heappush
from bisect import bisect_right

class UnionFind:

	def __init__(self, n):
		self.parents = list(range(n))
		self.size = [1] * n

	def find(self, x):
		if self.parents[x] == x:
			return x
		else:
			self.parents[x] = self.find(self.parents[x])
			return self.parents[x]

	def union(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x != y:
			if self.size[x] < self.size[y]:
				(x, y) = (y, x)
			self.parents[y] = x
			self.size[x] += self.size[y]

def main():
	(N, M) = list(map(int, input().split()))
	uf = UnionFind(N)
	for _ in range(M):
		(X, Y, Z) = [int(x) - 1 for x in input().split()]
		uf.union(X, Y)
	ans = [uf.find(x) for x in uf.parents]
	print(len(set(ans)))

def __starting_point():
	main()
__starting_point()


(n, m) = list(map(int, input().split()))
import sys
sys.setrecursionlimit(10 ** 9)
root = [-1 for i in range(n + 1)]
dep = [1] * (n + 1)

def r(x):
	if root[x] < 0:
		return x
	else:
		root[x] = r(root[x])
		return root[x]

def unite(x, y):
	x = r(x)
	y = r(y)
	if x == y:
		return
	if dep[x] == dep[y]:
		dep[x] += 1
	if dep[x] < dep[y]:
		(x, y) = (y, x)
	root[x] += root[y]
	root[y] = x
for i in range(m):
	(x, y, z) = list(map(int, input().split()))
	unite(x, y)
g = [0] * (n + 1)
for i in range(1, n + 1):
	g[r(i)] += 1
ans = 0
for i in range(n + 1):
	if g[i] > 0:
		ans += 1
print(ans)


import sys
sys.setrecursionlimit(10 ** 9)
(n, m) = map(int, input().split())
rel = [[] for _ in range(n)]
for i in range(m):
	(x, y, z) = map(int, input().split())
	rel[x - 1].append(y - 1)
	rel[y - 1].append(x - 1)
ans = [-1] * n

def hoge(parent, pos):
	for i in rel[pos]:
		if ans[i] >= 0:
			continue
		ans[i] = pos
		hoge(pos, i)
	return
cnt = 0
for i in range(n):
	if ans[i] < 0:
		hoge(0, i)
		cnt += 1
print(cnt)


(n, m) = map(int, input().split())
uf = [-1] * n

def root(x):
	if uf[x] < 0:
		return x
	uf[x] = root(uf[x])
	return uf[x]

def unite(x, y):
	(rx, ry) = (root(x), root(y))
	if rx == ry:
		return False
	if uf[rx] > uf[ry]:
		(rx, ry) = (ry, rx)
	uf[rx] += uf[ry]
	uf[ry] = rx
	return True
for i in range(m):
	(x, y, z) = map(int, input().split())
	unite(x - 1, y - 1)
ans = 0
for i in range(n):
	if uf[i] < 0:
		ans += 1
print(ans)


class UnionFind:

	def __init__(self, n):
		self.n = n
		self.parents = [-1] * n

	def find(self, x):
		if self.parents[x] < 0:
			return x
		else:
			self.parents[x] = self.find(self.parents[x])
			return self.parents[x]

	def union(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return
		if self.parents[x] > self.parents[y]:
			(x, y) = (y, x)
		self.parents[x] += self.parents[y]
		self.parents[y] = x

	def members(self, x):
		root = self.find(x)
		return [i for i in range(self.n) if self.find(i) == root]

	def roots(self):
		return [i for (i, x) in enumerate(self.parents) if x < 0]

	def group_count(self):
		return len(self.roots())
(N, M) = list(map(int, input().split()))
u = UnionFind(N)
for i in range(M):
	(x, y, z) = list(map(int, input().split()))
	u.union(x - 1, y - 1)
print(u.group_count())


(N, M) = map(int, input().split())
graph = [[] for i in range(N)]
for i in range(M):
	(x, y, z) = map(int, input().split())
	(x, y) = (x - 1, y - 1)
	graph[x].append(y)
	graph[y].append(x)
visited = [False for i in range(N)]

def dfs(v):
	Q = []
	visited[v] = True
	Q.append(v)
	while len(Q) > 0:
		v = Q.pop()
		for u in graph[v]:
			if not visited[u]:
				visited[u] = True
				Q.append(u)
count = 0
for i in range(N):
	if not visited[i]:
		dfs(i)
		count += 1
print(count)


import sys
import itertools
import time
import math
sys.setrecursionlimit(10 ** 7)
from collections import defaultdict
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines
(N, M) = map(int, readline().split())
adj = [[] for _ in range(N)]
for i in range(M):
	(x, y, z) = map(int, readline().split())
	x -= 1
	y -= 1
	adj[x].append(y)
	adj[y].append(x)
visited = [False for _ in range(N)]

def dfs(v):
	if visited[v]:
		return False
	visited[v] = True
	for u in adj[v]:
		dfs(u)
	return True
ans = 0
for i in range(N):
	if dfs(i):
		ans += 1
print(ans)


ma = lambda : map(int, input().split())
lma = lambda : list(map(int, input().split()))
tma = lambda : tuple(map(int, input().split()))
ni = lambda : int(input())
yn = lambda fl: print('Yes') if fl else print('No')
import collections
import math
import itertools
import heapq as hq
ceil = math.ceil

class unionfind:

	def __init__(self, n):
		self.n = n
		self.par = list(range(n))
		self.size = [1] * n
		self.rank = [0] * n

	def root(self, x):
		if self.par[x] == x:
			return x
		else:
			self.par[x] = self.root(self.par[x])
			return self.par[x]

	def same(self, x, y):
		return self.root(x) == self.root(y)

	def unite(self, x, y):
		x = self.root(x)
		y = self.root(y)
		if x == y:
			return
		else:
			if self.rank[x] < self.rank[y]:
				(x, y) = (y, x)
			if self.rank[x] == self.rank[y]:
				self.rank[x] += 1
			self.par[y] = x
			self.size[x] += self.size[y]

	def get_size(self, x):
		x = self.root(x)
		return self.size[x]

	def parent_set(self):
		for x in range(self.n):
			self.root(x)
		s = set()
		for par in self.par:
			s.add(par)
		return s
(n, m) = ma()
uf = unionfind(n)
for i in range(m):
	(x, y, z) = ma()
	uf.unite(x - 1, y - 1)
s = uf.parent_set()
print(len(s))


import sys

def input():
	return sys.stdin.readline().rstrip()

class UnionFind:

	def __init__(self, n):
		self.n = n
		self.parents = [-1] * n

	def find(self, x):
		if self.parents[x] < 0:
			return x
		else:
			self.parents[x] = self.find(self.parents[x])
			return self.parents[x]

	def union(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return
		if self.parents[x] > self.parents[y]:
			(x, y) = (y, x)
		self.parents[x] += self.parents[y]
		self.parents[y] = x

	def size(self, x):
		return -self.parents[self.find(x)]

	def same(self, x, y):
		return self.find(x) == self.find(y)

	def members(self, x):
		root = self.find(x)
		return [i for i in range(self.n) if self.find(i) == root]

	def roots(self):
		return [i for (i, x) in enumerate(self.parents) if x < 0]

	def group_count(self):
		return len(self.roots())

	def all_group_members(self):
		return {r: self.members(r) for r in self.roots()}

	def __str__(self):
		return '\n'.join(('{}: {}'.format(r, self.members(r)) for r in self.roots()))

def main():
	(n, m) = map(int, input().split())
	uf = UnionFind(n)
	for _ in range(m):
		(x, y, z) = map(int, input().split())
		uf.union(x - 1, y - 1)
	print(uf.group_count())

def __starting_point():
	main()
__starting_point()


class UnionFind:

	def __init__(self, n):
		self.n = n
		self.root = [-1] * (n + 1)
		self.rnk = [0] * (n + 1)

	def Find_Root(self, x):
		if self.root[x] < 0:
			return x
		else:
			self.root[x] = self.Find_Root(self.root[x])
			return self.root[x]

	def Unite(self, x, y):
		x = self.Find_Root(x)
		y = self.Find_Root(y)
		if x == y:
			return
		elif self.rnk[x] > self.rnk[y]:
			self.root[x] += self.root[y]
			self.root[y] = x
		else:
			self.root[y] += self.root[x]
			self.root[x] = y
			if self.rnk[x] == self.rnk[y]:
				self.rnk[y] += 1

	def isSameGroup(self, x, y):
		return self.Find_Root(x) == self.Find_Root(y)

	def Count(self, x):
		return -self.root[self.Find_Root(x)]
(N, M) = map(int, input().split())
UN = UnionFind(N)
for _ in range(M):
	(s, t, u) = map(int, input().split())
	UN.Unite(s, t)
ans = 0
for i in UN.root:
	if i < 0:
		ans += 1
print(ans - 1)


import sys
sys.setrecursionlimit(100000000)
(N, M) = map(int, input().split())
visited = [False for i in range(N)]
v_to = [[] for i in range(N)]
for i in range(M):
	(X, Y, Z) = map(int, input().split())
	v_to[X - 1].append(Y - 1)
	v_to[Y - 1].append(X - 1)

def dfs(i):
	if visited[i]:
		return 0
	visited[i] = True
	for to in v_to[i]:
		dfs(to)
	return 1
ans = 0
for i in range(N):
	ans += dfs(i)
print(ans)


(N, M) = map(int, input().split())
lst = [i for i in range(N)]

def root(n):
	if n == lst[n]:
		return n
	lst[n] = root(lst[n])
	return lst[n]

def union(x, y):
	(rootX, rootY) = (root(x), root(y))
	if rootX != rootY:
		if rootX > rootY:
			lst[rootX] = rootY
		if rootY > rootX:
			lst[rootY] = rootX
for i in range(M):
	(X, Y, Z) = map(int, input().split())
	X -= 1
	Y -= 1
	union(X, Y)
ans = len([i for i in range(N) if root(i) == i])
print(ans)


def solve(string):
	(n, m, *xyz) = map(int, string.split())
	t = [-1] * (n + 1)

	def union(r1, r2):
		if r1 != r2:
			t[max(r1, r2)] = min(r1, r2)

	def find(x):
		if t[x] < 0:
			return x
		t[x] = find(t[x])
		return t[x]
	for (x, y, _) in zip(*[iter(xyz)] * 3):
		union(find(x), find(y))
	return str(t.count(-1) - 1)
(n, m) = map(int, input().split())
print(solve('{} {}\n'.format(n, m) + '\n'.join([input() for _ in range(m)])))


(N, M) = map(int, input().split())
par = [i for i in range(N + 1)]
size = [1 for _ in range(N + 1)]

def find(x):
	if par[x] == x:
		return x
	else:
		par[x] = find(par[x])
		return par[x]

def unite(x, y):
	x = find(x)
	y = find(y)
	if x == y:
		return 0
	par[x] = y
	size[y] = size[x] + size[y]
	size[x] = 0
for i in range(M):
	(x, y, z) = map(int, input().split())
	unite(x, y)
Ans = 0
for j in size[1:]:
	if j != 0:
		Ans += 1
print(Ans)


from collections import defaultdict
(N, M) = map(int, input().split())
D = defaultdict(list)
S = [0 for i in range(N)]
for i in range(M):
	(x, y, z) = map(int, input().split())
	D[x].append(y)
	D[y].append(x)
ans = 0
for i in range(N):
	if S[i] > 0:
		continue
	T = [i + 1]
	S[i] = 1
	ans += 1
	while T:
		n = T.pop()
		for d in D[n]:
			if S[d - 1] > 0:
				continue
			else:
				S[d - 1] = 1
			T.append(d)
print(ans)


import sys
sys.setrecursionlimit(10 ** 7)
(n, m) = map(int, input().split())
f = [False for _ in range(n)]
a = [[] for _ in range(n)]
res = 0

def dfs(k):
	f[k] = True
	for g in a[k]:
		if not f[g]:
			dfs(g)
for _ in range(m):
	(x, y, z) = map(int, input().split())
	a[x - 1].append(y - 1)
	a[y - 1].append(x - 1)
for i in range(n):
	if not f[i]:
		res += 1
		dfs(i)
print(res)


(n, m) = map(int, input().split())
graph = [[] for i in range(n)]
for i in range(m):
	(x, y, z) = map(int, input().split())
	graph[x - 1].append(y - 1)
	graph[y - 1].append(x - 1)
check = [True] * n
count = 0
for i in range(n):
	if check[i]:
		count += 1
		stack = []
		stack.append(i)
		check[i] = False
		while stack:
			p = stack.pop()
			for j in graph[p]:
				if check[j]:
					stack.append(j)
					check[j] = False
	else:
		continue
print(count)


import sys
input = sys.stdin.readline
(N, M) = map(int, input().split())
XYZ = [list(map(int, input().split())) for i in range(M)]
Group = [i for i in range(N + 1)]

def find(x):
	while Group[x] != x:
		x = Group[x]
	return x

def Union(x, y):
	if find(x) != find(y):
		Group[find(y)] = Group[find(x)] = min(find(y), find(x))
for (x, y, z) in XYZ:
	Union(x, y)
ANS = [find(i) for i in range(1, N + 1)]
print(len(set(ANS)))


(n, m) = map(int, input().split())
w = [i for i in range(n + 1)]
s = [1] * (n + 1)

def root(x):
	if w[x] == x:
		return x
	x = w[x]
	return root(w[x])

def unite(x, y):
	x = root(x)
	y = root(y)
	if x != y:
		if s[x] < s[y]:
			w[x] = y
			s[y] += 1
		else:
			w[y] = x
			s[x] += 1
for i in range(m):
	(x, y) = list(map(int, input().split()))[:2]
	unite(x, y)
go = set()
for i in range(1, n + 1):
	go.add(root(i))
print(len(go))


from collections import Counter
(n, m) = map(int, input().split())

class UnionFind:

	def __init__(self, n):
		self.par = [i for i in range(n)]
		self.rank = [0] * n
		self.size = [1] * n

	def find(self, x):
		if self.par[x] == x:
			return x
		else:
			self.par[x] = self.find(self.par[x])
			return self.par[x]

	def union(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return
		if self.rank[x] < self.rank[y]:
			self.par[x] = y
			self.size[y] += self.size[x]
		else:
			self.par[y] = x
			self.size[x] += self.size[y]
			if self.rank[x] == self.rank[y]:
				self.rank[x] += 1

	def same(self, x, y):
		return self.find(x) == self.find(y)

	def all_find(self):
		for n in range(len(self.par)):
			self.find(n)
uf = UnionFind(n)
for _ in range(m):
	(x, y, z) = map(int, input().split())
	x -= 1
	y -= 1
	uf.union(x, y)
root = set([])
for i in range(n):
	root.add(uf.find(i))
print(len(root))


(n, m) = (int(i) for i in input().split())
(par, rank, q) = ([i for i in range(n + 1)], [0 for i in range(n + 1)], set())

def root(x):
	if par[x] != x:
		par[x] = root(par[x])
	return par[x]

def unite(x, y):
	(x2, y2) = (root(x), root(y))
	if x2 != y2:
		if rank[x2] < rank[y2]:
			par[x2] = y2
		else:
			par[y2] = x2
		if rank[x2] == rank[y2]:
			rank[x2] += 1
for i in range(m):
	(x, y, z) = (int(i) for i in input().split())
	unite(x, y)
for i in range(1, n + 1):
	q.add(root(i))
print(len(q))


def find(x):
	while G[x][0] != x:
		x = G[x][0]
	return x

def union(x, y):
	xa = find(x)
	ya = find(y)
	if G[xa][1] >= G[ya][1]:
		G[ya][0] = xa
		G[xa][1] = max(G[xa][1], G[ya][1] + 1)
	else:
		G[xa][0] = ya
		G[ya][1] = max(G[ya][1], G[xa][1] + 1)
(N, M) = map(int, input().split())
G = {i: [i, 0] for i in range(1, N + 1)}
for _ in range(M):
	(x, y, z) = map(int, input().split())
	union(x, y)
hist = [0 for _ in range(N + 1)]
for i in range(1, N + 1):
	x = find(i)
	hist[x] = 1
print(sum(hist))


(N, M) = map(int, input().split())
p = [i for i in range(N)]
g = [[i] for i in range(N)]
for _ in range(M):
	(x, y, z) = map(int, input().split())
	(x, y) = (p[x - 1], p[y - 1])
	if x == y:
		continue
	if len(g[x]) < len(g[y]):
		(x, y) = (y, x)
	g[x] += g[y]
	for z in g[y]:
		p[z] = x
	g[y] = []
print(len(set(p)))


(n, m) = map(int, input().split())
xy = [i for i in range(n + 1)]

def root(x):
	i = x
	while i != xy[i]:
		i = xy[i]
	xy[x] = i
	return i
for _ in range(m):
	(x, y) = map(int, input().split()[:2])
	xy[root(x)] = root(y)
print(sum((i == v for (i, v) in enumerate(xy))) - 1)


import sys, collections
stdin = sys.stdin
(n, m) = map(int, stdin.readline().split())
par = [i for i in range(n)]
size = [1] * n
rank = [1] * n

def find(x, par):
	if par[x] == x:
		return x
	else:
		return find(par[x], par)

def unite(x, y):
	x = find(x, par)
	y = find(y, par)
	if x != y:
		if rank[x] < rank[y]:
			par[x] = y
			size[y] += size[x]
		else:
			par[y] = x
			size[x] += size[y]
			if rank[x] == rank[y]:
				rank[x] += 1
for _ in range(m):
	(x, y, z) = map(int, stdin.readline().split())
	unite(x - 1, y - 1)
ans = set()
for i in range(n):
	ans.add(find(i, par))
print(len(ans))


import sys
sys.setrecursionlimit(10000000)

def visit_tree(now, num):
	visited[now] = num
	for i in range(len(tree[now])):
		if not visited[tree[now][i]]:
			visit_tree(tree[now][i], num)
(n, m) = map(int, input().split())
tree = [[] for _ in range(n)]
for i in range(m):
	(x, y, z) = map(int, input().split())
	tree[x - 1].append(y - 1)
	tree[y - 1].append(x - 1)
visited = [0 for _ in range(n)]
num = 0
for i in range(n):
	if not visited[i]:
		num += 1
		visit_tree(i, num)
print(num)


(n, m) = map(int, input().split())
par = [i for i in range(n + 1)]
rank = [0] * (n + 1)

def find(x):
	if par[x] == x:
		return x
	return find(par[x])

def unite(x, y):
	root_x = find(x)
	root_y = find(y)
	if rank[root_x] != rank[root_y]:
		par[min(root_x, root_y)] = max(root_x, root_y)
	else:
		par[root_y] = root_x
		rank[root_x] += 1
for i in range(m):
	(x, y, z) = map(int, input().split())
	unite(x, y)
roo = [-1]
for i in range(n):
	roo.append(find(i + 1))
print(len(set(roo)) - 1)


(N, M) = (int(i) for i in input().split())
uf = [-1] * N

def parent(v):
	if uf[v] < 0:
		return v
	else:
		uf[v] = parent(uf[v])
		return uf[v]

def size(v):
	return -uf[parent(v)]

def union(u, v):
	pu = parent(u)
	pv = parent(v)
	if pu != pv:
		res = uf[pv] * uf[pu]
		uf[pv] += uf[pu]
		uf[pu] = pv
	else:
		res = 0
	return res
for i in range(M):
	(X, Y, Z) = (int(i) for i in input().split())
	union(X - 1, Y - 1)
ans = 0
for i in range(N):
	if uf[i] < 0:
		ans += 1
print(ans)


import bisect, collections, copy, heapq, itertools, math, string, sys
input = lambda : sys.stdin.readline().rstrip()
sys.setrecursionlimit(10 ** 7)
INF = float('inf')

def I():
	return int(input())

def F():
	return float(input())

def SS():
	return input()

def LI():
	return [int(x) for x in input().split()]

def LI_():
	return [int(x) - 1 for x in input().split()]

def LF():
	return [float(x) for x in input().split()]

def LSS():
	return input().split()

def resolve():
	(N, M) = LI()
	G = collections.defaultdict(list)
	for _ in range(M):
		(X, Y, _) = LI_()
		G[X].append(Y)
		G[Y].append(X)
	visited = [False] * N

	def dfs(c):
		visited[c] = True
		for n in G[c]:
			if not visited[n]:
				dfs(n)
	ans = [0]
	for i in range(N):
		if not visited[i]:
			dfs(i)
			ans[0] += 1
	print(ans[0])

def __starting_point():
	resolve()
__starting_point()


class UnionFind:

	def __init__(self, N):
		self.root = [-1 for _ in range(N)]
		self.size = [1 for _ in range(N)]

	def find(self, x):
		while self.root[x] >= 0:
			x = self.root[x]
		return x

	def union(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return
		if self.size[x] < self.size[y]:
			self.root[x] = y
			self.size[y] += self.size[x]
		else:
			self.root[y] = x
			self.size[x] += self.size[y]
(N, M) = [int(_) for _ in input().split()]
uf = UnionFind(N)
for i in range(M):
	(X, Y, Z) = [int(_) for _ in input().split()]
	uf.union(X - 1, Y - 1)
ans = set()
for i in range(N):
	ans.add(uf.find(i))
print(len(ans))


class Unionfind:

	def __init__(self, n):
		self.n = n
		self.parents = [-1] * n

	def find(self, x):
		if self.parents[x] < 0:
			return x
		else:
			self.parents[x] = self.find(self.parents[x])
			return self.parents[x]

	def union(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return
		if self.parents[x] > self.parents[y]:
			(x, y) = (y, x)
		self.parents[x] += self.parents[y]
		self.parents[y] = x

	def roots(self):
		return [i for (i, x) in enumerate(self.parents) if x < 0]
(n, m) = list(map(int, input().split()))
xyz = sorted([list(map(int, input().split())) for _ in range(m)])
uf = Unionfind(n)
for (x, y, z) in xyz:
	uf.union(x - 1, y - 1)
print(len(uf.roots()))


class UnionFind:

	def __init__(self, n):
		self.n = n
		self.parents = [-1] * n

	def find(self, x):
		if self.parents[x] < 0:
			return x
		else:
			self.parents[x] = self.find(self.parents[x])
			return self.parents[x]

	def union(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return
		if self.parents[x] > self.parents[y]:
			(x, y) = (y, x)
		self.parents[x] += self.parents[y]
		self.parents[y] = x

	def size(self, x):
		return -self.parents[self.find(x)]

	def same(self, x, y):
		return self.find(x) == self.find(y)

	def members(self, x):
		root = self.find(x)
		return [i for i in range(self.n) if self.find(i) == root]

	def roots(self):
		return [i for (i, x) in enumerate(self.parents) if x < 0]

	def group_count(self):
		return len(self.roots())

	def all_group_members(self):
		return {r: self.members(r) for r in self.roots()}

	def __str__(self):
		return '\n'.join(('{}: {}'.format(r, self.members(r)) for r in self.roots()))
(n, m) = map(int, input().split())
a = [list(map(int, input().split())) for i in range(m)]
u = UnionFind(n)
for i in range(m):
	u.union(a[i][0] - 1, a[i][1] - 1)
print(u.group_count())


(n, m) = map(int, input().split())
par = [-1] * (n + 1)

def find(a):
	if par[a] < 0:
		return a
	else:
		par[a] = find(par[a])
		return par[a]

def unite(a, b):
	a = find(a)
	b = find(b)
	if a == b:
		return False
	else:
		if par[a] < par[b]:
			(a, b) = (b, a)
		par[a] += par[b]
		par[b] = a
		return True
for i in range(m):
	(x, y, z) = map(int, input().split())
	unite(x, y)
cnt = 0
for i in range(n):
	if par[i + 1] < 0:
		cnt += 1
print(cnt)


(n, m) = map(int, input().split())

class UnionFind:
	__slots__ = ['_size', '_first_idx', '_parents']

	def __init__(self, size: int, first_index: int=0) -> None:
		self._size = size
		self._first_idx = first_index
		self._parents = [-1] * (size + first_index)

	def find(self, x: int) -> int:
		if self._parents[x] < 0:
			return x
		self._parents[x] = self.find(self._parents[x])
		return self._parents[x]

	def same(self, x: int, y: int) -> bool:
		return self.find(x) == self.find(y)

	def unite(self, x: int, y: int) -> bool:
		(x, y) = (self.find(x), self.find(y))
		if x == y:
			return False
		if self._parents[x] > self._parents[y]:
			(x, y) = (y, x)
		self._parents[x] += self._parents[y]
		self._parents[y] = x
		return True

	def size(self, x: int) -> int:
		return -self._parents[self.find(x)]

	def group_count(self) -> int:
		return sum([1 for i in self._parents if i < 0]) - self._first_idx

	def connected(self) -> bool:
		return self._parents[self.find(self._first_idx)] == -self._size
uf = UnionFind(n, 1)
for i in range(m):
	(x, y, z) = map(int, input().split())
	uf.unite(x, y)
print(uf.group_count())


from sys import setrecursionlimit

def find(parent, i):
	t = parent[i]
	if t < 0:
		return i
	t = find(parent, t)
	parent[i] = t
	return t

def unite(parent, i, j):
	i = find(parent, i)
	j = find(parent, j)
	if i == j:
		return
	parent[j] += parent[i]
	parent[i] = j
setrecursionlimit(10 ** 5)
(N, M) = map(int, input().split())
parent = [-1] * N
for _ in range(M):
	(X, Y, Z) = map(int, input().split())
	unite(parent, X - 1, Y - 1)
print(len([x for x in parent if x < 0]))


class UnionFind:

	def __init__(self, n):
		self.n = n
		self.parents = [i for i in range(n)]
		self.ranks = [0 for _ in range(n)]

	def root(self, node):
		parent_node = self.parents[node]
		if parent_node == node:
			return node
		root_node = self.root(parent_node)
		self.parents[node] = root_node
		return root_node

	def union(self, one_node, other_node):
		one_root = self.root(one_node)
		other_root = self.root(other_node)
		if one_root == other_root:
			return
		if self.ranks[one_root] < self.ranks[other_root]:
			self.parents[one_root] = other_root
		else:
			self.parents[other_root] = one_root
			if self.ranks[one_root] == self.ranks[other_root]:
				self.ranks[one_root] += 1

def main():
	(N, M) = list(map(int, input().split(' ')))
	tree = UnionFind(N)
	for _ in range(M):
		(x, y, _) = list(map(int, input().split(' ')))
		tree.union(x - 1, y - 1)
	roots = list(map(lambda n: tree.root(n), range(N)))
	print(len(set(roots)))

def __starting_point():
	main()
__starting_point()


import sys
sys.setrecursionlimit(500 * 500)
(N, M) = map(int, input().split())
Q = [list(map(int, input().split())) for _ in range(M)]
C = [[] for _ in range(N + 1)]
count = 0
for q in Q:
	X = q[0]
	Y = q[1]
	C[X].append(Y)
	C[Y].append(X)
flag = [-1] * (N + 1)
flag[1] = 0

def dfs(s):
	global count
	for c in C[s]:
		flag[s] = 0
		if flag[c] == -1:
			flag[c] = 0
			count += 1
			dfs(c)
for i in range(1, N + 1):
	dfs(i)
print(N - count)


import sys
sys.setrecursionlimit(10 ** 6)

def f(j):
	nodes[j] = 1
	for k in links[j]:
		if nodes[k] == 0:
			f(k)
(N, M) = map(int, input().split())
XYZ = [list(map(int, input().split())) for _ in range(M)]
links = [[] for _ in range(N + 1)]
for i in range(M):
	links[XYZ[i][0]].append(XYZ[i][1])
	links[XYZ[i][1]].append(XYZ[i][0])
nodes = [0] * (N + 1)
ans = 0
for i in range(1, N + 1):
	if nodes[i] == 0:
		ans += 1
		nodes[i] = 1
		for j in links[i]:
			f(j)
print(ans)


import sys
sys.setrecursionlimit(10 ** 5)
input = sys.stdin.readline
(N, M) = map(int, input().split())
ans = list(range(N))

def root(a):
	if a == ans[a]:
		return a
	else:
		ans[a] = root(ans[a])
		return ans[a]
for _ in range(M):
	(x, y, _) = map(lambda a: int(a) - 1, input().split())
	(rx, ry) = (root(x), root(y))
	if rx != ry:
		ans[ry] = rx
count = 0
for (i, a) in enumerate(ans):
	count += i == a
print(count)


import sys
(N, M) = map(int, input().split())
G = {k: [] for k in range(N)}
for _ in range(M):
	(X, Y, Z) = map(int, input().split())
	G[X - 1].append(Y - 1)
	G[Y - 1].append(X - 1)
visited = [False] * N
sys.setrecursionlimit(1000000)

def dfs(ci):
	for ni in G[ci]:
		if visited[ni] is True:
			continue
		visited[ni] = True
		dfs(ni)
ans = 0
for i in range(N):
	if visited[i] is False:
		ans += 1
		visited[i] = True
		dfs(i)
print(ans)


(n, m) = map(int, input().split())
xy = [list(map(int, input().split())) for _ in range(m)]
ans = [1] * n
a = list(range(n))

def find(a, x):
	if a[x] != x:
		a[x] = find(a, a[x])
	return a[x]

def unite(a, x, y):
	x = find(a, x)
	y = find(a, y)
	if x != y:
		a[x] = min(x, y)
		a[y] = a[x]
for (i, j, k) in xy:
	unite(a, i - 1, j - 1)
q = []
for i in range(n):
	p = find(a, i)
	q.append(p)
print(len(set(q)))


class UnionFind:

	def __init__(self, n):
		self.n = n
		self.root = [-1] * (n + 1)

	def find(self, x):
		if self.root[x] < 0:
			return x
		else:
			self.root[x] = self.find(self.root[x])
			return self.root[x]

	def unite(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return False
		if self.root[x] > self.root[y]:
			(x, y) = (y, x)
		self.root[x] += self.root[y]
		self.root[y] = x

	def is_same(self, x, y):
		return self.find(x) == self.find(y)

	def size(self, x):
		return -self.root[self.find(x)]
(n, m) = map(int, input().split())
cards = UnionFind(n)
for i in range(m):
	(x, y, z) = map(int, input().split())
	cards.unite(x, y)
print(sum((cards.find(i) == i for i in range(1, n + 1))))


def abc126_e():
	(n, m) = map(int, input().split())
	par = [x for x in range(n)]
	rank = [0] * n

	def find(x):
		if par[x] == x:
			return x
		else:
			par[x] = find(par[x])
			return par[x]

	def unite(x, y):
		x = find(x)
		y = find(y)
		if x == y:
			return
		if rank[x] < rank[y]:
			par[x] = y
		else:
			par[y] = x
			if rank[x] == rank[y]:
				rank[x] += 1
	for _ in range(m):
		(x, y, z) = map(int, input().split())
		unite(x - 1, y - 1)
	for i in range(n):
		_ = find(i)
	ans = len(set(par))
	print(ans)

def __starting_point():
	abc126_e()
__starting_point()


import sys
sys.setrecursionlimit(10 ** 7)

def dfs(G, v):
	seen[v] = True
	for next_v in G[v]:
		if seen[next_v]:
			continue
		dfs(G, next_v)
(N, M) = map(int, input().split())
G = [[] for _ in range(N)]
seen = [False] * N
cnt = 0
for i in range(M):
	(x, y, z) = map(int, input().split())
	G[x - 1].append(y - 1)
	G[y - 1].append(x - 1)
for v in range(N):
	if seen[v]:
		continue
	dfs(G, v)
	cnt += 1
print(cnt)


(N, M) = list(map(int, input().split()))
par = [-1] * N

def find(x):
	if par[x] < 0:
		return x
	else:
		par[x] = find(par[x])
		return par[x]

def union(x, y):
	(p, q) = (find(x), find(y))
	if p == q:
		return
	if p > q:
		(p, q) = (q, p)
	par[p] += par[q]
	par[q] = p
for _ in range(M):
	(X, Y, _) = list(map(int, input().split()))
	(X, Y) = (X - 1, Y - 1)
	union(X, Y)
ans = 0
for i in range(N):
	if par[i] < 0:
		ans += 1
print(ans)


(N, M) = map(int, input().split())
edge = [list(map(int, input().split())) for i in range(M)]
c = [[] for i in range(N)]
for (i, j, w) in edge:
	c[i - 1].append(j - 1)
	c[j - 1].append(i - 1)
a = 0
v = [0] * N
import sys
sys.setrecursionlimit(10 ** 6)

def dfs(c, v, p):
	v[p] = 1
	for n in c[p]:
		if v[n] == 0:
			dfs(c, v, n)
for i in range(N):
	if v[i] == 1:
		continue
	dfs(c, v, i)
	a += 1
print(a)


from collections import deque
(N, M) = map(int, input().split())
edge = [[] for i in range(N)]
for i in range(M):
	(x, y, _) = map(int, input().split())
	edge[x - 1].append(y - 1)
	edge[y - 1].append(x - 1)
visited = [False] * N
ans = 0
for i in range(N):
	if visited[i]:
		continue
	else:
		ans += 1
	q = deque([i])
	while q:
		cur = q.pop()
		visited[cur] = True
		for next in edge[cur]:
			if visited[next]:
				continue
			visited[next] = True
			q.append(next)
print(ans)


import collections
(n, m) = list(map(int, input().split()))
checked = [False] * n
way = [[] for i in range(n)]
for i in range(m):
	(x, y, z) = list(map(int, input().split()))
	x -= 1
	y -= 1
	way[x].append(y)
	way[y].append(x)
ans = 0
for i in range(n):
	if checked[i] == False:
		q = collections.deque()
		q.append(i)
		while len(q) > 0:
			c = q.popleft()
			for i in way[c]:
				if not checked[i]:
					checked[i] = True
					q.append(i)
		ans += 1
print(ans)


(n, m) = map(int, input().split())
parent = [i for i in range(n + 1)]
rank = [0] * (n + 1)
s = set()

def find(x):
	if parent[x] == x:
		return x
	else:
		parent[x] = find(parent[x])
		return parent[x]

def union(x, y):
	x = find(x)
	y = find(y)
	if rank[x] < rank[y]:
		parent[x] = y
	else:
		parent[y] = x
		if rank[x] == rank[y]:
			rank[x] += 1
for i in range(m):
	(x, y, z) = map(int, input().split())
	union(x, y)
for i in range(1, n + 1):
	s.add(find(i))
print(len(s))


import sys
sys.setrecursionlimit(1000000)
(n, m) = map(int, input().split())
lb = [0 for i in range(n)]
l = [[] for i in range(n + 1)]
for i in range(m):
	(x, y, z) = map(int, input().split())
	l[x].append(y)
	l[y].append(x)

def dfs(a, num):
	if lb[a - 1] != 0:
		pass
	else:
		lb[a - 1] = num
		for i in l[a]:
			dfs(i, num)
	return None
for i in range(n):
	dfs(i + 1, i + 1)
count = 0
laa = [0 for i in range(n + 1)]
for i in range(n):
	if lb[i] == 0:
		count += 1
	elif laa[lb[i]] == 0:
		count += 1
		laa[lb[i]] = 1
	else:
		pass
print(count)


from collections import defaultdict
(N, M) = list(map(int, input().split()))
edges = defaultdict(list)
for _ in range(M):
	(x, y, z) = list(map(int, input().split()))
	x -= 1
	y -= 1
	edges[x].append(y)
	edges[y].append(x)
is_visited = [False] * N

def dfs(i):
	stack = [i]
	while stack:
		i = stack.pop()
		if is_visited[i]:
			continue
		is_visited[i] = True
		for j in edges[i]:
			stack.append(j)
islands = 0
for i in range(N):
	if is_visited[i] == False:
		islands += 1
		dfs(i)
print(islands)


import bisect
import sys
input = sys.stdin.readline
(n, m) = map(int, input().split())
par = [-1] * n

def find(x):
	if par[x] < 0:
		return x
	else:
		par[x] = find(par[x])
		return par[x]

def unite(x, y):
	x = find(x)
	y = find(y)
	if x == y:
		return False
	else:
		if par[x] > par[y]:
			(x, y) = (y, x)
		par[x] += par[y]
		par[y] = x
		return True

def same(x, y):
	return find(x) == find(y)

def size(x):
	return -par[find(x)]
for i in range(m):
	(x, y, z) = map(int, input().split())
	unite(x - 1, y - 1)
par.sort()
print(bisect.bisect_left(par, 0))


(n, m) = map(int, input().split())
tree = [-i for i in range(n + 1)]
for _i in range(m):
	(x, y, z) = map(int, input().split())
	while tree[x] > 0:
		x = tree[x]
	while tree[y] > 0:
		y = tree[y]
	(x, y) = sorted([x, y])
	if x == y:
		continue
	else:
		tree[y] = x
print(sum((1 for i in tree if i < 0)))


from collections import deque
(n, m) = map(int, input().split())
e = [[] for i in range(n)]
l = [-1] * n
for i in range(m):
	(a, b, c) = map(int, input().split())
	e[a - 1].append(b - 1)
	e[b - 1].append(a - 1)

def dfs(x, count):
	l[x] = count
	q = deque([])
	q.append(x)
	while q:
		bef = q.popleft()
		for nex in e[bef]:
			if l[nex] == -1:
				l[nex] = count
				q.append(nex)
count = 0
for i in range(n):
	if l[i] == -1 and e[i]:
		dfs(i, count)
		count += 1
print(count + l.count(-1))


(N, M) = list(map(int, input().split()))
root = [i for i in range(N)]
height = [0] * N

def find(a):
	f = a
	if a == root[a]:
		return a
	while a != root[a]:
		a = root[a]
	root[f] = a
	return a

def union(a, b):
	A = find(a)
	B = find(b)
	if A == B:
		return
	if height[A] > height[B]:
		root[B] = root[A]
	else:
		root[A] = root[B]
		if height[A] == height[B]:
			height[B] += 1
for i in range(M):
	(a, b, c) = map(int, input().split())
	a -= 1
	b -= 1
	union(a, b)
l = [0] * N
for j in range(N):
	l[find(j)] += 1
print(N - l.count(0))


import sys
sys.setrecursionlimit(10 ** 7)

def dfs(s):
	if visited[s]:
		return
	visited[s] = 1
	for to in t[s]:
		if visited[to]:
			continue
		dfs(to)
(N, M) = map(int, input().split())
t = [[] for _ in range(N)]
visited = [0] * N
for _ in range(M):
	(X, Y, Z) = map(int, input().split())
	X -= 1
	Y -= 1
	t[X].append(Y)
	t[Y].append(X)
ans = 0
for i in range(0, N):
	if visited[i]:
		continue
	ans += 1
	dfs(i)
print(ans)


(N, M) = map(int, input().split())
nlist = [] * N
for i in range(N):
	nlist.append([])
for i in range(M):
	(X, Y, Z) = map(int, input().split())
	X -= 1
	Y -= 1
	nlist[X].append(Y)
	nlist[Y].append(X)
visit = [False] * N
ans = 0
for i in range(N):
	if visit[i]:
		continue
	ans += 1
	visit[i] = True
	vlist = nlist[i]
	while vlist:
		tmp = []
		for to in vlist:
			if visit[to]:
				continue
			visit[to] = True
			tmp.extend(nlist[to])
		vlist = tmp
print(ans)


(N, M) = map(int, input().split())
tree = [-1 for i in range(N)]

def root(x):
	if tree[x] < 0:
		return x
	tree[x] = root(tree[x])
	return tree[x]

def find(x, y):
	return root(x) == root(y)

def union(x, y):
	x = root(x)
	y = root(y)
	if x != y:
		if tree[x] < tree[y]:
			(x, y) = (y, x)
		tree[x] += tree[y]
		tree[y] = x
		return 1
	return 0
cnt = 0
for i in range(M):
	(x, y, z) = map(int, input().split())
	cnt += union(x - 1, y - 1)
print(N - cnt)


import sys
sys.setrecursionlimit(10 ** 9)

class UnionFind:

	def __init__(self, n):
		self.n = [-1] * n
		self.r = [0] * n
		self.siz = n

	def find_root(self, x):
		if self.n[x] < 0:
			return x
		else:
			self.n[x] = self.find_root(self.n[x])
			return self.n[x]

	def unite(self, x, y):
		x = self.find_root(x)
		y = self.find_root(y)
		if x == y:
			return
		elif self.r[x] > self.r[y]:
			self.n[x] += self.n[y]
			self.n[y] = x
		else:
			self.n[y] += self.n[x]
			self.n[x] = y
			if self.r[x] == self.r[y]:
				self.r[y] += 1
		self.siz -= 1

	def root_same(self, x, y):
		return self.find_root(x) == self.find_root(y)

	def count(self, x):
		return -self.n[self.find_root(x)]

	def size(self):
		return self.siz
(n, m) = map(int, input().split())
uf = UnionFind(n)
for i in range(m):
	(x, y, z) = map(int, input().split())
	uf.unite(x - 1, y - 1)
print(uf.size())


from collections import defaultdict, deque
(N, M) = map(int, input().split())
E = defaultdict(list)
for i in range(M):
	(x, y, z) = map(int, input().split())
	E[x - 1].append(y - 1)
	E[y - 1].append(x - 1)
visited = [False] * N
ans = 0
q = deque()
for i in range(N):
	if not visited[i]:
		ans += 1
		visited[i] = True
		q.append(i)
		while q:
			nxt = q.pop()
			for j in E[nxt]:
				if not visited[j]:
					visited[j] = True
					q.append(j)
print(ans)


(n, m) = map(int, input().split())
g = [[] for i in range(n)]
for i in range(m):
	(u, v, z) = map(int, input().split())
	g[u - 1].append((u - 1, v - 1, z))
	g[v - 1].append((v - 1, u - 1, z))
count = 0
renketu_list = [-1] * n
stack = []
for i in range(n):
	if renketu_list[i] == -1:
		count += 1
		renketu_list[i] = count
		while len(g[i]) > 0:
			stack.append(g[i].pop())
		while len(stack) > 0:
			(u, v, z) = stack.pop()
			if renketu_list[v] == -1:
				renketu_list[v] = count
				while len(g[v]) > 0:
					stack.append(g[v].pop())
print(count)


(N, M) = map(int, input().split())
root = [-1] * N

def search(i):
	if root[i] >= 0:
		root[i] = search(root[i])
		return root[i]
	return i
for i in range(M):
	(x, y, z) = map(int, input().split())
	x -= 1
	y -= 1
	rx = search(x)
	ry = search(y)
	if rx == ry:
		continue
	elif root[rx] <= root[ry]:
		root[ry] += root[rx]
		root[rx] = ry
	else:
		root[rx] += root[ry]
		root[ry] = rx
ans = 0
for i in range(N):
	if root[i] < 0:
		ans += 1
print(ans)


def rt(i):
	while i != G[i][0]:
		i = G[i][0]
	return i
(N, M) = map(int, input().split())
G = {i: [i, 1] for i in range(1, N + 1)}
for _ in range(M):
	(X, Y, Z) = map(int, input().split())
	rx = rt(X)
	ry = rt(Y)
	if rx != ry:
		if G[rx][1] >= G[ry][1]:
			G[ry][0] = rx
			G[rx][1] += G[ry][1]
		else:
			G[rx][0] = ry
			G[ry][1] += G[rx][1]
cnt = 0
A = []
for i in range(1, N + 1):
	A.append(rt(i))
A = list(set(A))
print(len(A))


(N, M) = map(int, input().split())
par = [i for i in range(N + 1)]
h = [1 for _ in range(N + 1)]

def root(x):
	if par[x] == x:
		return x
	par[x] = root(par[x])
	return par[x]

def unite(x, y):
	rx = root(x)
	ry = root(y)
	if h[rx] < h[ry]:
		(rx, ry) = (ry, rx)
	h[rx] += h[ry]
	par[ry] = rx
for _ in range(M):
	(x, y, z) = map(int, input().split())
	unite(x, y)
for i in range(1, N + 1):
	par[i] = root(i)
print(len(set(par[1:])))


from collections import deque
(n, m) = map(int, input().split())
root = [[] for i in range(n)]
for _ in range(m):
	(a, b, c) = (int(x) for x in input().split())
	root[b - 1].append(a - 1)
	root[a - 1].append(b - 1)
check = [-1] * n
ans = 0
for j in range(n):
	if check[j] != -1:
		continue
	ans += 1
	check[j] = 1
	stack = deque([j])
	check[0] = 0
	while len(stack) > 0:
		v = stack.popleft()
		for i in root[v]:
			if check[i] == -1:
				check[i] = 1
				stack.append(i)
for i in check:
	if i == -1:
		ans += 1
print(ans)


(n, m) = map(int, input().split())
root = [int(i) for i in range(n)]
rank = [0] * n

def find(x):
	if root[x] == x:
		return x
	else:
		return find(root[x])
for i in range(m):
	(x, y, z) = map(int, input().split())
	fx = find(x - 1)
	fy = find(y - 1)
	if rank[fx] >= rank[fy]:
		root[fy] = fx
		if rank[fx] == rank[fy]:
			rank[fx] += 1
	else:
		root[fx] = fy
a = []
for i in range(n):
	a.append(find(i))
print(len(set(a)))


(N, M) = map(int, input().split())
flag = list(range(N))

def takeflag(p):
	stock = []
	while flag[flag[p]] != flag[p]:
		stock.append(p)
		p = flag[p]
	p = flag[p]
	for i in stock:
		flag[i] = p
	return p
for i in range(M):
	(x, y, z) = map(int, input().split())
	(x, y) = (x - 1, y - 1)
	(x, y) = map(takeflag, (x, y))
	(x, y) = (min(x, y), max(x, y))
	flag[x] = y
st = set()
for i in range(N):
	st.add(takeflag(i))
print(len(st))


(n, m) = map(int, input().split())
g = [[] for _ in range(n)]
for i in range(m):
	(x, y, z) = map(int, input().split())
	g[x - 1].append(y - 1)
	g[y - 1].append(x - 1)
check = [False] * n
cnt = 0
import queue
q = queue.Queue()
for i in range(n):
	if check[i]:
		continue
	cnt += 1
	check[i] = True
	q.put(i)
	while not q.empty():
		now = q.get()
		for ne in g[now]:
			if check[ne]:
				continue
			check[ne] = True
			q.put(ne)
print(cnt)


import sys
sys.setrecursionlimit(1000000)
(n, m) = map(int, input().split())
from collections import defaultdict
xyz = defaultdict(lambda : set([]))
for _ in range(m):
	(x, y, z) = map(int, input().split())
	xyz[x].add(y)
	xyz[y].add(x)
no_checked = [0] * n

def DFS(x):
	global no_checked
	global xyz
	no_checked[x - 1] = 1
	for item in xyz[x]:
		if no_checked[item - 1] == 0:
			DFS(item)
cnt = 0
for i in range(1, n + 1):
	if no_checked[i - 1] == 0:
		cnt += 1
		DFS(i)
print(cnt)


read = input
(n, m) = map(int, read().split())
f = [-1 for i in range(n + 1)]

def find(x):
	if f[x] < 0:
		return x
	else:
		f[x] = find(f[x])
		return f[x]
for i in range(m):
	(x, y, z) = map(int, read().split())
	if abs(x) < abs(y):
		(x, y) = (y, x)
	fx = find(x)
	fy = find(y)
	if fx == fy:
		continue
	f[fx] = f[fx] - 1
	f[fy] = fx
ans = 0
for i in range(1, n + 1):
	if f[i] < 0:
		ans += 1
print(ans)


(n, m) = map(int, input().split())
par = [i for i in range(n)]
size = [1] * n

def find(x):
	if par[x] == x:
		return x
	else:
		par[x] = find(par[x])
		return par[x]

def union(a, b):
	x = find(a)
	y = find(b)
	if x != y:
		if size[x] < size[y]:
			par[x] = par[y]
			size[y] += size[x]
		else:
			par[y] = par[x]
			size[x] += size[y]
	else:
		return
for i in range(m):
	(x, y, z) = map(int, input().split())
	union(x - 1, y - 1)
ans = {find(i) for i in range(n)}
print(len(ans))


class UnionFind:

	def __init__(self, size):
		self.data = [-1] * size

	def merge(self, x, y):
		x = self.root(x)
		y = self.root(y)
		if x == y:
			return False
		if self.data[x] < self.data[y]:
			(x, y) = (y, x)
		self.data[y] += self.data[x]
		self.data[x] = y
		return True

	def root(self, x):
		if self.data[x] < 0:
			return x
		self.data[x] = self.root(self.data[x])
		return self.data[x]

	def size(self, x):
		return -self.data[self.root(x)]

def main():
	(N, M) = map(int, input().split())
	uf = UnionFind(N)
	for i in range(M):
		(x, y, z) = map(int, input().split())
		uf.merge(x - 1, y - 1)
	cnt = 0
	for i in range(N):
		if uf.root(i) == i:
			cnt += 1
	print(cnt)

def __starting_point():
	main()
__starting_point()


(N, M) = map(int, input().split())
List = []
for i in range(M):
	List.append(list(map(int, input().split())))
List.sort()

class UnionFind:

	def __init__(self, n):
		self.n = n
		self.parents = [-1] * n

	def find(self, x):
		if self.parents[x] < 0:
			return x
		else:
			self.parents[x] = self.find(self.parents[x])
			return self.parents[x]

	def union(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return
		if self.parents[x] > self.parents[y]:
			(x, y) = (y, x)
		self.parents[x] += self.parents[y]
		self.parents[y] = x

	def size(self, x):
		return -self.parents[self.find(x)]

	def same(self, x, y):
		return self.find(x) == self.find(y)

	def members(self, x):
		root = self.find(x)
		return [i for i in range(self.n) if self.find(i) == root]

	def roots(self):
		return [i for (i, x) in enumerate(self.parents) if x < 0]

	def group_count(self):
		return len(self.roots())

	def all_group_members(self):
		return {r: self.members(r) for r in self.roots()}

	def __str__(self):
		return '\n'.join(('{}: {}'.format(r, self.members(r)) for r in self.roots()))
uf = UnionFind(N)
for i in range(M):
	uf.union(List[i][0] - 1, List[i][1] - 1)
print(uf.group_count())


(N, M) = map(int, input().split())
E = [[] for _ in range(N)]
for _ in range(M):
	(x, y, z) = map(lambda i: int(i) - 1, input().split())
	E[x].append(y)
	E[y].append(x)
G = [0] * (N + 1)

def dfs(root, g):
	stack = [root]
	G[root] = g
	while stack:
		node = stack.pop()
		for to in E[node]:
			if G[to] == 0:
				G[to] = g
				stack.append(to)
ans = 0
for i in range(N):
	if G[i] == 0:
		ans += 1
		dfs(i, ans)
print(ans)


from collections import defaultdict
dic = defaultdict(list)
(n, m) = map(int, input().split())
seen = set()
l = [None] * n
for i in range(m):
	(x, y, _) = map(int, input().split())
	dic[x - 1].append(y - 1)
	dic[y - 1].append(x - 1)
for i in range(n):
	if i in seen:
		continue
	seen.add(i)
	l[i] = i
	stack = [i]
	while stack:
		q = stack.pop()
		for child in dic[q]:
			if child not in seen:
				seen.add(child)
				l[child] = i
				stack.append(child)
print(len(set(l)))


import sys
from collections import defaultdict
readline = sys.stdin.buffer.readline

def geta(fn=lambda s: s.decode()):
	return list(map(fn, readline().split()))

def gete(fn=lambda s: s.decode()):
	return fn(readline().rstrip())

class UnionFind:

	def __init__(self, N: int):
		self.d = [-1 for _ in range(N)]

	def root(self, x: int) -> int:
		if self.d[x] < 0:
			return x
		self.d[x] = self.root(self.d[x])
		return self.d[x]

	def unite(self, x: int, y: int) -> bool:
		(x, y) = (self.root(x), self.root(y))
		if x == y:
			return False
		if self.d[x] > self.d[y]:
			(x, y) = (y, x)
		self.d[x] += self.d[y]
		self.d[y] = x
		return True

	def same(self, x: int, y: int) -> bool:
		return self.root(x) == self.root(y)

	def size(self, x: int):
		return -self.d[self.root(x)]

	def show(self):
		m = {}
		for n in range(len(self.d)):
			r = self.root(n)
			if r not in m:
				m[r] = [n]
			else:
				m[r].append(n)
		print('root -> childs')
		print('---------------------')
		for key in m:
			print('{} -> {}'.format(key, m[key]))

def main():
	(n, m) = geta(int)
	uf = UnionFind(2 * n)
	ans = n
	for _ in range(m):
		(x, y, z) = geta(int)
		united = False
		if z & 1 == 0:
			united = uf.unite(2 * x - 2, 2 * y - 2) and uf.unite(2 * x - 1, 2 * y - 1)
		else:
			united = uf.unite(2 * x - 2, 2 * y - 1) and uf.unite(2 * x - 1, 2 * y - 2)
		if united:
			ans -= 1
	print(ans)

def __starting_point():
	main()
__starting_point()


(N, M) = map(int, input().split())
R = [i for i in range(N)]

def root(x):
	if R[x] == x:
		return x
	else:
		R[x] = root(R[x])
		return R[x]

def union(x, y):
	rx = root(x)
	ry = root(y)
	if rx < ry:
		R[ry] = rx
	else:
		R[rx] = ry
for i in range(M):
	(x, y, z) = map(int, input().split())
	union(x - 1, y - 1)
for i in range(N):
	root(i)
print(len(set(R)))


(N, M) = map(int, input().split())
parent = [-1] * (N + 1)

def root(x):
	while parent[x] >= 0:
		x = parent[x]
	return x

def unite(x, y):
	root_x = root(x)
	root_y = root(y)
	if root_x != root_y:
		if parent[root_x] > parent[root_y]:
			parent[root_x] = root_y
		else:
			if parent[root_x] == parent[root_y]:
				parent[root_x] -= 1
			parent[root_y] = root_x
	return
for _ in range(M):
	(X, Y, Z) = map(int, input().split())
	unite(X, Y)
print(sum((i < 0 for i in parent)) - 1)


import sys
sys.setrecursionlimit(10 ** 9)
(N, M) = list(map(int, input().split()))
paths = [[] for _ in range(N)]
for _ in range(M):
	(a, b, z) = list(map(int, input().split()))
	paths[a - 1].append(b - 1)
	paths[b - 1].append(a - 1)
visited = [False] * N

def dfs(node, prev):
	if visited[node]:
		return
	visited[node] = True
	for n in paths[node]:
		if n != prev:
			dfs(n, node)
count = 0
for i in range(N):
	if visited[i] == False:
		count += 1
		dfs(i, -1)
print(count)


import queue
(n, m) = list(map(int, input().split()))
dic = {}
count = 0
q = queue.Queue()
for i in range(m):
	(a, b, c) = list(map(int, input().split()))
	if not a - 1 in dic:
		dic[a - 1] = [b - 1]
	else:
		dic[a - 1].append(b - 1)
	if not b - 1 in dic:
		dic[b - 1] = [a - 1]
	else:
		dic[b - 1].append(a - 1)
dp = [0] * n
for i in range(n):
	if dp[i] == 0:
		count += 1
		dp[i] = count
		if i in dic:
			for j in dic[i]:
				dp[j] = count
				q.put(j)
		while not q.empty():
			temp = q.get()
			if temp in dic:
				for j in dic[temp]:
					if dp[j] == 0:
						dp[j] = count
						q.put(j)
print(count)


(n, m) = map(int, input().split())
xy = []
data = [[] for i in range(n + 1)]
for _ in range(m):
	(x, y, z) = map(int, input().split())
	xy.append([x, y])
	data[x].append(y)
	data[y].append(x)
flag = [0] * (n + 1)
count = 0
for i in range(1, n + 1):
	if flag[i] == 0:
		count += 1
		flag[i] = 1
		que = [i]
		while que:
			h = que.pop()
			for u in data[h]:
				if flag[u] == 0:
					flag[u] = 1
					que.append(u)
print(count)


import sys
import re
import math
import collections
import bisect
import itertools
import fractions
import functools
import copy
import heapq
import decimal
import statistics
import queue
sys.setrecursionlimit(10 ** 9)
INF = 10 ** 16
MOD = 10 ** 9 + 7
ni = lambda : int(sys.stdin.readline())
ns = lambda : list(map(int, sys.stdin.readline().split()))
na = lambda : list(map(int, sys.stdin.readline().split()))
na1 = lambda : list([int(x) - 1 for x in sys.stdin.readline().split()])

class UnionFind:

	def __init__(self, n):
		self.n = n
		self.parents = [-1] * n

	def find(self, x):
		if self.parents[x] < 0:
			return x
		else:
			self.parents[x] = self.find(self.parents[x])
			return self.parents[x]

	def union(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return
		if self.parents[x] > self.parents[y]:
			(x, y) = (y, x)
		self.parents[x] += self.parents[y]
		self.parents[y] = x

	def size(self, x):
		return -self.parents[self.find(x)]

	def same(self, x, y):
		return self.find(x) == self.find(y)

	def members(self, x):
		root = self.find(x)
		return [i for i in range(self.n) if self.find(i) == root]

	def roots(self):
		return [i for (i, x) in enumerate(self.parents) if x < 0]

	def group_count(self):
		return len(self.roots())

	def all_group_members(self):
		return {r: self.members(r) for r in self.roots()}

	def __str__(self):
		return '\n'.join(('{}: {}'.format(r, self.members(r)) for r in self.roots()))

def main():
	(n, m) = ns()
	uf = UnionFind(n)
	for _ in range(m):
		(x, y, z) = ns()
		uf.union(x - 1, y - 1)
	ans = uf.group_count()
	print(ans)

def __starting_point():
	main()
__starting_point()


from collections import deque
(N, M) = map(int, input().split())
Clear = [-1] * N
T = [[] for _ in range(N)]
ans = 0
for i in range(M):
	(X, Y, Z) = map(int, input().split())
	X -= 1
	Y -= 1
	T[X].append(Y)
	T[Y].append(X)
for i in range(N):
	if Clear[i] == -1:
		ans += 1
		Clear[i] = 1
		P = deque([i])
		while len(P) > 0:
			t = P.popleft()
			for j in T[t]:
				if Clear[j] == -1:
					Clear[j] = 1
					P.append(j)
print(ans)


import sys
sys.setrecursionlimit(10 ** 7)
(N, M) = map(int, input().split())
edges = [[] for _ in range(N)]
for _ in range(M):
	(x, y, z) = map(int, input().split())
	x -= 1
	y -= 1
	edges[x].append(y)
	edges[y].append(x)
visited = [False] * N

def dfs(u):
	if visited[u]:
		return
	visited[u] = True
	for v in edges[u]:
		if visited[v]:
			continue
		dfs(v)
ans = 0
for u in range(N):
	if visited[u]:
		continue
	ans += 1
	dfs(u)
print(ans)


(n, m) = map(int, input().split())
xy = [[] for _ in range(n + 1)]
for _ in range(m):
	(x, y, z) = map(int, input().split())
	xy[x].append(y)
	xy[y].append(x)
from collections import deque
visited = [0] * (n + 1)
count = 0
for i in range(1, n + 1):
	if visited[i] == 0:
		stack = deque()
		stack.append(i)
		visited[i] += 1
		while stack:
			a = stack.pop()
			for j in xy[a]:
				if visited[j] == 0:
					visited[j] += 1
					stack.append(j)
		count += 1
print(count)


(n, m) = map(int, input().split())
edges = [[] for i in range(n)]
for i in range(m):
	(x, y, z) = map(int, input().split())
	edges[x - 1].append(y - 1)
	edges[y - 1].append(x - 1)
visited = [False] * n
ret = 0
for i in range(n):
	if not visited[i]:
		q = [i]
		visited[i] = True
		while len(q) > 0:
			u = q.pop(0)
			for v in edges[u]:
				if not visited[v]:
					q.append(v)
					visited[v] = True
		ret += 1
print(ret)


class UnionFind:

	def __init__(self, n):
		self.n = n
		self.parents = [-1] * n

	def find(self, x):
		if self.parents[x] < 0:
			return x
		else:
			self.parents[x] = self.find(self.parents[x])
		return self.parents[x]

	def union(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return
		if self.parents[x] > self.parents[y]:
			(x, y) = (y, x)
		self.parents[x] += self.parents[y]
		self.parents[y] = x

	def same(self, x, y):
		return self.find(x) == self.find(y)

	def roots(self):
		return [i for (i, x) in enumerate(self.parents) if x < 0]

	def num_roots(self):
		return len([i for (i, x) in enumerate(self.parents) if x < 0])

	def members(self, x):
		root = self.find(x)
		return [i for i in range(self.n) if self.find(i) == root]

	def num_members(self, x):
		return abs(self.parents[self.find(x)])

	def __str__(self):
		return '\n'.join(('{}: {}'.format(r, self.members(r)) for r in self.roots()))
(N, M) = map(int, input().split())
uf = UnionFind(N)
for i in range(M):
	(a, b, c) = map(int, input().split())
	uf.union(a - 1, b - 1)
print(uf.num_roots())


class UnionFind:

	def __init__(self, node):
		self.parent = [-1 for _ in range(node)]

	def find(self, target):
		if self.parent[target] < 0:
			return target
		else:
			self.parent[target] = self.find(self.parent[target])
			return self.parent[target]

	def is_same(self, x, y):
		return self.find(x) == self.find(y)

	def union(self, x, y):
		root_x = self.find(x)
		root_y = self.find(y)
		if root_x == root_y:
			return
		if self.parent[root_x] > self.parent[root_y]:
			(root_x, root_y) = (root_y, root_x)
		self.parent[root_x] += self.parent[root_y]
		self.parent[root_y] = root_x

	def get_size(self, x):
		return -self.parent[self.find(x)]

	def get_root(self):
		return [i for (i, root) in enumerate(self.parent) if root < 0]

def main():
	(n, m) = list(map(int, input().split()))
	uf = UnionFind(n)
	for _ in range(m):
		(x, y, _) = [int(x) - 1 for x in input().split()]
		uf.union(x, y)
	print(len(uf.get_root()))

def __starting_point():
	main()
__starting_point()


(n, m) = map(int, input().split())
uf = [i for i in range(n + 1)]

def uf_find(x):
	while uf[x] != x:
		x = uf[x]
	return x
for i in range(m):
	(x, y, z) = map(int, input().split())
	(a, b) = (uf_find(x), uf_find(y))
	if a > b:
		(a, b) = (b, a)
	uf[b] = a
c = set()
for i in range(1, n + 1):
	c.add(uf_find(i))
print(len(c))


(n, m) = map(int, input().split())
ans = n
pre = [i for i in range(n)]
for _ in range(m):
	(x, y, z) = map(lambda x: int(x) - 1, input().split())
	X = [x]
	while pre[x] != x:
		x = pre[x]
		X.append(x)
	Y = [y]
	while pre[y] != y:
		y = pre[y]
		Y.append(y)
	if x != y:
		ans -= 1
		for xx in X:
			pre[xx] = y
		for yy in Y:
			pre[yy] = y
		pre[x] = y
print(ans)


import sys
sys.setrecursionlimit(100100)
(N, M) = [int(x) for x in input().split()]
vien = [[] for _ in range(N)]
for _ in range(M):
	(a, b, w) = [int(x) for x in input().split()]
	a -= 1
	b -= 1
	w = w & 1
	vien[a].append(b)
	vien[b].append(a)
been = [False] * N
ats = 0

def dfs(x):
	been[x] = True
	for u in vien[x]:
		if not been[u]:
			dfs(u)
for i in range(N):
	if been[i]:
		continue
	ats += 1
	dfs(i)
print(ats)


import sys
sys.setrecursionlimit(10 ** 6)

def f(j):
	a[j] = 1
	n = len(dic[j])
	for k in range(n):
		if a[dic[j][k]] == 0:
			f(dic[j][k])
(N, M) = map(int, input().split())
dic = {}
for i in range(1, N + 1):
	dic[i] = []
for i in range(M):
	(x, y, z) = map(int, input().split())
	dic[x].append(y)
	dic[y].append(x)
a = [0] * (N + 1)
out = 0
i = 1
while i < N + 1:
	if a[i] == 0:
		a[i] = 1
		out += 1
		n = len(dic[i])
		for j in range(n):
			if a[dic[i][j]] == 0:
				f(dic[i][j])
	i += 1
print(out)


(n, m) = map(int, input().split())
xy = [i for i in range(n + 1)]

def root(x):
	i = x
	while i != xy[i]:
		i = xy[i]
	xy[x] = i
	return i
for _ in range(m):
	(x, y) = map(int, input().split()[:2])
	rx = root(x)
	ry = root(y)
	if rx < ry:
		xy[rx] = ry
	else:
		xy[ry] = rx
ans = sum((i == v for (i, v) in enumerate(xy))) - 1
print(ans)


(N, M) = map(int, input().split())
par = [i for i in range(N)]
rank = [0] * N

def find(x):
	if par[x] == x:
		return x
	else:
		par[x] = find(par[x])
		return par[x]

def same(x, y):
	return find(x) == find(y)

def union(x, y):
	x = find(x)
	y = find(y)
	if x == y:
		return
	if rank[x] > rank[y]:
		par[y] = x
	else:
		par[x] = y
		if rank[x] == rank[y]:
			rank[y] += 1
for i in range(M):
	(a, b, c) = map(int, input().split())
	a -= 1
	b -= 1
	union(a, b)
cnt = 0
for i in range(N):
	if i == par[i]:
		cnt += 1
print(cnt)


import sys
sys.setrecursionlimit(114514)
from collections import Counter
(N, M) = map(int, input().split())
g = [i for i in range(N + 1)]

def find(x):
	if g[x] == x:
		return x
	g[x] = find(g[x])
	return g[x]

def union(x, y):
	x = find(x)
	y = find(y)
	if x != y:
		g[x] = y
for _ in range(M):
	(x, y, _) = map(int, input().split())
	union(x, y)
print(len(Counter([find(i) for i in range(1, N + 1)])))


(n, m) = map(int, input().split())
a = [list(map(int, input().split()))[:2] for i in range(m)]
b = [i for i in range(n + 1)]
c = [1] * (n + 1)

def root(x):
	if b[x] == x:
		return x
	x = b[x]
	return root(x)

def unite(x, y):
	x = root(x)
	y = root(y)
	if x != y:
		if c[x] > c[y]:
			b[y] = x
			c[x] += 1
		else:
			b[x] = y
			c[y] += 1
for (i, j) in a:
	unite(i, j)
for i in range(1, n + 1):
	b[i] = root(i)
print(len(set(b[1:])))


import sys
sys.setrecursionlimit(10 ** 6)

def get_par(x):
	if x == par_list[x]:
		return x
	else:
		par_list[x] = get_par(par_list[x])
		return par_list[x]
(N, M) = map(int, input().split())
par_list = list(range(N))
for i in range(M):
	(Xi, Yi, Zi) = map(int, input().split())
	par_Xi = get_par(Xi - 1)
	par_Yi = get_par(Yi - 1)
	if par_Xi != par_Yi:
		par_list[par_Yi] = par_Xi
set_uf = set()
for par in par_list:
	set_uf.add(get_par(par))
print(len(set_uf))


from collections import deque
import heapq
(N, M) = map(int, input().split())
edges = {i: [] for i in range(N)}
for _ in range(M):
	(x, y, _) = map(int, input().split())
	edges[x - 1].append(y - 1)
	edges[y - 1].append(x - 1)
ans = 0
visited = [False] * N
for i in range(N):
	if visited[i]:
		continue
	stack = [i]
	while stack:
		v = stack.pop()
		for u in edges[v]:
			if not visited[u]:
				visited[u] = True
				stack.append(u)
	ans += 1
print(ans)


(N, M) = map(int, input().split())
v = set()

def dfs(graph, start, visited):
	stack = [start]
	visited.add(start)
	while stack:
		label = stack.pop(0)
		for node in g[label]:
			if node not in visited:
				visited.add(node)
				stack.append(node)
	return visited
g = {i: [] for i in range(1, N + 1)}
for i in range(M):
	(x, y, z) = map(int, input().split())
	g[x].append(y)
	g[y].append(x)
ans = 0
for i in range(1, N + 1):
	if i not in v:
		ans += 1
		dfs(g, i, v)
print(ans)


import sys
input = sys.stdin.readline

class UnionFind:

	def __init__(self, N):
		self.N = N
		self.__make_set()

	def __make_set(self):
		self._parent = list(range(self.N + 1))
		self._rank = [0] * (self.N + 1)
		self._size = [1] * (self.N + 1)

	def find(self, x):
		if self._parent[x] != x:
			self._parent[x] = self.find(self._parent[x])
		return self._parent[x]

	def union(self, x, y):
		x_root = self.find(x)
		y_root = self.find(y)
		if x_root == y_root:
			return
		x_rank = self._rank[x_root]
		y_rank = self._rank[y_root]
		if x_rank > y_rank:
			self._parent[y_root] = x_root
			self._size[x_root] += self._size[y_root]
		elif x_rank < y_rank:
			self._parent[x_root] = y_root
			self._size[y_root] += self._size[x_root]
		else:
			self._parent[y_root] = x_root
			self._rank[x_root] += 1
			self._size[x_root] += self._size[y_root]

	def same_set(self, x, y):
		return self.find(x) == self.find(y)

	def size(self, x):
		return self._size[self.find(x)]

def main():
	(N, M) = list(map(int, input().split()))
	uf = UnionFind(N)
	for _ in range(M):
		(X, Y, _) = list(map(int, input().split()))
		uf.union(X, Y)
	s = set()
	for i in range(1, N + 1):
		s.add(uf.find(i))
	ans = len(s)
	print(ans)

def __starting_point():
	main()
__starting_point()


import sys
sys.setrecursionlimit(10 ** 6)
(n, m) = map(int, input().split())
xy = []
for _ in range(m):
	(x, y, _) = map(int, input().split())
	xy.append((x - 1, y - 1))

class UnionFind:

	def __init__(self, n):
		self.li = list(range(n))

	def root(self, x):
		if self.li[x] == x:
			return x
		self.li[x] = self.root(self.li[x])
		return self.li[x]

	def unite(self, x, y):
		rx = self.root(x)
		ry = self.root(y)
		if rx == ry:
			return
		self.li[ry] = rx

	def same(self, x, y):
		return self.root(x) == self.root(y)
uf = UnionFind(n)
for (x, y) in xy:
	uf.unite(x, y)
for i in range(n):
	uf.root(i)
print(len(set(uf.li)))


(n, m) = map(int, input().split())

def root(x):
	if x != parent[x]:
		x = root(parent[x])
	return x

def same(x, y):
	return root(x) == root(y)
parent = list(range(n))
rank = [0] * n

def unite(x, y):
	rx = root(x)
	ry = root(y)
	if rank[rx] > rank[ry]:
		parent[ry] = rx
	else:
		parent[rx] = ry
		if rank[rx] == rank[ry]:
			rank[ry] += 1
for i in range(m):
	(x, y, z) = map(int, input().split())
	unite(x - 1, y - 1)
ans = set()
for i in range(n):
	ans.add(root(i))
print(len(ans))


def find(x):
	if x == par[x]:
		return x
	par[x] = find(par[x])
	return par[x]

def union(x, y):
	(x, y) = (find(x), find(y))
	if x == y:
		return
	par[y] = x
(n, m) = map(int, input().split())
par = {i: i for i in range(1, n + 1)}
for _ in range(m):
	(a, b, c) = map(int, input().split())
	union(a, b)
print(sum([1 for i in range(1, n + 1) if par[i] == i]))


from networkx.utils import UnionFind

def main():
	(n, m) = map(int, input().split())
	uf = UnionFind()
	for i in range(n):
		_ = uf[i]
	for _ in range(m):
		(x, y, z) = map(int, input().split())
		uf.union(x - 1, y - 1)
	print(len(list(uf.to_sets())))

def __starting_point():
	main()
__starting_point()


a = [int(s) for s in input().split()]
g = {i: [] for i in range(1, a[0] + 1)}
for i in range(a[1]):
	c = [int(s) for s in input().split()]
	g[c[0]].append(c[1])
	g[c[1]].append(c[0])
j = 0
d = {i: False for i in range(1, a[0] + 1)}
for i in range(1, a[0] + 1):
	if d[i] == False:
		j += 1
		d[i] = True
		if g[i] != []:
			Q = [i]
			while Q != []:
				r = Q.pop(0)
				if g[r] != []:
					for m in g[r]:
						if d[m] == False:
							d[m] = True
							Q.append(m)
print(j)


import heapq
import sys
sys.setrecursionlimit(10 ** 8)
(n, m) = map(int, input().split())
c = [0] * n
g = [[] for i in range(n)]
revealed = [False] * n
rn = 0
for i in range(m):
	(x, y, z) = map(int, input().split())
	x -= 1
	y -= 1
	c[x] += 1
	c[y] += 1
	g[y].append(x)
	g[x].append(y)
hq = [(c[i], i) for i in range(n)]
heapq.heapify(hq)

def dfs(src):
	nonlocal rn
	rn += 1
	revealed[src] = True
	for nxt in g[src]:
		if not revealed[nxt]:
			dfs(nxt)
ans = 0
while rn < n:
	(_, now) = heapq.heappop(hq)
	if revealed[now]:
		continue
	revealed[now] = True
	ans += 1
	dfs(now)
print(ans)


(N, M) = map(int, input().split())
edge = [[] for _ in range(N)]
for i in range(M):
	(a, b, c) = map(int, input().split())
	edge[a - 1].append(b - 1)
	edge[b - 1].append(a - 1)
from collections import deque
ans = 0
visited = [False] * N
d = deque()
for i in range(N):
	if visited[i] == False:
		visited[i] = True
		d.append(i)
		while len(d) > 0:
			v = d.popleft()
			for w in edge[v]:
				if visited[w] == False:
					visited[w] = True
					d.append(w)
		ans += 1
print(ans)


(n, m) = map(int, input().split())
adj = [[] for _ in range(n)]
for _ in range(m):
	(x, y, z) = map(int, input().split())
	adj[x - 1].append(y - 1)
	adj[y - 1].append(x - 1)
opn = [True] * n
count = 0
for i in range(n):
	if opn[i]:
		count += 1
		opn[i] = False
		stack = [i]
		while stack:
			u = stack.pop()
			for v in adj[u]:
				if opn[v]:
					stack.append(v)
					opn[v] = False
print(count)


class UnionFind:

	def __init__(self, n):
		self.par = [i for i in range(n)]
		self.rank = [0] * n

	def root(self, x):
		if self.par[x] == x:
			return x
		else:
			self.par[x] = self.root(self.par[x])
			return self.par[x]

	def union(self, x, y):
		x = self.root(x)
		y = self.root(y)
		if x != y:
			if self.rank[x] < self.rank[y]:
				self.par[x] = y
			else:
				self.par[y] = x
				if self.rank[x] == self.rank[y]:
					self.rank[x] += 1

	def samegrp(self, x, y):
		return self.root(x) == self.root(y)
(n, m) = [int(x) for x in input().split()]
A = UnionFind(n)
ans = n
for i in range(m):
	(x, y, _) = [int(z) - 1 for z in input().split()]
	if not A.samegrp(x, y):
		ans -= 1
	A.union(x, y)
print(ans)


import sys
import heapq
import math
import fractions
import bisect
import itertools
from collections import Counter
from collections import deque
from operator import itemgetter

def input():
	return sys.stdin.readline().strip()

def mp():
	return map(int, input().split())

def lmp():
	return list(map(int, input().split()))

class UnionFind:

	def __init__(self, n):
		self.n = n
		self.parents = [-1] * n

	def find(self, x):
		if self.parents[x] < 0:
			return x
		else:
			self.parents[x] = self.find(self.parents[x])
			return self.parents[x]

	def union(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return
		if self.parents[x] > self.parents[y]:
			(x, y) = (y, x)
		self.parents[x] += self.parents[y]
		self.parents[y] = x

	def size(self, x):
		return -self.parents[self.find(x)]

	def same(self, x, y):
		return self.find(x) == self.find(y)

	def members(self, x):
		root = self.find(x)
		return [i for i in range(self.n) if self.find(i) == root]

	def roots(self):
		return [i for (i, x) in enumerate(self.parents) if x < 0]

	def group_count(self):
		return len(self.roots())

	def all_group_members(self):
		return {r: self.members(r) for r in self.roots()}

	def __str__(self):
		return '\n'.join(('{}: {}'.format(r, self.members(r)) for r in self.roots()))
(n, m) = mp()
uf = UnionFind(n)
for i in range(m):
	(X, Y, Z) = mp()
	uf.union(X - 1, Y - 1)
print(len(uf.roots()))


from sys import setrecursionlimit
setrecursionlimit(10 ** 9)
(n, m) = [int(i) for i in input().split()]
U = [[int(i) for i in input().split()] for j in range(m)]
E = [[] for i in range(n + 1)]
for (u, v, w) in U:
	E[u].append(v)
	E[v].append(u)
visited = [False] * (n + 1)

def dfs(v):
	if visited[v]:
		return 0
	visited[v] = True
	for e in E[v]:
		dfs(e)
	return 1
ans = 0
for i in range(1, n + 1):
	ans += dfs(i)
print(ans)


import sys, re
from collections import deque, defaultdict, Counter
from math import ceil, sqrt, hypot, factorial, pi, sin, cos, radians, gcd
from itertools import accumulate, permutations, combinations, product, groupby, combinations_with_replacement
from operator import itemgetter, mul
from copy import deepcopy
from string import ascii_lowercase, ascii_uppercase, digits
from bisect import bisect, bisect_left
from heapq import heappush, heappop
from functools import reduce
import networkx as nx
from networkx.utils import union_find

def input():
	return sys.stdin.readline().strip()

def INT():
	return int(input())

def MAP():
	return list(map(int, input().split()))

def LIST():
	return list(map(int, input().split()))

def ZIP(n):
	return list(zip(*(MAP() for _ in range(n))))
sys.setrecursionlimit(10 ** 9)
INF = float('inf')
mod = 10 ** 9 + 7
(N, M) = MAP()
XYZ = [LIST() for _ in range(M)]
uf = union_find.UnionFind(list(range(1, N + 1)))
for (X, Y, Z) in XYZ:
	uf.union(X, Y)
print(len(list(uf.to_sets())))


def main():
	(n, m) = list(map(int, input().split()))
	cards = [-1 for i in range(n)]
	mg = {}
	for i in range(n):
		mg[i + 1] = []
	for i in range(m):
		(x, y, z) = list(map(int, input().split()))
		mg[x].append(y)
		mg[y].append(x)
	ans = 0
	for i in range(n):
		if cards[i] == -1:
			ans += 1
			cards[i] = 0
			que = [i]
			while len(que) > 0:
				s = que.pop(0)
				for v in mg[s + 1]:
					if cards[v - 1] == 0:
						continue
					cards[v - 1] = 0
					que.append(v - 1)
	print(ans)

def __starting_point():
	main()
__starting_point()


import sys
sys.setrecursionlimit(10 ** 7)

def update(v):
	for nv in con[v]:
		if seen[nv]:
			continue
		seen[nv] = 1
		update(nv)
(N, M) = map(int, input().split())
seen = [0] * N
con = [[] for i in range(N)]
cnt = [[i, 0] for i in range(N)]
for i in range(M):
	(X, Y, Z) = map(int, input().split())
	(X, Y) = (X - 1, Y - 1)
	con[X].append(Y)
	con[Y].append(X)
	cnt[X][1] += 1
	cnt[Y][1] += 1
cnt.sort(key=lambda x: x[1], reverse=True)
ans = 0
for (i, a) in cnt:
	if seen[i]:
		continue
	ans += 1
	seen[i] = 1
	update(i)
print(ans)


(n, m) = map(int, input().split())
par = [-1] * n

def find(x):
	if par[x] < 0:
		return x
	else:
		par[x] = find(par[x])
		return par[x]

def same(x, y):
	return find(x) == find(y)

def unite(x, y):
	x = find(x)
	y = find(y)
	if x == y:
		return 0
	else:
		if par[x] > par[y]:
			(x, y) = (y, x)
		par[x] += par[y]
		par[y] = x

def size(x):
	return -par[find(x)]
for i in range(m):
	(x, y, z) = map(int, input().split())
	unite(x - 1, y - 1)
ans = 0
for i in range(n):
	if par[i] < 0:
		ans += 1
print(ans)


from collections import defaultdict

def dfs(u):
	st = [u]
	while st:
		u = st.pop()
		if cv[u]:
			continue
		cv[u] = 1
		for nxt in adj[u]:
			st.append(nxt)
(n, m) = [int(item) for item in input().split()]
data = []
ans = [-1] * n
adj = defaultdict(set)
for _ in range(m):
	(x, y, z) = [int(item) for item in input().split()]
	x -= 1
	y -= 1
	adj[x].add(y)
	adj[y].add(x)
cost = 0
cv = [0] * n
for i in range(n):
	if not cv[i]:
		cost += 1
		dfs(i)
print(cost)


(n, m) = list(map(int, input().split()))

class UnionFind:

	def __init__(self, n):
		self.n = n
		self.parents = [-1] * n

	def find(self, x):
		if self.parents[x] < 0:
			return x
		else:
			self.parents[x] = self.find(self.parents[x])
			return self.parents[x]

	def union(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return
		if self.parents[x] > self.parents[y]:
			(x, y) = (y, x)
		self.parents[x] += self.parents[y]
		self.parents[y] = x

	def size(self, x):
		return -self.parents[self.find(x)]

	def roots(self):
		return [i for (i, x) in enumerate(self.parents) if x < 0]

	def group_count(self):
		return len(self.roots())
uf = UnionFind(n)
for i in range(m):
	(x, y, z) = list(map(int, input().split()))
	x -= 1
	y -= 1
	uf.union(x, y)
print(uf.group_count())


(N, M) = map(int, input().split())

def root(x):
	if x == p[x]:
		return x
	p[x] = y = root(p[x])
	return y

def unite(x, y):
	px = root(x)
	py = root(y)
	if px < py:
		p[py] = px
	else:
		p[px] = py
(*p,) = range(N)
for i in range(M):
	(x, y, z) = map(int, input().split())
	unite(x - 1, y - 1)
ans = 0
for i in range(N):
	if root(i) == i:
		ans += 1
print(ans)


def search(n):
	idx = n
	while A[n - 1] != n:
		n = A[n - 1]
	A[idx - 1] = n
	return n
(N, M) = list(map(int, input().split()))
A = [i for i in range(1, N + 1)]
ans = 0
for i in range(M):
	(X, Y, Z) = list(map(int, input().split()))
	(X_root, Y_root) = (search(X), search(Y))
	if X_root != Y_root:
		A[X_root - 1] = Y_root
		ans += 1
print(N - ans)


MOD = 10 ** 9 + 7
INFI = 10 ** 10
import math
from collections import deque
import itertools
import heapq
from fractions import Fraction
import copy
from functools import lru_cache
from collections import defaultdict
import pprint

def sosuhante(n):
	for k in range(2, int(math.sqrt(n)) + 1):
		if n % k == 0:
			return False
	return True

def cmb(n, r):
	if n - r < r:
		r = n - r
	if r == 0:
		return 1
	if r == 1:
		return n
	numerator = [n - r + k + 1 for k in range(r)]
	denominator = [k + 1 for k in range(r)]
	for p in range(2, r + 1):
		pivot = denominator[p - 1]
		if pivot > 1:
			offset = (n - r) % p
			for k in range(p - 1, r, p):
				numerator[k - offset] /= pivot
				denominator[k] /= pivot
	result = 1
	for k in range(r):
		if numerator[k] > 1:
			result *= int(numerator[k])
	return result

def kingaku(a, b, n):
	keta = len(str(n))
	return a * n + b * keta

def my_index(l, x, default=False):
	if x in l:
		return l.index(x)
	else:
		return default

def ret(a):
	c = [None] * (len(a) - 1)
	if len(a) == 1:
		return a[0]
	elif len(a) == 0:
		return 0
	for i in range(1, len(a)):
		c[i - 1] = abs(a[i] - a[i - 1])
	return ret(c)

def soinsubunkai(n):
	a = []
	i = 1
	while i * i <= n:
		if n % i == 0 and i != 1:
			a.append(i)
			n = n // i
		if n % i != 0 or i == 1:
			i += 1
	nokori = [n]
	return a + nokori

def make_divisors(n):
	(lower_divisors, upper_divisors) = ([], [])
	i = 1
	while i * i <= n:
		if n % i == 0:
			lower_divisors.append(i)
			if i != n // i:
				upper_divisors.append(n // i)
		i += 1
	return lower_divisors + upper_divisors[::-1]

def main():
	(n, m) = map(int, input().split())
	graph = [[] for _ in range(n + 1)]
	for i in range(m):
		(a, b, c) = map(int, input().split())
		graph[a].append(b)
		graph[b].append(a)
	stack = []
	visited = [0 for _ in range(n + 1)]
	zones = 0
	count = 0

	def DFS():
		c = 1
		while True:
			if len(stack) == 0:
				break
			s = stack.pop()
			if visited[s] == 0:
				for i in graph[s]:
					if visited[i] == 0:
						stack.append(i)
				visited[s] = 1
				c += 1
			if len(stack) == 0:
				break
		return c
	for i in range(1, n + 1):
		if visited[i] == 0:
			visited[i] = 1
			for j in graph[i]:
				stack.append(j)
			if len(stack) > 0:
				count += DFS()
				zones += 1
		else:
			continue
	print(n - count + zones)

def __starting_point():
	main()
__starting_point()


import sys
sys.setrecursionlimit(100000)
(N, M) = [int(_) for _ in input().split()]
XYZ = [[int(_) for _ in input().split()] for _ in range(M)]
UF = list(range(N + 1))

def find(x):
	if UF[x] != x:
		UF[x] = find(UF[x])
	return UF[x]

def unite(x, y):
	UF[find(x)] = find(y)

def same(x, y):
	return find(x) == find(y)
for (x, y, z) in XYZ:
	unite(x, y)
s = set()
for i in range(1, N + 1):
	s.add(find(i))
print(len(set(s)))


class UnionFind:

	def __init__(self, n):
		self.par = [-1] * n

	def unite(self, x, y):
		x = self.root(x)
		y = self.root(y)
		if x == y:
			return False
		if self.par[x] > self.par[y]:
			(x, y) = (y, x)
		self.par[x] += self.par[y]
		self.par[y] = x
		return True

	def root(self, x):
		path = []
		while self.par[x] >= 0:
			path.append(x)
			x = self.par[x]
		for y in path:
			self.par[y] = x
		return x

	def same(self, x, y):
		return self.root(x) == self.root(y)

	def size(self, x):
		return -self.par[self.root(x)]
(n, m) = map(int, input().split())
uni = UnionFind(n)
for _ in range(m):
	(x, y, z) = map(int, input().split())
	x -= 1
	y -= 1
	uni.unite(x, y)
a = [0] * n
for i in range(n):
	a[uni.root(i)] = 1
print(sum(a))


from collections import deque
(n, m) = map(int, input().split())
graph = [[] * n for _ in range(n)]
for _ in range(m):
	(x, y, z) = map(int, input().split())
	x -= 1
	y -= 1
	z %= 2
	graph[x].append(y)
	graph[y].append(x)
seen = [False] * n
ans = 0
for i in range(n):
	if not seen[i]:
		seen[i] = True
		node = deque(graph[i])
		while node:
			v = node.popleft()
			if seen[v]:
				continue
			seen[v] = True
			node.extend(graph[v])
		ans += 1
print(ans)


import sys
sys.setrecursionlimit(10 ** 6)
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines

def find(x):
	if par[x] < 0:
		return x
	else:
		par[x] = find(par[x])
		return find(par[x])

def union(x, y):
	x = find(x)
	y = find(y)
	if x == y:
		return False
	else:
		if par[x] > par[y]:
			(x, y) = (y, x)
		par[x] += par[y]
		par[y] = x
		return True

def same(x, y):
	return find(x) == find(y)
(N, M) = map(int, readline().split())
par = [-1] * (N + 1)
for i in range(M):
	(x, y, z) = map(int, readline().split())
	union(x, y)
print(sum((1 for i in par[1:] if i < 0)))


import sys
import math
import itertools
import bisect
from copy import copy
from collections import deque, Counter
from decimal import Decimal

def s():
	return input()

def i():
	return int(input())

def S():
	return input().split()

def I():
	return list(map(int, input().split()))

def L():
	return list(input().split())

def l():
	return list(map(int, input().split()))

def lcm(a, b):
	return a * b // math.gcd(a, b)
sys.setrecursionlimit(10 ** 9)
INF = 10 ** 9
mod = 10 ** 9 + 7
(N, M) = I()
links = [[] for _ in range(N)]
for i in range(M):
	(x, y, z) = I()
	links[x - 1].append(y - 1)
	links[y - 1].append(x - 1)
ans = 0
visited = [0] * N

def dfs(n):
	if visited[n]:
		return
	visited[n] = 1
	for l in links[n]:
		dfs(l)
for i in range(N):
	if not visited[i]:
		dfs(i)
		ans += 1
print(ans)


import sys
sys.setrecursionlimit(100000)
(n, m) = map(int, input().split())
g = [i for i in range(n)]

def find(x):
	if g[x] == x:
		return x
	g[x] = find(g[x])
	return g[x]

def union(x, y):
	x = find(x)
	y = find(y)
	if x != y:
		g[x] = y
for i in range(m):
	(xi, yi, zi) = map(int, input().split())
	union(xi - 1, yi - 1)
ans = 0
for i in range(n):
	if find(i) == i:
		ans += 1
print(ans)


import sys
sys.setrecursionlimit(10 ** 9)
(N, M) = list(map(int, input().split()))

class Union_Find:

	def __init__(self, n):
		self.parent = [i for i in range(n)]
		self.rank = [1 for i in range(n)]

	def find(self, x):
		if self.parent[x] == x:
			return x
		else:
			return self.find(self.parent[x])

	def unite(self, x, y):
		px = self.find(x)
		py = self.find(y)
		if px == py:
			return
		elif self.rank[px] == self.rank[py]:
			self.parent[py] = px
			self.rank[px] += 1
		elif self.rank[px] > self.rank[py]:
			self.parent[py] = px
		else:
			self.parent[px] = py
uftree = Union_Find(N + 1)
for i in range(M):
	(x, y, _) = list(map(int, input().split()))
	uftree.unite(x, y)
result = 0
for i in range(1, N + 1):
	if uftree.find(i) == i:
		result += 1
print(result)


(n, m) = map(int, input().split())
tree = [-i for i in range(n + 1)]

def search_root(num, tree=tree):
	if tree[num] < 0:
		return num
	else:
		tree[num] = search_root(tree[num])
		return tree[num]
for _i in range(m):
	(x, y, z) = map(int, input().split())
	(x, y) = sorted([search_root(x), search_root(y)])
	if x == y:
		continue
	else:
		tree[x] = y
print(sum((1 for i in tree if i < 0)))


from collections import deque
(n, m) = map(int, input().split())
xyz = []
for _ in range(m):
	(x, y, z) = map(int, input().split())
	xyz.append((x, y, z))
uf = [-1] * (n + 1)

def find(i):
	if uf[i] < 0:
		return i
	else:
		uf[i] = find(uf[i])
		return uf[i]
for (x, y, z) in xyz:
	(px, py) = (find(x), find(y))
	if px != py:
		(px, py) = (px, py) if uf[py] < uf[px] else (px, py)
		uf[px] += uf[py]
		uf[py] = px
ans = sum([1 for i in range(1, n + 1) if uf[i] < 0])
print(ans)


import sys
input = sys.stdin.readline
from collections import Counter

def read():
	(N, M) = list(map(int, input().strip().split()))
	XYZ = []
	for i in range(M):
		(x, y, z) = list(map(int, input().strip().split()))
		XYZ.append((x, y, z))
	return (N, M, XYZ)

class UnionFind:

	def __init__(self, n):
		self.n = n
		self.parent = [x for x in range(n)]

	def find(self, x):
		if self.parent[x] == x:
			return x
		else:
			self.parent[x] = self.find(self.parent[x])
			return self.parent[x]

	def union(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x > y:
			(x, y) = (y, x)
		self.parent[y] = x

	def parents(self):
		return [self.find(x) for x in range(self.n)]

def solve(N, M, XYZ):
	uf = UnionFind(N)
	for (x, y, z) in XYZ:
		uf.union(x - 1, y - 1)
	C = Counter(uf.parents())
	return len(C)

def __starting_point():
	inputs = read()
	print(solve(*inputs))
__starting_point()


class Graph:

	def __init__(self):
		self.adjacency_dict = {}

	def add_vertex(self, v):
		self.adjacency_dict[v] = []

	def add_edge(self, v1, v2):
		self.adjacency_dict[v1].append(v2)
		self.adjacency_dict[v2].append(v1)

	def remove_edge(self, v1, v2):
		self.adjacency_dict[v1].remove(v2)
		self.adjacency_dict[v2].remove(v1)

	def remove_vertex(self, v):
		while self.adjacency_dict[v] != []:
			adjacency_vertex = self.adjacency_dict[v][-1]
			self.remove_edge(v, adjacency_vertex)
		del adjacency_vertex[v]

	def get_vertexes(self):
		return list(self.adjacency_dict.keys())

	def get_edges(self, v):
		return self.adjacency_dict[v]

	def print_graph(self):
		print(self.adjacency_dict)
(n, m) = list(map(int, input().strip().split()))
xyz = [list(map(int, input().strip().split())) for _ in range(m)]
g = Graph()
for i in range(n):
	g.add_vertex(i)
for i in range(m):
	g.add_edge(xyz[i][0] - 1, xyz[i][1] - 1)
res = 0
reached_nodes = [0 for _ in range(n)]
for i in g.get_vertexes():
	if reached_nodes[i] == 1:
		continue
	res += 1
	reached_nodes[i] = 1
	q = [i]
	while len(q) > 0:
		u = q.pop()
		for v in g.get_edges(u):
			if reached_nodes[v] == 1:
				continue
			q.append(v)
			reached_nodes[v] = 1
print(res)


(n, m) = map(int, input().split())
fa = {i: i for i in range(1, n + 1)}
cnt = n

def getfa(x):
	if fa[x] == x:
		return x
	fa[x] = getfa(fa[x])
	return fa[x]
for i in range(m):
	(x, y, z) = map(int, input().split())
	fx = getfa(x)
	fy = getfa(y)
	if fx != fy:
		cnt -= 1
	fa[fy] = fx
print(cnt)


class UnionFind:

	def __init__(self, N):
		self.root = list(range(N))
		self.size = [1] * N

	def find_root(self, x):
		root = self.root
		while root[x] != x:
			root[x] = root[root[x]]
			x = root[x]
		return x

	def merge(self, x, y):
		x = self.find_root(x)
		y = self.find_root(y)
		if x == y:
			return
		(sx, sy) = (self.size[x], self.size[y])
		if sx < sy:
			self.root[x] = y
			self.size[y] += sx
		else:
			self.root[y] = x
			self.size[x] += sy
(n, m) = map(int, input().split())
xyz = []
for i in range(m):
	xyz.append(list(map(int, input().split())))
uf = UnionFind(n)
answer = []
find_root = uf.find_root
merge = uf.merge
for i in range(m):
	(x, y, z) = (xyz[i][0] - 1, xyz[i][1] - 1, xyz[i][2])
	merge(x, y)
s = set([])
for i in range(n):
	s.add(uf.find_root(i))
print(len(s))


(N, M) = map(int, input().split())
xyz = [list(map(int, input().split())) for _ in [0] * M]
par = [-1] * N

def get_parent(n):
	if par[n] == -1:
		return n
	else:
		par[n] = get_parent(par[n])
		return par[n]

def merge(i, j):
	i = get_parent(i)
	j = get_parent(j)
	if i != j:
		par[j] = i
	return
for (x, y, z) in xyz:
	merge(x - 1, y - 1)
print(par.count(-1))


from collections import deque
(N, M) = list(map(int, input().split()))
graph = [[] for _ in range(N + 1)]
for _ in range(M):
	(a, b, c) = map(int, input().split())
	graph[a].append(b)
	graph[b].append(a)
seen = [False] * (N + 1)
count = 0
for i in range(1, N + 1):
	if seen[i] == False:
		seen[i] = True
		S = deque([i])
		while S:
			v = S.popleft()
			for i in graph[v]:
				if seen[i] == False:
					seen[i] = True
					S.append(i)
		count += 1
print(count)


(N, M) = map(int, input().split())
root = [-1] * N

def find(i):
	global root
	if root[i] >= 0:
		root[i] = find(root[i])
		return root[i]
	return i
for i in range(M):
	(X, Y, Z) = map(int, input().split())
	rx = find(X - 1)
	ry = find(Y - 1)
	if rx == ry:
		continue
	elif root[rx] <= root[ry]:
		root[rx] += root[ry]
		root[ry] = rx
	elif root[rx] > root[ry]:
		root[ry] += root[rx]
		root[rx] = ry
ans = 0
for r in root:
	if r < 0:
		ans += 1
print(ans)


import sys
sys.setrecursionlimit(3 * 10 ** 5)
(N, M) = map(int, input().split())
adj = [[] for i in range(N + 1)]
for i in range(M):
	(u, v, w) = map(int, input().split())
	adj[u].append(v)
	adj[v].append(u)
vis = [False for i in range(N + 1)]

def bfs(s):
	frontier = [s]
	ptr = 0
	while ptr < len(frontier):
		u = frontier[ptr]
		if not vis[u]:
			vis[u] = True
			for v in adj[u]:
				if not vis[v]:
					frontier.append(v)
		ptr += 1
ans = 0
for u in range(1, N + 1):
	if not vis[u]:
		ans += 1
		bfs(u)
print(ans)


(n, m) = list(map(int, input().split()))
xy = []
for _ in range(m):
	(x, y, _) = list(map(int, input().split()))
	xy.append((x - 1, y - 1))

class UF:

	def __init__(self, n):
		self.n = n
		self.g = list(range(n))
		self.vertices = list(range(n))

	def union(self, i0, i1):
		(g0, g1) = (self.find(i0), self.find(i1))
		(g0, g1) = (min(g0, g1), max(g0, g1))
		self.g[g1] = g0

	def find(self, i):
		path = []
		while self.g[i] != i:
			path.append(i)
			i = self.g[i]
		for j in path:
			self.g[j] = i
		return i
uf = UF(n)
for (x, y) in xy:
	uf.union(x, y)
g = set()
for x in range(n):
	g.add(uf.find(x))
answer = len(g)
print(answer)


def ketu(x, y):
	gx = get_g(x)
	gy = get_g(y)
	if dep[gy] > dep[gx]:
		(gx, gy) = (gy, gx)
	if dep[gy] == dep[gx]:
		dep[gx] += 1
	oya[gy] = gx

def get_g(x):
	oyax = oya[x]
	if oyax == x:
		return x
	re = oya[x] = get_g(oyax)
	return re
(n, m) = map(int, input().split())
oya = [i for i in range(n + 1)]
dep = [1] * (n + 1)
for _ in range(m):
	(x, y, z) = map(int, input().split())
	ketu(x, y)
for i in range(1, n + 1):
	get_g(i)
print(len(set(oya[1:])))


import sys
sys.setrecursionlimit(10 ** 6)
(N, M) = map(int, input().split())
XYZ = []
for _ in range(M):
	XYZ.append(tuple(map(int, input().split())))
G = [[] for _ in range(N + 1)]
for el in XYZ:
	(x, y, z) = el
	G[x].append(y)
	G[y].append(x)
seen = [False] * (N + 1)

def dfs(parent):
	seen[parent] = True
	for child in G[parent]:
		if seen[child] == False:
			dfs(child)
cnt = 0
for start in range(1, N + 1):
	if seen[start] == False:
		dfs(start)
		cnt += 1
print(cnt)


import sys, math, collections, itertools
input = sys.stdin.readline
(N, M) = list(map(int, input().split()))
road = [[] for _ in range(N + 1)]
for _ in range(M):
	(x, y, _) = list(map(int, input().split()))
	road[x].append(y)
	road[y].append(x)
no_visit = set(list(range(1, N + 1)))
q = collections.deque([])
cnt = 0
while no_visit:
	q.append(no_visit.pop())
	cnt += 1
	while q:
		now = q.popleft()
		for nxt in road[now]:
			if nxt in no_visit:
				q.append(nxt)
				no_visit.discard(nxt)
print(cnt)


from collections import deque
(N, M) = map(int, input().split())
G = [[] for i in range(N + 1)]
for i in range(M):
	(x, y, z) = map(int, input().split())
	G[x].append(y)
	G[y].append(x)
cnt = 0
seen = [False] * (N + 1)
for i in range(1, N + 1):
	if seen[i] == False:
		seen[i] = True
		cnt += 1
		d = deque([i])
		while len(d) > 0:
			v = d.popleft()
			for j in G[v]:
				if seen[j] == False:
					seen[j] = True
					d.append(j)
print(cnt)


(N, M) = map(int, input().split())
import networkx as nx
G = nx.Graph()
for i in range(1, N + 1):
	G.add_node(i)
for i in range(0, M):
	(A, B, C) = map(int, input().split())
	G.add_edge(A, B)
print(nx.number_connected_components(G))


import sys
sys.setrecursionlimit(10 ** 6)
(n, m) = map(int, input().split())
t = [[] for i in range(n)]
c = [-1 for i in range(n)]
for i in range(m):
	(x, y, z) = map(int, input().split())
	x -= 1
	y -= 1
	t[x].append(y)
	t[y].append(x)

def dfs(num, depth):
	if c[num] != -1:
		return
	else:
		c[num] = depth
	for i in t[num]:
		dfs(i, depth)
cnt = 0
for i in range(n):
	if c[i] == -1:
		cnt += 1
		dfs(i, cnt)
print(max(c))


(n, m) = map(int, input().split())
XYZ = [list(map(int, input().split())) for _ in range(m)]

def search(UF, loc):
	if UF[loc] == loc:
		return UF[loc]
	else:
		UF[loc] = search(UF, UF[loc])
		return UF[loc]
dic = [0] * (n + 1)
A = [0] * (n + 1)
UF = [_ for _ in range(n + 1)]
for (x, y, z) in XYZ:
	UF[x] = search(UF, x)
	UF[y] = search(UF, y)
	if UF[x] != UF[y]:
		UF[max(UF[x], UF[y])] = min(UF[x], UF[y])
for i in range(1, n + 1):
	temp = search(UF, i)
	dic[temp] = 1
print(sum(dic))


(N, M) = map(int, input().split())
tree = [[] for i in range(N)]
ischecked = [0] * N
ans = 0
for i in range(M):
	(X, Y, Z) = map(int, input().split())
	tree[X - 1].append(Y - 1)
	tree[Y - 1].append(X - 1)
for i in range(N):
	if ischecked[i] == 1:
		continue
	ischecked[i] = 1
	q = tree[i]
	while q:
		a = q.pop()
		if ischecked[a] == 1:
			continue
		ischecked[a] = 1
		q.extend(tree[a])
	ans = ans + 1
print(ans)


def c_show(graph, x):
	seen = set()
	nodes = set([x])
	while nodes:
		cur = nodes.pop()
		seen.add(cur)
		nodes |= set(graph[cur]) - seen
	return seen

def c_cnt(graph, n):
	done = set()
	cnt = 0
	for x in range(n):
		if x not in done:
			done |= c_show(graph, x)
			cnt += 1
	return cnt
(n, m) = map(int, input().split())
g = [list() for _ in range(n)]
for _ in range(m):
	(x, y, z) = map(int, input().split())
	g[x - 1].append(y - 1)
	g[y - 1].append(x - 1)
print(c_cnt(g, n))


def find(x):
	if par[x] < 0:
		return x
	else:
		par[x] = find(par[x])
		return par[x]

def unite(x, y):
	x = find(x)
	y = find(y)
	if x == y:
		return False
	if par[x] > par[y]:
		(x, y) = (y, x)
	par[x] += par[y]
	par[y] = x
	return True
import bisect
(n, m) = map(int, input().split())
par = [-1] * n
for _ in range(m):
	(x, y, z) = map(int, input().split())
	unite(x - 1, y - 1)
par.sort()
print(bisect.bisect_left(par, 0))


def unite(rt, x, y):
	tx = x
	ty = y
	if tx > ty:
		(tx, ty) = (ty, tx)
	rt[ty] = tx

def find(rt, x):
	if rt[x] == -1 or rt[x] == x:
		return x
	else:
		rt[x] = find(rt, rt[x])
		return rt[x]

def main():
	(n, m) = map(int, input().split())
	rt = [-1] * (n + 1)
	ans = n
	for i in range(m):
		(x, y, z) = map(int, input().split())
		root_x = find(rt, x)
		root_y = find(rt, y)
		if root_x == -1 or root_y == -1:
			pass
		elif root_x == root_y:
			continue
		ans -= 1
		unite(rt, root_x, root_y)
	print(ans)
main()


from networkx.utils import groups

class UnionFind:

	def __init__(self, elements=None):
		if elements is None:
			elements = ()
		self.parents = {}
		self.weights = {}
		for x in elements:
			self.weights[x] = 1
			self.parents[x] = x

	def __getitem__(self, object):
		if object not in self.parents:
			self.parents[object] = object
			self.weights[object] = 1
			return object
		path = [object]
		root = self.parents[object]
		while root != path[-1]:
			path.append(root)
			root = self.parents[root]
		for ancestor in path:
			self.parents[ancestor] = root
		return root

	def __iter__(self):
		return iter(self.parents)

	def to_sets(self):
		for x in list(self.parents.keys()):
			_ = self[x]
		for block in list(groups(self.parents).values()):
			yield block

	def union(self, *objects):
		roots = [self[x] for x in objects]
		heaviest = max(roots, key=lambda r: self.weights[r])
		for r in roots:
			if r != heaviest:
				self.weights[heaviest] += self.weights[r]
				self.parents[r] = heaviest

def main():
	(N, M) = list(map(int, input().split()))
	XYZ = [list(map(int, input().split())) for _ in range(M)]
	u = UnionFind(list(range(1, N + 1)))
	for (x, y, z) in XYZ:
		u.union(x, y)
	print(len(list(u.to_sets())))
main()


(N, M) = map(int, input().split())
P = [i for i in range(N + 1)]
size = [1 for i in range(N + 1)]

def find(x):
	if P[x] == x:
		return x
	else:
		return find(P[x])

def union(y, z):
	Y = find(y)
	Z = find(z)
	if Y != Z:
		if size[Y] >= size[Z]:
			P[Z] = P[Y]
			size[Y] += size[Z]
		else:
			P[Y] = P[Z]
			size[Z] += size[Y]
for i in range(M):
	(x, y, z) = map(int, input().split())
	if find(x) != find(y):
		union(x, y)
ans = 0
for i in range(1, N + 1):
	if i == P[i]:
		ans += 1
print(ans)


from collections import deque
(N, M) = map(int, input().split())
tree = dict(zip([i for i in range(N)], [[] for i in range(N)]))
for i in range(M):
	(X, Y, Z) = map(int, input().split())
	tree[X - 1].append(Y - 1)
	tree[Y - 1].append(X - 1)
ans = 0
is_used = [False] * N
for i in range(N):
	if is_used[i]:
		continue
	ans += 1
	is_used[i] = True
	d = deque([i])
	while d:
		node = d.pop()
		children = tree[node]
		for child in children:
			if is_used[child]:
				continue
			is_used[child] = True
			d.append(child)
print(ans)


(N, M) = (int(x) for x in input().split())
adj_list = [[] for i in range(N)]
for i in range(M):
	(x, y, z) = (int(x) for x in input().split())
	adj_list[x - 1].append(y - 1)
	adj_list[y - 1].append(x - 1)
searched = [False] * N
count = 0
for i in range(N):
	if searched[i] == True:
		continue
	count += 1
	stack = [i]
	searched[i] = True
	while len(stack) > 0:
		node = stack.pop()
		for n in adj_list[node]:
			if searched[n] == False:
				stack.append(n)
				searched[n] = True
print(count)


import sys
sys.setrecursionlimit(10 ** 8)
(N, M) = map(int, input().split())
edge = [[] for _ in range(N)]
for i in range(M):
	(a, b, c) = map(int, input().split())
	edge[a - 1].append(b - 1)
	edge[b - 1].append(a - 1)

def dfs(v):
	if len(edge[v]) == 0:
		return 0
	for u in edge[v]:
		if visited[u] == False:
			visited[u] = True
			dfs(u)
	return 0
ans = 0
visited = [False] * N
for i in range(N):
	if visited[i] == False:
		visited[i] = True
		dfs(i)
		ans += 1
print(ans)


import sys
sys.setrecursionlimit(10 ** 7)
input = sys.stdin.readline
(n, m) = map(int, input().split())
graph = [[] for _ in range(n)]
for i in range(m):
	(x, y, z) = map(int, input().split())
	x -= 1
	y -= 1
	graph[x].append(y)
	graph[y].append(x)
memo = [-1] * n

def dfs(v, memo):
	memo[v] = 1
	for nv in graph[v]:
		if memo[nv] != -1:
			continue
		dfs(nv, memo)
ans = 0
for i in range(n):
	if memo[i] != -1:
		continue
	dfs(i, memo)
	ans += 1
print(ans)


import sys
sys.setrecursionlimit(10 ** 6)

def root(x):
	if c[x] == x:
		return x
	else:
		c[x] = root(c[x])
		return c[x]

def uni(x, y):
	rx = root(x)
	ry = root(y)
	c[ry] = rx
(n, m) = map(int, input().split())
c = [i for i in range(n)]
for i in range(m):
	(x, y, z) = map(int, input().split())
	x -= 1
	y -= 1
	uni(x, y)
for i in range(n):
	root(i)
print(len(set(c)))


import sys
sys.setrecursionlimit(1000000)
(N, M) = list(map(int, input().split()))
XYZ = [list(map(int, input().split())) for _ in range(M)]
G = [[] for _ in range(N)]
for i in XYZ:
	G[i[0] - 1].append(i[1])
	G[i[1] - 1].append(i[0])
check = [False for _ in range(N)]

def DFS(G, s):
	check[s - 1] = True
	for i in G[s - 1]:
		if not check[i - 1]:
			DFS(G, i)
ans = 0
for i in range(N):
	if not check[i]:
		DFS(G, i + 1)
		ans += 1
print(ans)


import sys
sys.setrecursionlimit(10 ** 6)
(N, M) = map(int, input().split())
G = [[] for _ in range(N)]
for i in range(M):
	(X, Y, Z) = map(int, input().split())
	X -= 1
	Y -= 1
	G[X].append(Y)
	G[Y].append(X)

def dfs(u, v):
	for t in G[u]:
		if not Visited[t]:
			Visited[t] = True
			dfs(t, u)
Visited = [False for _ in range(N)]
ans = 0
for i in range(N):
	if not Visited[i]:
		Visited[i] = True
		ans += 1
		dfs(i, -1)
print(ans)


import sys
sys.setrecursionlimit(100010)
(N, M) = map(int, input().split())
E = [[] for k in range(N)]
for k in range(M):
	(X, Y, Z) = map(int, input().split())
	E[X - 1].append(Y - 1)
	E[Y - 1].append(X - 1)
G = [-1] * N

def dfs(now, group):
	if G[now] == -1:
		G[now] = group
		for tsugi in E[now]:
			dfs(tsugi, group)
ans = 0
for k in range(N):
	if G[k] == -1:
		dfs(k, ans)
		ans += 1
print(ans)


from collections import deque
(N, M) = map(int, input().split())
E = [[] for _ in range(N + 1)]
for i in range(M):
	(x, y, z) = map(int, input().split())
	E[x].append(y)
	E[y].append(x)
d = [-1] * (N + 1)

def dfs(start, num):
	q = deque([start])
	d[start] = num
	while q:
		v = q.pop()
		for s in E[v]:
			if d[s] == -1:
				d[s] = num
				q.append(s)
group_num = 0
for i in range(1, N + 1):
	if d[i] == -1:
		group_num += 1
		dfs(i, group_num)
print(group_num)


import sys
sys.setrecursionlimit(500000)
(N, M) = map(int, input().split())
A = [[] for _ in range(N)]
for i in range(M):
	(a, b, c) = map(int, input().split())
	a -= 1
	b -= 1
	A[a].append(b)
	A[b].append(a)
reach = [-1 for _ in range(N)]

def dfs(v):
	if reach[v] != -1:
		return
	else:
		reach[v] = 1
	for u in A[v]:
		dfs(u)
test = 0
for i in range(N):
	if reach[i] == -1:
		dfs(i)
		test += 1
print(test)


def union_find():

	def get_parent(node):
		if par[node] == -1:
			return node
		else:
			par[node] = get_parent(par[node])
			return par[node]

	def merge(i, j):
		i = get_parent(i)
		j = get_parent(j)
		if i != j:
			par[j] = i
		return
	(n, m) = map(int, input().split())
	xyz = [list(map(int, input().split())) for _ in range(m)]
	par = [-1] * n
	for (x, y, z) in xyz:
		merge(x - 1, y - 1)
	print(par.count(-1))
union_find()


import sys
sys.setrecursionlimit(10 ** 6)
(n, m) = map(int, input().split())
adjacent_list = [[] for i in range(n + 1)]
for i in range(m):
	(x, y, z) = map(int, input().split())
	adjacent_list[x].append(y)
	adjacent_list[y].append(x)
finished = set()
ans = 0

def dfs(node):
	global finished
	finished.add(node)
	for i in adjacent_list[node]:
		if i not in finished:
			dfs(i)
while len(finished) != n:
	for i in range(1, n + 1):
		if i not in finished:
			dfs(i)
			ans += 1
print(ans)


import sys
input = sys.stdin.readline
(n, m) = map(int, input().split())
g = [[] for _ in range(n)]
for i in range(m):
	(x, y, z) = map(int, input().split())
	(x, y) = (x - 1, y - 1)
	g[x].append(y)
	g[y].append(x)
s = []
visit = [-1] * n
cnt = 0
for i in range(n):
	if visit[i] == -1:
		s.append(i)
		cnt += 1
		visit[i] = cnt
		while s:
			v = s.pop()
			for u in g[v]:
				if visit[u] == -1:
					visit[u] = visit[v]
					s.append(u)
print(max(visit))


(N, M) = map(int, input().split())
XYZ = [[int(x) for x in input().split()] for _ in range(M)]
par = [i for i in range(N)]
rank = [0] * N

def root(x):
	tmp = x
	while par[tmp] != tmp:
		tmp = par[tmp]
	return tmp

def unite(x, y):
	rx = root(x)
	ry = root(y)
	if rx == ry:
		return
	if rank[rx] < rank[ry]:
		(rx, ry) = (ry, rx)
	if rank[rx] == rank[ry]:
		rank[rx] += 1
	par[ry] = rx
for (x, y, z) in XYZ:
	unite(x - 1, y - 1)
ans = 0
for i in range(N):
	if par[i] == i:
		ans += 1
print(ans)


(n, m) = list(map(int, input().split()))
edges = [[] for i in range(n)]
for i in range(m):
	(tx, ty, _tz) = list(map(int, input().split()))
	edges[tx - 1].append(ty - 1)
	edges[ty - 1].append(tx - 1)
visited = [False] * n
ans = 0
for i in range(n):
	if not visited[i]:
		q = [i]
		visited[i] = True
		while q:
			u = q.pop(0)
			for v in edges[u]:
				if not visited[v]:
					q.append(v)
					visited[v] = True
		ans += 1
print(ans)


class UnionFind:

	def __init__(self, n):
		self.p = [i for i in range(n)]
		self.components = n

	def root(self, x):
		if self.p[x] == x:
			return x
		else:
			self.p[x] = self.root(self.p[x])
			return self.p[x]

	def unite(self, x, y):
		(x, y) = (self.root(x), self.root(y))
		if x != y:
			self.p[x] = y
			self.components -= 1

	def same(self, x, y):
		return self.root(x) == self.root(y)
(N, M) = map(int, input().split())
UF = UnionFind(N)
for _ in range(M):
	(X, Y, Z) = map(int, input().split())
	(X, Y) = (X - 1, Y - 1)
	UF.unite(X, Y)
print(UF.components)


class UnionFind(object):

	def __init__(self, size):
		self.parent = [i for i in range(size)]
		self.rank = [0] * size

	def find(self, x):
		if self.parent[x] == x:
			return x
		self.parent[x] = self.find(self.parent[x])
		return self.parent[x]

	def unite(self, x, y):
		(x, y) = (self.find(x), self.find(y))
		if x == y:
			return
		if self.rank[x] < self.rank[y]:
			self.parent[x] = y
		else:
			self.parent[y] = x
			if self.rank[x] == self.rank[y]:
				self.rank[x] += 1

	def same(self, x, y):
		return self.find(x) == self.find(y)
(N, M) = map(int, input().split())
uf = UnionFind(N)
for _ in range(M):
	(x, y, z) = map(int, input().split())
	uf.unite(x - 1, y - 1)
for i in range(N):
	uf.find(i - 1)
s = set(uf.parent)
print(len(s))


class UnionFind:

	def __init__(self, n):
		self.n = n
		self.root = [-1] * n
		self.rank = [0] * n

	def find(self, x):
		if self.root[x - 1] < 0:
			return x
		else:
			self.root[x - 1] = self.find(self.root[x - 1])
			return self.root[x - 1]

	def unite(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return
		elif self.rank[x - 1] > self.rank[y - 1]:
			self.root[x - 1] += self.root[y - 1]
			self.root[y - 1] = x
		else:
			self.root[y - 1] += self.root[x - 1]
			self.root[x - 1] = y
			if self.rank[x - 1] == self.rank[y - 1]:
				self.rank[y - 1] += 1

	def same(self, x, y):
		return self.find(x) == self.find(y)

	def count(self, x):
		return -self.root[self.find(x) - 1]
(N, M) = map(int, input().split())
uf = UnionFind(N)
for i in range(M):
	(x, y, z) = map(int, input().split())
	uf.unite(x, y)
s = set()
ans = 0
for i in range(1, N + 1):
	if uf.find(i) not in s:
		s.add(uf.find(i))
		ans += 1
print(ans)


import collections
import sys
sys.setrecursionlimit(100000)

def root(X):
	if cards[X] == X:
		return X
	else:
		cards[X] = root(cards[X])
		return cards[X]

def unite(X, Y):
	x = root(X)
	y = root(Y)
	if x == y:
		return
	else:
		cards[x] = y

def same(X, Y):
	return root(X) == root(Y)

def show(x):
	print(cards[x])
(N, M) = [int(i) for i in input().split()]
cards = [i for i in range(N + 1)]
for i in range(M):
	(X, Y, Z) = [int(i) for i in input().split()]
	if same(X, Y):
		pass
	else:
		unite(X, Y)
a = []
for i in range(1, N + 1):
	a.append(root(cards[i]))
print(len(set(a)))


(n, m) = map(int, input().split())
c = list(range(n + 1))
k = n
a = []
for i in range(n + 1):
	a.append([i])
for i in range(m):
	(x, y, z) = map(int, input().split())
	t = c[x]
	s = c[y]
	if t == s:
		continue
	if len(a[s]) > len(a[t]):
		(t, s) = (s, t)
	a[t] += a[s]
	for z in a[s]:
		c[z] = t
	a[s] = []
	k -= 1
print(k)


import sys
mod = 10 ** 9 + 7
sys.setrecursionlimit(mod)
(N, M) = map(int, input().split())
adj = {i: set() for i in range(1, N + 1)}
for i in range(M):
	(x, y, z) = map(int, input().split())
	adj[x].add(y)
	adj[y].add(x)
V = set()

def dfs(v):
	if v not in V:
		V.add(v)
		for u in adj[v]:
			dfs(u)
cnt = 0
for i in range(1, N + 1):
	if i not in V:
		cnt += 1
		dfs(i)
print(cnt)


(N, M) = map(int, input().split())
graph = [[] for _ in range(N + 1)]
for i in range(M):
	(X, Y, Z) = map(int, input().split())
	graph[X].append(Y)
	graph[Y].append(X)
answer = 0
stack = []
seen = [0] * (N + 1)
for i in range(1, N + 1):
	if seen[i] == 0:
		answer += 1
		seen[i] = 1
		if len(graph[i]):
			stack.append(i)
			while stack:
				s = stack.pop()
				for g in graph[s]:
					if seen[g] == 0:
						stack.append(g)
						seen[g] = 1
print(answer)


import sys
sys.setrecursionlimit(10 ** 7)
input = lambda : sys.stdin.readline().rstrip()
(n, m) = map(int, input().split())
g = [list() for i in range(n)]
for _ in range(m):
	(x, y, z) = map(int, input().split())
	x -= 1
	y -= 1
	g[x].append(y)
	g[y].append(x)
visited = [False] * n

def dfs(v, p):
	visited[v] = True
	for nv in g[v]:
		if nv == p or visited[nv]:
			continue
		dfs(nv, v)
cnt = 0
for v in range(n):
	if not visited[v]:
		dfs(v, -1)
		cnt += 1
print(cnt)


import sys
readline = sys.stdin.readline
(N, M) = list(map(int, readline().split()))

class UnionFind:
	N = 0
	parent = None
	size = None

	def __init__(self, N):
		self.N = N
		self.parent = [i for i in range(self.N)]
		self.size = [1] * self.N

	def root(self, x):
		while x != self.parent[x]:
			self.parent[x] = self.parent[self.parent[x]]
			x = self.parent[x]
		return x

	def same(self, x, y):
		return self.root(x) == self.root(y)

	def unite(self, x, y):
		x = self.root(x)
		y = self.root(y)
		if x == y:
			return
		if self.size[x] > self.size[y]:
			self.parent[y] = x
			self.size[x] += self.size[y]
		else:
			self.parent[x] = y
			self.size[y] += self.size[x]

	def get_group_size(self, x):
		return self.size[self.root(x)]

	def get_roots(self):
		r = set()
		for i in range(self.N):
			r.add(self.root(i))
		return r

	def show_parent(self):
		print(self.parent)

	def show_size(self):
		print(self.size)
UF = UnionFind(N)
for i in range(M):
	(x, y, z) = list(map(int, readline().split()))
	UF.unite(x - 1, y - 1)
print(len(UF.get_roots()))


(N, M) = map(int, input().split())
G = [[] for _ in range(N)]
for i in range(M):
	(x, y, z) = map(int, input().split())
	G[x - 1].append(y - 1)
	G[y - 1].append(x - 1)
lst = []
visited = [0] * N
for i in range(N):
	if visited[i] == 1:
		continue
	temp = [i]
	lst1 = [i]
	visited[i] = 1
	while temp:
		p = temp.pop()
		for q in G[p]:
			if visited[q] == 0:
				visited[q] = 1
				lst1.append(q)
				temp.append(q)
	if lst1 != []:
		lst.append(lst1)
print(len(lst))


import sys
sys.setrecursionlimit(10 ** 7)
(n, m) = map(int, input().split())
a = [[] for i in range(n)]
for i in range(m):
	(u, v, w) = map(int, input().split())
	a[u - 1].append((v - 1, w))
	a[v - 1].append((u - 1, w))
b = [None for i in range(n)]

def k(v, dis):
	b[v] = dis
	for (next_v, w) in a[v]:
		if b[next_v] != None:
			continue
		if w % 2 == 0:
			k(next_v, dis)
		else:
			k(next_v, 1 - dis)
c2 = 0
for i in range(n):
	if b[i] == None:
		k(i, 0)
		c2 += 1
print(c2)


(N, M) = map(int, input().split())
t = [[] for _ in range(N)]
visited = [0] * N
for _ in range(M):
	(X, Y, Z) = map(int, input().split())
	X -= 1
	Y -= 1
	t[X].append(Y)
	t[Y].append(X)
ans = 0
for i in range(N):
	if visited[i]:
		continue
	ans += 1
	stack = [i]
	while stack:
		s = stack.pop()
		for to in t[s]:
			if visited[to]:
				continue
			visited[to] = 1
			stack.append(to)
print(ans)


import sys
sys.setrecursionlimit(10 ** 7)

def update(v):
	for nv in G[v]:
		if seen[nv]:
			continue
		seen[nv] = 1
		update(nv)
(N, M) = map(int, input().split())
seen = [0] * N
G = [[] for i in range(N)]
for i in range(M):
	(X, Y, Z) = map(int, input().split())
	(X, Y) = (X - 1, Y - 1)
	G[X].append(Y)
	G[Y].append(X)
ans = 0
for i in range(N):
	if seen[i]:
		continue
	ans += 1
	seen[i] = 1
	update(i)
print(ans)


(N, M) = map(int, input().split())
nodes = [i for i in range(N)]

def root(x):
	if nodes[x] == x:
		return x
	else:
		nodes[x] = root(nodes[x])
	return nodes[x]

def same(x, y):
	return root(x) == root(y)

def unite(x, y):
	if not same(x, y):
		nodes[root(x)] = root(y)
for _ in range(M):
	(X, Y, Z) = map(int, input().split())
	unite(X - 1, Y - 1)
ans = 0
for i in range(len(nodes)):
	if nodes[i] == i:
		ans += 1
print(ans)


from queue import Queue
(N, M) = map(int, input().split())
d = {}
for i in range(1, N + 1):
	d[i] = []
for i in range(M):
	(x, y, z) = map(int, input().split())
	d[x].append(y)
	d[y].append(x)
isChecked = [False for i in range(N)]
ans = 0
for k in d:
	if isChecked[k - 1]:
		continue
	ans += 1
	q = Queue()
	q.put(k)
	while not q.empty():
		v = q.get()
		if isChecked[v - 1]:
			continue
		isChecked[v - 1] = True
		for u in d[v]:
			q.put(u)
print(ans)


def main():
	(N, M) = map(int, input().split())
	known = [False] * N
	rel = [list() for _ in range(N)]
	for _ in range(M):
		(x, y, z) = list(map(int, input().split()))
		rel[x - 1].append(y - 1)
		rel[y - 1].append(x - 1)
	r = 0
	for i in range(N):
		if known[i]:
			continue
		known[i] = True
		r += 1
		cur = rel[i].copy()
		while cur:
			t = cur.pop()
			if not known[t]:
				cur.extend(rel[t])
				known[t] = True
	print(r)
main()


(N, M) = map(int, input().split())
par = [i for i in range(N)]
rank = [0 for i in range(N)]

def root(x):
	if par[x] == x:
		return x
	else:
		par[x] = root(par[x])
		return par[x]

def unite(x, y):
	(x, y) = (root(x), root(y))
	if x != y:
		if rank[x] < rank[y]:
			par[x] = y
		else:
			par[y] = x
			if rank[x] == rank[y]:
				rank[x] += 1
for i in range(M):
	(X, Y, Z) = map(int, input().split())
	unite(X - 1, Y - 1)
for i in range(N):
	root(i)
print(len(set(par)))


import sys

def solve(N: int, M: int, X: 'List[int]', Y: 'List[int]', Z: 'List[int]'):
	X = [x - 1 for x in X]
	Y = [x - 1 for x in Y]
	uf = UnionFind(N)
	for (x, y) in zip(X, Y):
		uf.union(x, y)
	return len(uf.roots())

def main():

	def iterate_tokens():
		for line in sys.stdin:
			for word in line.split():
				yield word
	tokens = iterate_tokens()
	N = int(next(tokens))
	M = int(next(tokens))
	X = [int()] * M
	Y = [int()] * M
	Z = [int()] * M
	for i in range(M):
		X[i] = int(next(tokens))
		Y[i] = int(next(tokens))
		Z[i] = int(next(tokens))
	print(solve(N, M, X, Y, Z))

class UnionFind:

	def __init__(self, n):
		self.n = n
		self.parents = [-1] * n

	def find(self, x):
		if self.parents[x] < 0:
			return x
		else:
			self.parents[x] = self.find(self.parents[x])
			return self.parents[x]

	def union(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return
		if self.parents[x] > self.parents[y]:
			(x, y) = (y, x)
		self.parents[x] += self.parents[y]
		self.parents[y] = x

	def size(self, x):
		return -self.parents[self.find(x)]

	def same(self, x, y):
		return self.find(x) == self.find(y)

	def members(self, x):
		root = self.find(x)
		return [i for i in range(self.n) if self.find(i) == root]

	def roots(self):
		return [i for (i, x) in enumerate(self.parents) if x < 0]

	def group_count(self):
		return len(self.roots())

	def all_group_members(self):
		return {r: self.members(r) for r in self.roots()}

	def __str__(self):
		return '\n'.join(('{}: {}'.format(r, self.members(r)) for r in self.roots()))

def test():
	import doctest
	doctest.testmod()

def __starting_point():
	main()
__starting_point()


from typing import List

def main():

	def dfs(source: int) -> None:
		stack = [source]
		is_visited[source] = True
		while stack:
			u = stack.pop()
			for v in graph[u]:
				if is_visited[v]:
					continue
				is_visited[v] = True
				stack.append(v)
	(N, M, *X) = list(map(int, open(0).read().split()))
	graph: List[List[int]] = [[] for _ in range(N + 1)]
	for (x, y, _) in zip(*[iter(X)] * 3):
		(graph[x].append(y), graph[y].append(x))
	is_visited = [False] * (N + 1)
	res = 0
	for i in range(1, N + 1):
		if is_visited[i]:
			continue
		res += 1
		dfs(i)
	print(res)

def __starting_point():
	main()
__starting_point()


r = lambda x: x * (u[x] < 0) or r(u[x])
i = lambda : map(int, input().split()[:2])
(n, m) = i()
u = [-1] * -~n
while m:
	(x, y) = sorted(map(r, i()))
	m -= 1
	if x != y:
		u[x] += u[y]
		u[y] = x
print(sum((i < 0 for i in u)) - 1)


import sys
input = sys.stdin.readline
sys.setrecursionlimit(10 ** 9)
(n, m) = map(int, input().split())
GRAPH = {i: [] for i in range(1, n + 1)}
for _ in range(m):
	(x, y, z) = map(int, input().split())
	GRAPH[x].append(y)
	GRAPH[y].append(x)

def dfs(now):
	SEARCHED[now] = True
	for v in GRAPH[now]:
		if SEARCHED[v]:
			continue
		next = v
		dfs(next)
SEARCHED = {i: False for i in range(1, n + 1)}
count = 0
for i in range(1, n + 1):
	if SEARCHED[i]:
		continue
	dfs(i)
	count += 1
print(count)


import sys
sys.setrecursionlimit(1000000)
(n, m) = map(int, input().split())
edge = {i: [] for i in range(1, n + 1)}
graph = {i: -1 for i in range(1, n + 1)}
for _ in range(m):
	(x, y, z) = list(map(int, input().split()))
	edge[x].append(y)
	edge[y].append(x)

def color_graph(i, v):
	if graph[i] == -1:
		graph[i] = v
		for j in edge[i]:
			color_graph(j, v)
ans = 0
for i in range(1, n + 1):
	if graph[i] == -1:
		ans += 1
		color_graph(i, i)
print(ans)


import sys
sys.setrecursionlimit(1000000)
a = input().split()
N = int(a[0])
M = int(a[1])
l = []
f = []
for i in range(N):
	temp = []
	l.append(temp)
	f.append(0)
for i in range(M):
	b = input().split()
	X = int(b[0]) - 1
	Y = int(b[1]) - 1
	l[X].append(Y)
	l[Y].append(X)

def search(cnt, li, flag, num):
	if flag[num] == 0:
		flag[num] = cnt
		if len(li[num]) != 0:
			for i in range(len(li[num])):
				search(cnt, li, flag, li[num][i])
cnt = 0
for i in range(N):
	if f[i] == 0:
		cnt += 1
		search(cnt, l, f, i)
print(cnt)


class UnionFind:

	def __init__(self, n):
		self.n = n
		self.root = [-1] * n
		self.rank = [0] * n

	def find(self, x):
		if self.root[x - 1] < 0:
			return x
		else:
			self.root[x - 1] = self.find(self.root[x - 1])
			return self.root[x - 1]

	def unite(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return
		elif self.rank[x - 1] > self.rank[y - 1]:
			self.root[x - 1] += self.root[y - 1]
			self.root[y - 1] = x
			self.n -= 1
		else:
			self.n -= 1
			self.root[y - 1] += self.root[x - 1]
			self.root[x - 1] = y
			if self.rank[x - 1] == self.rank[y - 1]:
				self.rank[y - 1] += 1

	def same(self, x, y):
		return self.find(x) == self.find(y)

	def count(self, x):
		return -self.root[self.find(x) - 1]

	def num(self):
		return self.n
(N, M) = list(map(int, input().split()))
uf = UnionFind(N)
for i in range(M):
	(x, y, z) = list(map(int, input().split()))
	uf.unite(x, y)
print(uf.num())


(N, M) = map(int, input().split())
XY = [i for i in range(N + 1)]

def root(x):
	temp = x
	while temp != XY[temp]:
		temp = XY[temp]
	XY[x] = temp
	return temp
for _ in range(M):
	(x, y) = map(int, input().split()[:2])
	XY[root(x)] = root(y)
print(sum((i == v for (i, v) in enumerate(XY))) - 1)


from math import ceil, floor, factorial, gcd, sqrt, log2, cos, sin, tan, acos, asin, atan, degrees, radians, pi, inf
from itertools import accumulate, groupby, permutations, combinations, product, combinations_with_replacement
from collections import deque, defaultdict, Counter
from bisect import bisect_left, bisect_right
from operator import itemgetter
from heapq import heapify, heappop, heappush
from queue import Queue, LifoQueue, PriorityQueue
from copy import deepcopy
from time import time
from functools import reduce, lru_cache
import string
import sys
sys.setrecursionlimit(10 ** 7)

def input():
	return sys.stdin.readline().strip()

def INT():
	return int(input())

def MAP():
	return map(int, input().split())

def MAP1():
	return map(lambda x: int(x) - 1, input().split())

def LIST():
	return list(MAP())

def LIST1():
	return list(MAP1())

class UnionFind:

	def __init__(self, n):
		self.n = n
		self.parents = [-1] * n

	def find(self, x):
		if self.parents[x] < 0:
			return x
		else:
			self.parents[x] = self.find(self.parents[x])
			return self.parents[x]

	def union(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return
		if self.parents[x] > self.parents[y]:
			(x, y) = (y, x)
		self.parents[x] += self.parents[y]
		self.parents[y] = x

	def size(self, x):
		return -self.parents[self.find(x)]

	def same(self, x, y):
		return self.find(x) == self.find(y)

	def members(self, x):
		root = self.find(x)
		return [i for i in range(self.n) if self.find(i) == root]

	def roots(self):
		return [i for (i, x) in enumerate(self.parents) if x < 0]

	def group_count(self):
		return len(self.roots())

	def all_group_members(self):
		return {r: self.members(r) for r in self.roots()}

	def __str__(self):
		return '\n'.join(('{}: {}'.format(r, self.members(r)) for r in self.roots()))
(n, m) = MAP()
uf = UnionFind(n)
for i in range(m):
	(x, y, z) = MAP1()
	uf.union(x, y)
print(uf.group_count())


import sys
sys.setrecursionlimit(10 ** 5 + 10)
input = sys.stdin.readline

def dfs(v, G, visit):
	visit[v - 1] = 1
	for next in G[v - 1]:
		if visit[next - 1]:
			continue
		_ = dfs(next, G, visit)
(N, M) = map(int, input().split())
G = [[] for _ in range(N)]
for i in range(M):
	(a, b, _) = map(int, input().split())
	G[a - 1].append(b)
	G[b - 1].append(a)
count = 0
visit = [0] * N
for i in range(1, N + 1):
	if visit[i - 1]:
		continue
	if G[i - 1]:
		_ = dfs(i, G, visit)
	else:
		visit[i - 1] = 1
	count += 1
print(count)


import networkx as X
(n, m) = map(int, input().split())
g = X.Graph()
for i in range(n):
	g.add_node(i + 1)
for i in range(m):
	(x, y, z) = map(int, input().split())
	g.add_edge(x, y)
print(X.number_connected_components(g))


(N, M) = map(int, input().split())
Tree = [i for i in range(N)]
size = [1] * N

def find(x):
	if x == Tree[x]:
		return x
	else:
		Tree[x] = find(Tree[x])
		return Tree[x]

def unite(x, y):
	s1 = find(x)
	s2 = find(y)
	if s1 != s2:
		Tree[s2] = s1
		size[s1] += size[s2]
ans = N
for i in range(M):
	(X, Y, Z) = map(int, input().split())
	(X, Y) = (X - 1, Y - 1)
	if find(X) != find(Y):
		unite(X, Y)
		ans -= 1
print(ans)


import sys
sys.setrecursionlimit(10 ** 9)
(N, M) = map(int, input().split())
edge = [[] for _ in range(N)]
for _ in range(M):
	(x, y, z) = map(int, input().split())
	(x, y) = (x - 1, y - 1)
	edge[x].append(y)
	edge[y].append(x)
visited = [0] * N

def dfs(v):
	if visited[v] == 1:
		return
	visited[v] = 1
	for nv in edge[v]:
		dfs(nv)
ans = 0
for i in range(N):
	if visited[i] == 1:
		continue
	ans += 1
	dfs(i)
print(ans)


(n, m) = map(int, input().split())
a = [i for i in range(n + 1)]

def find(a, x):
	if a[x] != x:
		a[x] = find(a, a[x])
	return a[x]

def unite(a, x, y):
	x = find(a, x)
	y = find(a, y)
	if x != y:
		a[x] = min(x, y)
		a[y] = a[x]
for i in range(m):
	(x, y, z) = map(int, input().split())
	unite(a, x, y)
ans = -1
for (i, v) in enumerate(a):
	if i == v:
		ans += 1
print(ans)


(n, m) = map(int, input().split())
p = list(range(n))

def find(x):
	if p[x] != x:
		p[x] = find(p[x])
	return p[x]

def union(x, y):
	(x, y) = (find(x), find(y))
	p[x] = p[y] = min(x, y)
for _ in range(m):
	(x, y, z) = [int(i) - 1 for i in input().split()]
	if find(x) != find(y):
		union(x, y)
ans = set()
for i in range(n):
	find(i)
print(len(set(p)))


r = lambda x: x * (u[x] < 0) or r(u[x])
(n, m, *t) = map(int, open(0).read().split())
u = [-1] * -~n
for (x, y) in zip(t[::3], t[1::3]):
	(x, y) = sorted((r(x), r(y)))
	if x != y:
		u[x] += u[y]
		u[y] = x
print(sum((i < 0 for i in u)) - 1)


(n, m) = map(int, input().split())
parent = [i + 1 for i in range(n)]
rank = [0 for i in range(n)]

def find(x):
	if parent[x - 1] == x:
		return x
	else:
		parent[x - 1] = find(parent[x - 1])
		return parent[x - 1]

def unite(x, y):
	x = find(x)
	y = find(y)
	if x == y:
		return
	if rank[x - 1] < rank[y - 1]:
		parent[x - 1] = y
	else:
		parent[y - 1] = x
		if rank[x - 1] == rank[y - 1]:
			rank[x - 1] += 1
for i in range(m):
	(x, y, z) = map(int, input().split())
	unite(x, y)
ans = n
for i in range(n):
	if find(i + 1) != i + 1:
		ans -= 1
print(ans)


import sys
sys.setrecursionlimit(1000000)
(N, M) = map(int, input().split())
X = [i for i in range(N)]

def par(i):
	if X[i] == i:
		return i
	tmp = par(X[i])
	X[i] = tmp
	return tmp
ans = N
for _ in range(M):
	(x, y, z) = map(int, input().split())
	px = par(x - 1)
	py = par(y - 1)
	if px != py:
		ans -= 1
		X[py] = px
print(ans)


import sys
breadline = sys.stdin.buffer.readline
bread = sys.stdin.buffer.read
readline = sys.stdin.readline
read = sys.stdin.read
printout = sys.stdout.write
sprint = sys.stdout.flush
sys.setrecursionlimit(10 ** 7)
INF = 1 << 50
EPS = 1e-08
mod = 10 ** 9 + 7

def getnum(t=int):
	return t(breadline())

def numline(t=int):
	return map(t, breadline().split())

def numread(t=int):
	return map(t, bread().split())

def getstr():
	return readline().strip()

def strline():
	return readline().strip().split()

def strread():
	return read().strip().split()

def dfs(c, to, seen):
	for n in to[c]:
		if not seen[n]:
			seen[n] = 1
			dfs(n, to, seen)

def run():
	(N, M) = numline()
	to = [[] for _ in range(N + 1)]
	for _ in range(M):
		(x, y, z) = numline()
		to[x].append(y)
		to[y].append(x)
	G = []
	seen = [0] * (N + 1)
	for i in range(1, N + 1):
		if not seen[i]:
			seen[i] = 1
			dfs(i, to, seen)
			G.append(i)
	print(len(G))

def __starting_point():
	run()
__starting_point()


import sys
import collections
input_methods = ['clipboard', 'file', 'key']
using_method = 0
input_method = input_methods[using_method]
tin = lambda : map(int, input().split())
lin = lambda : list(tin())
mod = 1000000007

def main():
	(n, m) = tin()
	is_open = [-1] * n
	graph = [[] for _ in range(n)]
	for _ in range(m):
		(x, y, _) = tin()
		graph[x - 1].append(y - 1)
		graph[y - 1].append(x - 1)
	ret = 0
	for i in range(n):
		if is_open[i] > 0:
			continue
		ret += 1
		q = collections.deque()
		q.append(i)
		is_open[i] = 1
		while q:
			pos = q.pop()
			for t in graph[pos]:
				if is_open[t] > 0:
					continue
				is_open[t] = 1
				q.append(t)
	return ret
isTest = False

def pa(v):
	if isTest:
		print(v)

def input_clipboard():
	import clipboard
	input_text = clipboard.get()
	input_l = input_text.splitlines()
	for l in input_l:
		yield l

def __starting_point():
	if sys.platform == 'ios':
		if input_method == input_methods[0]:
			ic = input_clipboard()
			input = lambda : ic.__next__()
		elif input_method == input_methods[1]:
			sys.stdin = open('inputFile.txt')
		else:
			pass
		isTest = True
	else:
		pass
	ret = main()
	if ret is not None:
		print(ret)
__starting_point()


import sys
sys.setrecursionlimit(10 ** 9)
(n, m) = map(int, input().split())
xyz = [[] for i in range(n + 1)]
for _ in range(m):
	(x, y, z) = map(int, input().split())
	xyz[x].append(y)
	xyz[y].append(x)
ans = 0
visited = [False] * (n + 1)

def dfs(x):
	visited[x] = True
	for y in xyz[x]:
		if not visited[y]:
			dfs(y)
for x in range(1, n + 1):
	if visited[x]:
		continue
	dfs(x)
	ans += 1
print(ans)


from collections import deque
(n, m) = map(int, input().split())
tree = [[] for i in range(n)]
for i in range(m):
	(x, y, z) = map(int, input().split())
	tree[x - 1].append(y - 1)
	tree[y - 1].append(x - 1)
already = [False] * n
ans = 0
for i in range(n):
	if already[i]:
		continue
	ans += 1
	not_yet = deque(tree[i])
	for value in tree[i]:
		already[value] = True
	while not_yet:
		key = not_yet.popleft()
		for value in tree[key]:
			if already[value]:
				continue
			already[value] = True
			not_yet.append(value)
print(ans)


from collections import deque
(n, m) = map(int, input().split())
remains = set(range(1, n + 1))
edges = [[] for _ in range(n + 1)]
for i in range(m):
	(x, y, z) = map(int, input().split())
	edges[x].append(y)
	edges[y].append(x)
ans = 0
while len(remains) > 0:
	ans += 1
	d = deque()
	d.append(remains.pop())
	while len(d) > 0:
		tmp = d.pop()
		for i in edges[tmp]:
			if i in remains:
				d.append(i)
				remains.remove(i)
print(ans)


import queue
import sys
sys.setrecursionlimit(10 ** 6)
(N, M) = map(int, input().split())
XYZ = []
for _ in range(M):
	XYZ.append(tuple(map(int, input().split())))
G = [[] for _ in range(N + 1)]
for el in XYZ:
	G[el[0]].append(el[1])
	G[el[1]].append(el[0])
seen = [False] * (N + 1)
todo = queue.Queue()

def bfs(n):
	seen[n] = True
	for nxt in G[n]:
		if seen[nxt] == False:
			bfs(nxt)
cnt = 0
for check in range(1, N + 1):
	if seen[check] == False:
		cnt += 1
		bfs(check)
print(cnt)


(n, m) = map(int, input().split())
a = [[] for i in range(n)]
for i in range(m):
	(x, y, z) = map(int, input().split())
	x -= 1
	y -= 1
	a[x].append(y)
	a[y].append(x)
b = [0 for i in range(n)]
ans = 0
for j in range(n):
	if b[j] == 1:
		continue
	else:
		b[j] = 1
		ans += 1
		stack = [j]
	while stack:
		p = stack.pop()
		for i in range(len(a[p])):
			if b[a[p][i]] == 0:
				b[a[p][i]] = 1
				stack.append(a[p][i])
print(ans)


def find(A, x):
	p = A[x]
	if p == x:
		return x
	a = find(A, p)
	A[x] = a
	return a

def union(A, x, y):
	if find(A, x) > find(A, y):
		(bx, by) = (find(A, y), find(A, x))
	else:
		(bx, by) = (find(A, x), find(A, y))
	A[y] = bx
	A[by] = bx
(N, M) = map(int, input().split())
V = [i for i in range(N)]
for _ in range(M):
	(x, y, _) = map(int, input().split())
	union(V, x - 1, y - 1)
print(sum([1 for i in range(N) if i == V[i]]))


from typing import Set

class UnionFind:
	__slots__ = ['_data_size', '_first_idx', '_parents']

	def __init__(self, data_size: int, is_zero_origin: bool=True) -> None:
		self._data_size = data_size
		self._first_idx = 0 if is_zero_origin else 1
		self._parents = [-1] * (data_size + self._first_idx)

	def __getitem__(self, x: int) -> int:
		if self._parents[x] < 0:
			return x
		self._parents[x] = self[self._parents[x]]
		return self._parents[x]

	def __len__(self) -> int:
		return len(self.groups)

	@property
	def groups(self) -> Set[int]:
		return {self[x] for x in range(self._first_idx, self._data_size + self._first_idx)}

	def is_connected(self, x: int, y: int) -> bool:
		return self[x] == self[y]

	def unite(self, x: int, y: int) -> None:
		(x, y) = (self[x], self[y])
		if x == y:
			return
		if self._parents[x] > self._parents[y]:
			(x, y) = (y, x)
		self._parents[x] += self._parents[y]
		self._parents[y] = x

def main():
	(N, _, *X) = list(map(int, open(0).read().split()))
	tree = UnionFind(N, is_zero_origin=False)
	for (x, y, _) in zip(*[iter(X)] * 3):
		tree.unite(x, y)
	print(len(tree))

def __starting_point():
	main()
__starting_point()


import sys
sys.setrecursionlimit(10 ** 6)

def dfs(x, g, vis):
	if vis[x]:
		return
	vis[x] = 1
	for y in g[x]:
		dfs(y, g, vis)

def main():
	(N, M) = map(int, input().split())
	g = [[] for _ in range(N)]
	for i in range(M):
		(X, Y, Z) = map(int, input().split())
		X -= 1
		Y -= 1
		g[X].append(Y)
		g[Y].append(X)
	vis = [0] * N
	ans = 0
	for i in range(N):
		if vis[i] == 0:
			dfs(i, g, vis)
			ans += 1
	print(ans)
main()


(N, M) = map(int, input().strip().split(' '))
pairs = [set() for i in range(N + 1)]
appeared = set()
for i in range(M):
	(x, y, z) = map(int, input().strip().split(' '))
	pairs[x].add(y)
	pairs[y].add(x)
	appeared.add(x)
	appeared.add(y)
count_not_appeared = N - len(appeared)
group_count = 0
while appeared:
	cur = appeared.pop()
	queue = [cur]
	while queue:
		cur = queue.pop()
		for n in pairs[cur]:
			if n in appeared:
				appeared.remove(n)
				queue.append(n)
	group_count += 1
print(count_not_appeared + group_count)


import sys
input = sys.stdin.readline
sys.setrecursionlimit(10 ** 7)
from collections import Counter, deque
from collections import defaultdict
from itertools import combinations, permutations, accumulate, groupby, product
from bisect import bisect_left, bisect_right
from heapq import heapify, heappop, heappush
from math import floor, ceil, pi, factorial
from operator import itemgetter

def I():
	return int(input())

def MI():
	return list(map(int, input().split()))

def LI():
	return list(map(int, input().split()))

def LI2():
	return [int(input()) for i in range(n)]

def MXI():
	return [[LI()] for i in range(n)]

def SI():
	return input().rstrip()

def printns(x):
	print('\n'.join(x))

def printni(x):
	print('\n'.join(list(map(str, x))))
inf = 10 ** 17
mod = 10 ** 9 + 7

class UnionFind:

	def __init__(self, n):
		self.n = n
		self.parents = [-1] * n

	def find(self, x):
		if self.parents[x] < 0:
			return x
		else:
			self.parents[x] = self.find(self.parents[x])
			return self.parents[x]

	def union(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return
		if self.parents[x] > self.parents[y]:
			(x, y) = (y, x)
		self.parents[x] += self.parents[y]
		self.parents[y] = x

	def size(self, x):
		return -self.parents[self.find(x)]

	def same(self, x, y):
		return self.find(x) == self.find(y)

	def members(self, x):
		root = self.find(x)
		return [i for i in range(self.n) if self.find(i) == root]

	def roots(self):
		return [i for (i, x) in enumerate(self.parents) if x < 0]

	def group_count(self):
		return len(self.roots())

	def all_group_members(self):
		return {r: self.members(r) for r in self.roots()}

	def __str__(self):
		return '\n'.join(('{}: {}'.format(r, self.members(r)) for r in self.roots()))
(n, m) = MI()
u = UnionFind(n)
for i in range(m):
	(a, b, c) = MI()
	u.union(a - 1, b - 1)
print(u.group_count())


(n, m) = map(int, input().split())
p = [i for i in range(n)]
r = [0 for i in range(n)]

def find(x):
	if p[x] == x:
		return x
	else:
		p[x] = find(p[x])
		return p[x]

def unite(x, y):
	x = find(x)
	y = find(y)
	if x == y:
		return
	if r[x] < r[y]:
		p[x] = y
	else:
		p[y] = x
		if r[x] == r[y]:
			r[x] += 1

def same(x, y):
	return find(x) == find(y)
for i in range(m):
	(x, y, z) = map(int, input().split())
	unite(x - 1, y - 1)
s = set()
for i in range(n):
	s.add(find(i))
print(len(s))