Buggy python submission (verdict: Time Limit Exceeded):
#!/usr/bin/env python3
import sys
sys.setrecursionlimit(10**8)


class Node:
    def __init__(self, index):
        self.index = index
        self.ref = []
        self.visited = False

    def append(self, node):
        self.ref.append(node)
        node.ref.append(self)

    def visit(self):
        self.visited = True
        for r in self.ref:
            if not r.visited:
                r.visit()


def solve(N: int, M: int, X: "List[int]", Y: "List[int]", Z: "List[int]"):
    nodes = [Node(i) for i in range(N)]
    X = [x-1 for x in X]
    Y = [y-1 for y in Y]
    for i in range(M):
        nodes[X[i]].append(nodes[Y[i]])
    sum = 0
    for i in range(N):
        if not nodes[i].visited:
            sum += 1
            nodes[i].visit()
    print(sum)
    return


# Generated by 1.1.6 https://github.com/kyuridenamida/atcoder-tools  (tips: You use the default template now. You can remove this line by using your custom template)
def main():
    def iterate_tokens():
        for line in sys.stdin:
            for word in line.split():
                yield word
    tokens = iterate_tokens()
    N = int(next(tokens))  # type: int
    M = int(next(tokens))  # type: int
    X = [int()] * (M)  # type: "List[int]"
    Y = [int()] * (M)  # type: "List[int]"
    Z = [int()] * (M)  # type: "List[int]"
    for i in range(M):
        X[i] = int(next(tokens))
        Y[i] = int(next(tokens))
        Z[i] = int(next(tokens))
    solve(N, M, X, Y, Z)


if __name__ == '__main__':
    main()


Fixed submission:
#!/usr/bin/env python3
import sys
sys.setrecursionlimit(10**8)


class Node:
    def __init__(self, index):
        self.index = index
        self.ref = []
        self.visited = False

    def append(self, node):
        self.ref.append(node)
        node.ref.append(self)

    def visit(self):
        self.visited = True
        for r in self.ref:
            if not r.visited:
                r.visit()


def solve(N: int, M: int, X: "List[int]", Y: "List[int]", Z: "List[int]"):
    nodes = [Node(i) for i in range(N)]
    X = [x-1 for x in X]
    Y = [y-1 for y in Y]
    for i in range(M):
        nodes[X[i]].append(nodes[Y[i]])
    sum = 0
    for i in range(N):
        if not nodes[i].visited:
            sum += 1
            nodes[i].visit()
    print(sum)
    return


# Generated by 1.1.6 https://github.com/kyuridenamida/atcoder-tools  (tips: You use the default template now. You can remove this line by using your custom template)
def main():
    def iterate_tokens():
        for line in sys.stdin:
            for word in line.split():
                yield word
    tokens = iterate_tokens()
    N = int(next(tokens))  # type: int
    M = int(next(tokens))  # type: int
    X = [int()] * (M)  # type: "List[int]"
    Y = [int()] * (M)  # type: "List[int]"
    Z = [int()] * (M)  # type: "List[int]"
    for i in range(M):
        X[i] = int(next(tokens))
        Y[i] = int(next(tokens))
        Z[i] = int(next(tokens))
    solve(N, M, X, Y, Z)


if __name__ == '__main__':
    main()

Buggy python submission (verdict: Runtime Error):
#!/usr/bin/env python3
import sys


class Node:
    def __init__(self, index):
        self.index = index
        self.ref = []
        self.visited = False

    def append(self, node):
        self.ref.append(node)
        node.ref.append(self)

    def visit(self):
        self.visited = True
        for r in self.ref:
            if not r.visited:
                r.visit()


def solve(N: int, M: int, X: "List[int]", Y: "List[int]", Z: "List[int]"):
    nodes = [Node(i) for i in range(N)]
    X = [x-1 for x in X]
    Y = [y-1 for y in Y]
    for i in range(M):
        nodes[X[i]].append(nodes[Y[i]])
    sum = 0
    for i in range(N):
        if not nodes[i].visited:
            sum += 1
            nodes[i].visit()
    print(sum)
    return


# Generated by 1.1.6 https://github.com/kyuridenamida/atcoder-tools  (tips: You use the default template now. You can remove this line by using your custom template)
def main():
    def iterate_tokens():
        for line in sys.stdin:
            for word in line.split():
                yield word
    tokens = iterate_tokens()
    N = int(next(tokens))  # type: int
    M = int(next(tokens))  # type: int
    X = [int()] * (M)  # type: "List[int]"
    Y = [int()] * (M)  # type: "List[int]"
    Z = [int()] * (M)  # type: "List[int]"
    for i in range(M):
        X[i] = int(next(tokens))
        Y[i] = int(next(tokens))
        Z[i] = int(next(tokens))
    solve(N, M, X, Y, Z)


if __name__ == '__main__':
    main()


Fixed submission:
#!/usr/bin/env python3
import sys
sys.setrecursionlimit(10**8)


class Node:
    def __init__(self, index):
        self.index = index
        self.ref = []
        self.visited = False

    def append(self, node):
        self.ref.append(node)
        node.ref.append(self)

    def visit(self):
        self.visited = True
        for r in self.ref:
            if not r.visited:
                r.visit()


def solve(N: int, M: int, X: "List[int]", Y: "List[int]", Z: "List[int]"):
    nodes = [Node(i) for i in range(N)]
    X = [x-1 for x in X]
    Y = [y-1 for y in Y]
    for i in range(M):
        nodes[X[i]].append(nodes[Y[i]])
    sum = 0
    for i in range(N):
        if not nodes[i].visited:
            sum += 1
            nodes[i].visit()
    print(sum)
    return


# Generated by 1.1.6 https://github.com/kyuridenamida/atcoder-tools  (tips: You use the default template now. You can remove this line by using your custom template)
def main():
    def iterate_tokens():
        for line in sys.stdin:
            for word in line.split():
                yield word
    tokens = iterate_tokens()
    N = int(next(tokens))  # type: int
    M = int(next(tokens))  # type: int
    X = [int()] * (M)  # type: "List[int]"
    Y = [int()] * (M)  # type: "List[int]"
    Z = [int()] * (M)  # type: "List[int]"
    for i in range(M):
        X[i] = int(next(tokens))
        Y[i] = int(next(tokens))
        Z[i] = int(next(tokens))
    solve(N, M, X, Y, Z)


if __name__ == '__main__':
    main()