Buggy python submission (verdict: Time Limit Exceeded):
import sys
import bisect
input = sys.stdin.readline

def same_tree(node_a, node_b):
    if node_a.root() == node_b.root():
        return True

def unite(node_a, node_b):
    root_a = node_a.root()
    root_b = node_b.root()
    if root_a == root_b:
        return
    if root_b.depth > root_a.depth:
        root_a, root_b = root_b, root_a
    root_b.is_root = False
    root_b.parent = root_a
    root_a.depth = max(root_a.depth, root_b.depth+1)

class Node:
    def __init__(self):
        self.is_root = True
        self.parent = None
        self.depth = 1
    
    def root(self):
        node = self
        while not node.is_root:
            node = node.parent
        return node

def main():
    N = int(input())
    
    nodes = [Node() for i in range(N)]

    # 各町の座標をタプル(i, x, y)に入れて配列に格納
    xs = []
    ys = []
    for i in range(N):
        x, y = map(int, input().split())
        bisect.insort_left(xs, (x, i))
        bisect.insort_left(ys, (y, i))

    # 使う可能性のある辺のみを取り出す
    edges = []
    for i in range(1, N):
        bisect.insort_left(edges, (xs[i][0] - xs[i-1][0], xs[i-1][1], xs[i][1]))
        bisect.insort_left(edges, (ys[i][0] - ys[i-1][0], ys[i-1][1], ys[i][1]))

    # クラスカル法
    ans = 0
    for (cost, a, b) in edges:
        if not same_tree(nodes[a], nodes[b]):
            unite(nodes[a], nodes[b])
            ans += cost
    print(ans)

if __name__ == "__main__":
    main()

Fixed submission:
import sys
input = sys.stdin.readline

def same_tree(node_a, node_b):
    if node_a.root() == node_b.root():
        return True

def unite(node_a, node_b):
    root_a = node_a.root()
    root_b = node_b.root()
    if root_a == root_b:
        return
    if root_b.depth > root_a.depth:
        root_a, root_b = root_b, root_a
    root_b.is_root = False
    root_b.parent = root_a
    root_a.depth = max(root_a.depth, root_b.depth+1)

class Node:
    def __init__(self):
        self.is_root = True
        self.parent = None
        self.depth = 1
    
    def root(self):
        node = self
        while not node.is_root:
            node = node.parent
        return node

def main():
    N = int(input())
    
    nodes = [Node() for i in range(N)]

    # 各町の座標をタプル(i, x, y)に入れて配列に格納
    xy = []
    for i in range(N):
        x, y = map(int, input().split())
        xy.append((i, x, y))
    
    # 使う可能性のある辺のみを取り出す
    edges = []
    xy = sorted(xy, key=lambda x: x[1])# x座標昇順
    # print("x:", xy)
    for i in range(1, N):
        edges.append((xy[i][1] - xy[i-1][1], xy[i-1][0], xy[i][0]))
    xy = sorted(xy, key=lambda x: x[2])# y座標昇順
    # print("y:", xy)
    for i in range(1, N):
        edges.append((xy[i][2] - xy[i-1][2], xy[i-1][0], xy[i][0]))
    
    ans = 0
    edges = sorted(edges)
    # print(edges)
    for (cost, a, b) in edges:
        if not same_tree(nodes[a], nodes[b]):
            unite(nodes[a], nodes[b])
            ans += cost
    print(ans)




if __name__ == "__main__":
    main()

Buggy python submission (verdict: Time Limit Exceeded):
import sys
import heapq
input = sys.stdin.readline

class Node:
    def __init__(self, id):
        self.id = id
        self.check = False
        self.link = []
        self.cost = []
    
    def __lt__(self, other):
        return self.id < other.id

def main():
    N = int(input())
    
    nodes = [Node(i) for i in range(N)]

    xy = []
    for i in range(N):
        x, y = map(int, input().split())
        xy.append((i, x, y))
    
    for t in range(2):
        if t == 0:
            xy = sorted(xy, key=lambda x: x[1])# x昇順
        else:
            xy = sorted(xy, key=lambda x: x[2])# y昇順
        p_n, p_x, p_y = xy[0]
        for i in range(1, N):
            n, x, y = xy[i]
            if t == 0:
                cost = abs(x - p_x)# x
            else:
                cost = abs(y - p_y)# y
            nodes[p_n].link.append(nodes[n])
            nodes[p_n].cost.append(cost)
            nodes[n].link.append(nodes[p_n])
            nodes[n].cost.append(cost)
            p_n, p_x, p_y = n, x, y
    q = []
    ans = 0
    heapq.heappush(q, (0, nodes[0]))# edge_cost, node
    while len(q) > 0:
        edge_cost, node = heapq.heappop(q)
        if node.check:
            continue
        node.check = True
        ans += edge_cost
        for i, next_node in enumerate(node.link):
            if not next_node.check:
                heapq.heappush(q, (node.cost[i], next_node))
    print(ans)

if __name__ == "__main__":
    main()

Fixed submission:
import sys
input = sys.stdin.readline

def same_tree(node_a, node_b):
    if node_a.root() == node_b.root():
        return True

def unite(node_a, node_b):
    root_a = node_a.root()
    root_b = node_b.root()
    if root_a == root_b:
        return
    if root_b.depth > root_a.depth:
        root_a, root_b = root_b, root_a
    root_b.is_root = False
    root_b.parent = root_a
    root_a.depth = max(root_a.depth, root_b.depth+1)

class Node:
    def __init__(self):
        self.is_root = True
        self.parent = None
        self.depth = 1
    
    def root(self):
        node = self
        while not node.is_root:
            node = node.parent
        return node

def main():
    N = int(input())
    
    nodes = [Node() for i in range(N)]

    # 各町の座標をタプル(i, x, y)に入れて配列に格納
    xy = []
    for i in range(N):
        x, y = map(int, input().split())
        xy.append((i, x, y))
    
    # 使う可能性のある辺のみを取り出す
    edges = []
    xy = sorted(xy, key=lambda x: x[1])# x座標昇順
    # print("x:", xy)
    for i in range(1, N):
        edges.append((xy[i][1] - xy[i-1][1], xy[i-1][0], xy[i][0]))
    xy = sorted(xy, key=lambda x: x[2])# y座標昇順
    # print("y:", xy)
    for i in range(1, N):
        edges.append((xy[i][2] - xy[i-1][2], xy[i-1][0], xy[i][0]))
    
    ans = 0
    edges = sorted(edges)
    # print(edges)
    for (cost, a, b) in edges:
        if not same_tree(nodes[a], nodes[b]):
            unite(nodes[a], nodes[b])
            ans += cost
    print(ans)




if __name__ == "__main__":
    main()