CodeEff/ECCO huggingface dataset:
# Original solution
n,m=list(map(int,input().split()))
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)]

uf=UnionFind(n)
for _ in range(m):
    x,y,z=list(map(int,input().split()))
    uf.Unite(x,y)
ans=set()
for i in range(1,n+1):
    ans.add(uf.Find_Root(i))
print((len(ans)))


# Optimized solution
n,m=list(map(int,input().split()))
import sys
input=sys.stdin.readline

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

uf=UnionFind(n)
for _ in range(m):
    x,y,z=list(map(int,input().split()))
    x-=1
    y-=1
    uf.Unite(x,y)
r=[0]*n
for i in range(n):
    r[i]=uf.Find_Root(i)
s=set(r)
print((len(s)))
# Original solution
# https://atcoder.jp/contests/abc126/tasks/abc126_e
import itertools
from collections import Counter
from collections import defaultdict
import bisect


# Union find
class UnionFind():
    def __init__(self,size):
        self.table = [-1 for _ in range(size)]  # 負の値の場合根を表す。正の値は次の要素を返す、根まで続く

    #集合の代表を求める
    def find(self,x):
        while self.table[x] >= 0:
            #根に来た時,self.table[根のindex]は負の値なのでx = 根のindexで値が返される。
            x = self.table[x]
        return x

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

    #併合
    def union(self,x,y):
        s1 = self.find(x)#根のindex,table[s1]がグラフの高さ
        s2 = self.find(y)
        if s1 != s2:#根が異なる場合
            if self.table[s1] != self.table[s2]:#グラフの高さが異なる場合
                if self.table[s1] < self.table[s2]:
                    self.table[s2] = s1
                else:
                    self.table[s1] = s2
            else:
                #グラフの長さが同じ場合,どちらを根にしても変わらない
                #その際,グラフが1長くなることを考慮する
                #self.table[s1] += -1
                self.table[s2] = s1
        return

    def num_group(self):
        # print(self.table)
        return self.table.count(-1)


def main():
    N, M = list(map(int, input().split()))
    uf = UnionFind(N)

    for _ in range(M):
        x, y, z = list(map(int, input().split()))
        uf.union(x - 1, y - 1)
    print((uf.num_group()))

if __name__ == '__main__':
    main()


# Optimized solution
# https://atcoder.jp/contests/abc126/tasks/abc126_e
import itertools
from collections import Counter
from collections import defaultdict
import bisect


# Union find
class UnionFind():
    def __init__(self,size):
        self.table = [-1 for _ in range(size)]  # 負の値の場合根を表す。正の値は次の要素を返す、根まで続く

    #集合の代表を求める
    def find(self,x):
        while self.table[x] >= 0:
            #根に来た時,self.table[根のindex]は負の値なのでx = 根のindexで値が返される。
            x = self.table[x]
        return x

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

    def rewrite(self,x, p):
        while self.table[x] >= 0:
            #根に来た時,self.table[根のindex]は負の値なのでx = 根のindexで値が返される。
            tmp = x
            x = self.table[x]
            self.table[tmp] = p
        return

    #併合
    def union(self,x,y):
        s1 = self.find(x)#根のindex,table[s1]がグラフの高さ
        s2 = self.find(y)
        if s1 != s2:#根が異なる場合
            if self.table[s1] != self.table[s2]:#グラフの高さが異なる場合
                if self.table[s1] < self.table[s2]:
                    self.table[s2] = s1
                    self.rewrite(y, s1)
                else:
                    self.table[s1] = s2
                    self.rewrite(x, s2)
            else:
                #グラフの長さが同じ場合,どちらを根にしても変わらない
                self.table[s2] = s1
                self.rewrite(y, s1)
        return

    def num_group(self):
        # print(self.table)
        return self.table.count(-1)


def main():
    N, M = list(map(int, input().split()))
    uf = UnionFind(N)

    for _ in range(M):
        x, y, z = list(map(int, input().split()))
        uf.union(x - 1, y - 1)
    print((uf.num_group()))

if __name__ == '__main__':
    main()
# Original solution
import sys
input = sys.stdin.readline


class UnionFind:
    def __init__(self, size):
        self.parent = [-1] * size
        self.rank = [1] * size
        self.groups = size

    def get_root(self, node):
        parent = self.parent[node]
        if parent == -1:
            root = node
        else:
            root = self.get_root(parent)
            self.parent[node] = root  # 同じnodeへの2回目以降のget_rootを高速にするために、直接rootに繋いでおく
        return root

    def in_same_group(self, node1, node2):
        root1 = self.get_root(node1)
        root2 = self.get_root(node2)
        return root1 == root2

    def unite(self, node1, node2):
        if self.in_same_group(node1, node2):
            return
        main_root = self.get_root(node1)
        sub_root = self.get_root(node2)
        if self.rank[main_root] < self.rank[sub_root]:  # rankの大きい方をmain_rootにする
            main_root, sub_root = sub_root, main_root

        self.parent[sub_root] = main_root
        self.rank[main_root] += self.rank[sub_root]
        self.groups -= 1


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

