Buggy python submission (verdict: Runtime Error):
class UnionFind():
    # 負の値は根で集合の個数
    # 正の値は次の要素を返す
    def __init__(self, size):
        self.table = [-1 for _ in range(size)]

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

    # 併合
    def union(self, x, y):
        s1 = self.find(x)  # 代表のIndexを取得する
        s2 = self.find(y)
        if s1 != s2:  # 代表のIndexが違う場合
            if self.table[s1] < self.table[s2]:  # 要素数の多い方へMergeする
                self.table[s2] += self.table[s1]  # 子の和を増やす(-)
                self.table[s1] = s2  # Mergeされる側の代表をする側のインデックスに
            else:
                self.table[s1] += self.table[s2]
                self.table[s2] = s1
        return

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


N, M = [int(n) for n in input().split()]
X = [0]*M
Y = [0]*M
Z = [0]*M
UF = UnionFind(N)
adj = [[0, []] for _ in range(N)]
for i in range(M):
    X[i], Y[i], Z[i] = [int(n) for n in input().split()]
    Z[i] %= 2
    X[i] -= 1
    Y[i] -= 1
    UF.union(X[i], Y[i])
s = set([UF.find(0)])
ans = 1

for i in range(1, N):
    tmp = UF.find(i)
    if not(tmp in s):
        ans += 1
        s.add(tmp)
print(ans)


Fixed submission:
class UnionFind:
    def __init__(self, n):
        self.par = [i for i in range(n+1)]
        self.rank = [0] * (n+1)

    # 検索
    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 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_check(self, x, y):
        return self.find(x) == self.find(y)


N, M = [int(n) for n in input().split()]
X = [0]*M
Y = [0]*M
Z = [0]*M
UF = UnionFind(N)
adj = [[0, []] for _ in range(N)]
for i in range(M):
    X[i], Y[i], Z[i] = [int(n) for n in input().split()]
    Z[i] %= 2
    X[i] -= 1
    Y[i] -= 1
    UF.union(X[i], Y[i])
s = set([UF.find(0)])
ans = 1

for i in range(1, N):
    tmp = UF.find(i)
    if not(tmp in s):
        ans += 1
        s.add(tmp)
print(ans)

Buggy python submission (verdict: Runtime Error):
class UnionFind():
    # 負の値は根で集合の個数
    # 正の値は次の要素を返す
    def __init__(self, size):
        self.table = [-1 for _ in range(size)]

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

    # 併合
    def union(self, x, y):
        s1 = self.find(x)  # 代表のIndexを取得する
        s2 = self.find(y)
        if s1 != s2:  # 代表のIndexが違う場合
            if self.table[s1] < self.table[s2]:  # 要素数の多い方へMergeする
                self.table[s2] += self.table[s1]  # 子の和を増やす(-)
                self.table[s1] = s2  # Mergeされる側の代表をする側のインデックスに
            else:
                self.table[s1] += self.table[s2]
                self.table[s2] = s1
        return

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


N, M = [int(n) for n in input().split()]
X = [0]*M
Y = [0]*M
Z = [0]*M
UF = UnionFind(N)
adj = [[0, []] for _ in range(N)]
for i in range(M):
    X[i], Y[i], Z[i] = [int(n) for n in input().split()]
    Z[i] %= 2
    X[i] -= 1
    Y[i] -= 1
    # adj[X[i]][0] += 1
    # adj[Y[i]][0] += 1
    # adj[X[i]][1].append((Y[i], Z[i]))
    # adj[Y[i]][1].append((X[i], Z[i]))
    UF.union(X[i], Y[i])
s = set([UF.find(0)])
ans = 1

for i in range(1, N):
    tmp = UF.find(i)
    if not(tmp in s):
        ans += 1
        s.add(tmp)
print(ans)


Fixed submission:
class UnionFind:
    def __init__(self, n):
        self.par = [i for i in range(n+1)]
        self.rank = [0] * (n+1)

    # 検索
    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 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_check(self, x, y):
        return self.find(x) == self.find(y)


N, M = [int(n) for n in input().split()]
X = [0]*M
Y = [0]*M
Z = [0]*M
UF = UnionFind(N)
adj = [[0, []] for _ in range(N)]
for i in range(M):
    X[i], Y[i], Z[i] = [int(n) for n in input().split()]
    Z[i] %= 2
    X[i] -= 1
    Y[i] -= 1
    UF.union(X[i], Y[i])
s = set([UF.find(0)])
ans = 1

for i in range(1, N):
    tmp = UF.find(i)
    if not(tmp in s):
        ans += 1
        s.add(tmp)
print(ans)