for i in range(m):
    x, y, z = list(map(int, input().split()))
    x -= 1
    y -= 1
    uf.unite(x, y)

print((uf.groups))


# Optimized solution
import sys
input = sys.stdin.readline


class UnionFind:
    def __init__(self, size):
        self.parent = [-1] * size
        self.rank = [1] * size
        self.groups = size

    def get_root(self, node):
        parent = self.parent[node]
        if parent == -1:
            root = node
        else:
            root = self.get_root(parent)
            self.parent[node] = root  # 同じnodeへの2回目以降のget_rootを高速にするために、直接rootに繋いでおく
        return root

    def unite(self, node1, node2):
        main_root = self.get_root(node1)
        sub_root = self.get_root(node2)
        if main_root == sub_root:
            return
        if self.rank[main_root] < self.rank[sub_root]:  # rankの大きい方をmain_rootにする
            main_root, sub_root = sub_root, main_root

        self.parent[sub_root] = main_root
        self.rank[main_root] += self.rank[sub_root]
        self.groups -= 1


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

for i in range(m):
    x, y, z = list(map(int, input().split()))
    x -= 1
    y -= 1
    uf.unite(x, y)

print((uf.groups))
# Original solution
import sys
input = sys.stdin.readline


class UnionFind:
    def __init__(self, size):
        self.parent = [-1] * size
        self.rank = [1] * size
        self.groups = size

    def get_root(self, node):
        parent = self.parent[node]
        if parent == -1:
            root = node
        else:
            root = self.get_root(parent)
            self.parent[node] = root  # 同じnodeへの2回目以降のget_rootを高速にするために、直接rootに繋いでおく
        return root

    def unite(self, node1, node2):
        main_root = self.get_root(node1)
        sub_root = self.get_root(node2)
        if main_root == sub_root:
            return
        if self.rank[main_root] < self.rank[sub_root]:  # rankの大きい方をmain_rootにする
            main_root, sub_root = sub_root, main_root

        self.parent[sub_root] = main_root
        self.rank[main_root] += self.rank[sub_root]
        self.groups -= 1


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

for i in range(m):
    x, y, z = list(map(int, input().split()))
    x -= 1
    y -= 1
    uf.unite(x, y)

print((uf.groups))


# Optimized solution
class UnionFind:
    def __init__(self, size):
        self.parent = [-1] * size
        self.rank = [1] * size
        self.groups = size

    def get_root(self, node):
        parent = self.parent[node]
        if parent == -1:
            root = node
        else:
            root = self.get_root(parent)
            self.parent[node] = root
        return root

    def unite(self, node1, node2):
        main_root = self.get_root(node1)
        sub_root = self.get_root(node2)
        if main_root == sub_root:
            return
        if self.rank[main_root] < self.rank[sub_root]:
            main_root, sub_root = sub_root, main_root

        self.parent[sub_root] = main_root
        self.rank[main_root] += self.rank[sub_root]
        self.groups -= 1


n, m, *t = list(map(int,open(0).read().split()))
uf = UnionFind(n)
X = t[::3]
Y = t[1::3]
for x, y in zip(X, Y):
    uf.unite(x-1, y-1)

print((uf.groups))
# Original solution
class UnionFind :
    def __init__(self, size) :
        self.parent = list(range(size))
        self.height = [0] * size
        self.size = [1] * size
        self.component = size

    def root(self, index) :
        if self.parent[index] == index :  # 根の場合
            return index
        rootIndex = self.root(self.parent[index])  # 葉の場合親の根を取得
        self.parent[index] = rootIndex  # 親の付け直し
        return rootIndex

    def union(self, index1, index2) :  # 結合
        root1 = self.root(index1)
        root2 = self.root(index2)

        if root1 == root2 :  # 連結されている場合
            return

        self.component -= 1  # 連結成分を減らす

        if self.height[root1] < self.height[root2] :
            self.parent[root1] = root2  # root2に結合
            self.size[root2] += self.size[root1]
        else :
            self.parent[root2] = root1  # root1に結合
            self.size[root1] += self.size[root2]
            if self.height[root1] == self.height[root2] :
                self.height[root1] += 1
        return

    def isSameRoot(self, index1, index2) :
        return self.root(index1) == self.root(index2)

    def sizeOfSameRoot(self, index) :
        return self.size[self.root(index)]

    def getComponent(self) :
        return self.component

N, M = list(map(int, input().split()))
tree = UnionFind(N)

for _ in range(M):
    fr, to, _ = list(map(int, input().split()))
    tree.union(fr - 1, to - 1)

print((tree.getComponent()))


# Optimized solution
class UnionFind:
    def __init__(self, size):
        self.parent = list(range(size))
        self.height = [0] * size
        self.size = [1] * size
        self.componentCount = size

    def root(self, index):
        if self.parent[index] == index:  # 根の場合
            return index
        rootIndex = self.root(self.parent[index])  # 葉の場合親の根を取得
        self.parent[index] = rootIndex  # 親の付け直し
        return rootIndex

    def union(self, index1, index2):  # 結合
        root1 = self.root(index1)
        root2 = self.root(index2)

        if root1 == root2:  # 連結されている場合
            return

        self.componentCount -= 1  # 連結成分を減らす

        if self.height[root1] < self.height[root2]:
            self.parent[root1] = root2  # root2に結合
            self.size[root2] += self.size[root1]
        else:
            self.parent[root2] = root1  # root1に結合
            self.size[root1] += self.size[root2]
            if self.height[root1] == self.height[root2]:
                self.height[root1] += 1
        return

    def isSameRoot(self, index1, index2):
        return self.root(index1) == self.root(index2)

    def sizeOfSameRoot(self, index):
        return self.size[self.root(index)]

N, M = list(map(int, input().split()))
tree = UnionFind(N)

for _ in range(M):
    a, b, c = list(map(int, input().split()))
    tree.union(a - 1, b - 1)

print((tree.componentCount))
# Original solution
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)


# Optimized solution
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
        else:
            if 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)
# Original solution
n, m = list(map(int, input().split()))
tree = [-i for i in range(n+1)]
rank = [1 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 = list(map(int, input().split()))
    x, y = [search_root(x), search_root(y)]
    if x==y:
        continue
    else:
        if rank[x]<rank[y]:
            rank[y] += 1
            tree[x] = y
        else:
            rank[x] += 1
            tree[y] = x
print((sum(1 for i in tree if i<0)))

# Optimized solution
n, m = list(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 = list(map(int, input().split()))
    x, y = [search_root(x), search_root(y)]
    if x==y:
        continue
    else:
        tree[x] = y
print((sum(1 for i in tree if i<0)))
# Original solution
n, m = list(map(int, input().split()))
tree = [-i for i in range(n+1)]

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

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

for _i in range(m):
    x, y, z = list(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)))
# Original solution
class UnionFind:
    def __init__(self, n):
        self.par = [i for i in range(n)]
        self.rank = [0]*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 unite(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
        else:
            self.par[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 = list(map(int, input().split()))
uf = UnionFind(n)
for i in range(m):
    x, y, z = list(map(int, input().split()))
    uf.unite(x-1, y-1)
print((len(set(uf.find(i) for i in range(n)))))

# Optimized solution
class UnionFind:
    def __init__(self, n):
        self.par = [i for i in range(n)]
        self.rank = [0]*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 unite(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
        else:
            self.par[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 = list(map(int, input().split()))
uf = UnionFind(n)
for i in range(m):
    x, y, z = list(map(int, input().split()))
    uf.unite(x-1, y-1)
print((sum(uf.par[i] == i for i in range(n))))
# Original solution
class Node:
    def __init__(self, val):
        self.num = val
        self.val = val
        self.is_parent = True
        self.parent = None
        self.childs = []

    def show(self):
        print(self.num, end=" ")
        print(self.is_parent, end=" ")
        for child in self.childs:
            print(child.num, end=" ")

def root(node):
    while node.parent != None:
        node = node.parent
    return node

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

roots = [Node(i) for i in range(N)]
count = N

for i in range(M):
    x, y, z = map(int, input().split())
    x = roots[x-1]
    y = roots[y-1]
    if x.is_parent and y.is_parent:
            y.is_parent = False
            y.parent = x
            count -= 1
            x.childs.append(y)
    else:
        root_x = root(x)
        root_y = root(y)
        if root_x != root_y:
            root_y.is_parent = False
            root_y.parent = root_x
            count -= 1
            root_x.childs.append(root_y)

print(count)


# Optimized solution
class Node:
    def __init__(self, val):
        self.num = val
        self.val = val
        self.is_parent = True
        self.parent = None
        self.childs = []

    def show(self):
        print(self.num, end=" ")
        print(self.is_parent, end=" ")
        for child in self.childs:
            print(child.num, end=" ")

def root(node):
    depth = 0
    while node.parent != None:
        node = node.parent
        depth += 1
    return node, depth

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

roots = [Node(i) for i in range(N)]
count = N

for i in range(M):
    x, y, z = map(int, input().split())
    x = roots[x-1]
    y = roots[y-1]
    if x.is_parent and y.is_parent:
            y.is_parent = False
            y.parent = x
            count -= 1
            x.childs.append(y)
    else:
        root_x, depth_x = root(x)
        root_y, depth_y = root(y)
        if root_x != root_y:
            if depth_x >= depth_y:
                root_y.is_parent = False
                root_y.parent = root_x
                count -= 1
                root_x.childs.append(root_y)
            else:
                root_x.is_parent = False
                root_x.parent = root_y
                count -= 1
                root_y.childs.append(root_x)

print(count)
# Original solution
class Node:
    def __init__(self, val):
        self.num = val
        self.val = val
        self.is_parent = True
        self.parent = None
        self.childs = []

    def show(self):
        print(self.num, end=" ")
        print(self.is_parent, end=" ")
        for child in self.childs:
            print(child.num, end=" ")

def root(node):
    depth = 0
    while node.parent != None:
        node = node.parent
        depth += 1
    return node, depth

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

roots = [Node(i) for i in range(N)]
count = N

for i in range(M):
    x, y, z = map(int, input().split())
    x = roots[x-1]
    y = roots[y-1]
    if x.is_parent and y.is_parent:
            y.is_parent = False
            y.parent = x
            count -= 1
            x.childs.append(y)
    else:
        root_x, depth_x = root(x)
        root_y, depth_y = root(y)
        if root_x != root_y:
            if depth_x >= depth_y:
                root_y.is_parent = False
                root_y.parent = root_x
                count -= 1
                root_x.childs.append(root_y)
            else:
                root_x.is_parent = False
                root_x.parent = root_y
                count -= 1
                root_y.childs.append(root_x)

print(count)


# Optimized solution
class Node:
    def __init__(self, val):
        self.num = val
        self.val = val
        self.is_parent = True
        self.parent = None

def root(node):
    depth = 0
    while node.parent != None:
        node = node.parent
        depth += 1
    return node, depth

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

roots = [Node(i) for i in range(N)]
count = N

for i in range(M):
    x, y, z = list(map(int, input().split()))
    x = roots[x-1]
    y = roots[y-1]
    if x.is_parent and y.is_parent:
            y.is_parent = False
            y.parent = x
            count -= 1
    else:
        root_x, depth_x = root(x)
        root_y, depth_y = root(y)
        if root_x != root_y:
            if depth_x >= depth_y:
                root_y.is_parent = False
                root_y.parent = root_x
                count -= 1
            else:
                root_x.is_parent = False
                root_x.parent = root_y
                count -= 1

print(count)
# Original solution
class Node:
    def __init__(self, val):
        self.num = val
        self.val = val
        self.is_parent = True
        self.parent = None

def root(node):
    depth = 0
    while node.parent != None:
        node = node.parent
        depth += 1
    return node, depth

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

roots = [Node(i) for i in range(N)]
count = N

for i in range(M):
    x, y, z = list(map(int, input().split()))
    x = roots[x-1]
    y = roots[y-1]
    if x.is_parent and y.is_parent:
            y.is_parent = False
            y.parent = x
            count -= 1
    else:
        root_x, depth_x = root(x)
        root_y, depth_y = root(y)
        if root_x != root_y:
            if depth_x >= depth_y:
                root_y.is_parent = False
                root_y.parent = root_x
                count -= 1
            else:
                root_x.is_parent = False
                root_x.parent = root_y
                count -= 1

print(count)


# Optimized solution
class Node:
    def __init__(self):
        self.is_parent = True
        self.parent = None

def root(node):
    depth = 0
    while node.parent != None:
        node = node.parent
        depth += 1
    return node, depth

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

roots = [Node() for i in range(N)]
count = N

for i in range(M):
    x, y, z = list(map(int, input().split()))
    x = roots[x-1]
    y = roots[y-1]
    if x.is_parent and y.is_parent:
            y.is_parent = False
            y.parent = x
            count -= 1
    else:
        root_x, depth_x = root(x)
        root_y, depth_y = root(y)
        if root_x != root_y:
            if depth_x >= depth_y:
                root_y.is_parent = False
                root_y.parent = root_x
                count -= 1
            else:
                root_x.is_parent = False
                root_x.parent = root_y
                count -= 1

print(count)