Problem:


Score : 500 points

Problem Statement

There are N towns on a plane. The i-th town is located at the coordinates (x_i,y_i). There may be more than one town at the same coordinates.

You can build a road between two towns at coordinates (a,b) and (c,d) for a cost of min(|a-c|,|b-d|) yen (the currency of Japan). It is not possible to build other types of roads.

Your objective is to build roads so that it will be possible to travel between every pair of towns by traversing roads. At least how much money is necessary to achieve this?

Constraints

2 ≤ N ≤ 10^5

0 ≤ x_i,y_i ≤ 10^9

All input values are integers.

Input

Input is given from Standard Input in the following format:

N
x_1 y_1
x_2 y_2
:
x_N y_N

Output

Print the minimum necessary amount of money in order to build roads so that it will be possible to travel between every pair of towns by traversing roads.

Sample Input 1

3
1 5
3 9
7 8

Sample Output 1

3

Build a road between Towns 1 and 2, and another between Towns 2 and 3. The total cost is 2+1=3 yen.

Sample Input 2

6
8 3
4 9
12 19
18 1
13 5
7 6

Sample Output 2

8



Sample input:
3
1 5
3 9
7 8


Sample output:
3

Submission status: Time Limit Exceeded

Solution code:

class UnionFind:
    def __init__(self, n):
        # total number of nodes.
        self.n = n
        # node id -> root node id
        self._root_table = list(range(n))
        # root node id -> group size
        self._size_table = [1] * n

    def find(self, x):
        """Returns x's root node id."""
        r = self._root_table[x]
        if r != x:
            # Update the cache on query.
            r = self._root_table[x] = self.find(r)
        return r

    def union(self, x, y):
        """Merges two groups."""
        x = self.find(x)
        y = self.find(y)

        if x == y:
            return

        # Ensure that x is the larger (or equal) group.
        if self._size_table[x] < self._size_table[y]:
            x, y = y, x

        self._size_table[x] += self._size_table[y]
        self._root_table[y] = x

    def size(self, x):
        return self._size_table[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._root_table) if x == i]

    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 = int(input())
cities, xs, ys = [], [], []
for i in range(N):
    x, y = map(int, input().split())
    cities.append((x, y))
    xs.append((x, i))
    ys.append((y, i))
xs.sort()
ys.sort()
xd, yd = [], []
for i in range(1, N):
    x1, c1 = xs[i - 1]
    x2, c2 = xs[i]
    if x2-x1 <= abs(cities[c1][1] - cities[c2][1]):
        xd.append((x2 - x1, c1, c2))
    y1, c1 = ys[i - 1]
    y2, c2 = ys[i]
    if y2-y1 <= abs(cities[c1][0] - cities[c2][0]):
        xd.append((y2 - y1, c1, c2))
xd.sort()

uf = UnionFind(N)
xi = yi = 0
cost = 0
INF = 10**10
merged_cnt = 0
while xi < len(xd):
    d1, c1, c2 = xd[xi]
    if not uf.same(c1, c2):
        uf.union(c1, c2)
        cost += d1
        merged_cnt += 1
        if merged_cnt == N-1:
            break
    xi += 1
print(cost)

Submission status: Time Limit Exceeded

Solution code:

class UnionFind:
    def __init__(self, n):
        # total number of nodes.
        self.n = n
        # node id -> root node id
        self._root_table = list(range(n))
        # root node id -> group size
        self._size_table = [1] * n

    def find(self, x):
        """Returns x's root node id."""
        r = self._root_table[x]
        if r != x:
            # Update the cache on query.
            r = self._root_table[x] = self.find(r)
        return r

    def union(self, x, y):
        """Merges two groups."""
        x = self.find(x)
        y = self.find(y)

        if x == y:
            return

        # Ensure that x is the larger (or equal) group.
        if self._size_table[x] < self._size_table[y]:
            x, y = y, x

        self._size_table[x] += self._size_table[y]
        self._root_table[y] = x

    def size(self, x):
        return self._size_table[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._root_table) if x == i]

    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 = int(input())
cities, xs, ys = [], [], []
for i in range(N):
    x, y = map(int, input().split())
    cities.append((x, y))
    xs.append((x, i))
    ys.append((y, i))
xs.sort()
ys.sort()
xd, yd = [], []
for i in range(1, N):
    x1, c1 = xs[i - 1]
    x2, c2 = xs[i]
    if x2-x1 <= abs(cities[c1][1] - cities[c2][1]):
        xd.append((x2 - x1, c1, c2))
    y1, c1 = ys[i - 1]
    y2, c2 = ys[i]
    if y2-y1 <= abs(cities[c1][0] - cities[c2][0]):
        yd.append((y2 - y1, c1, c2))
xd.sort()
yd.sort()

uf = UnionFind(N)
xi = yi = 0
cost = 0
INF = 10**10
while xi < len(xd) and yi < len(yd):
    if xi < len(xd):
        d1, c1, c2 = xd[xi]
    else:
        d1 = INF
    if yi < len(yd):
        d2, c3, c4 = yd[yi]
    else:
        d2 = INF
    if d1 <= d2:
        if not uf.same(c1, c2):
            uf.union(c1, c2)
            cost += d1
            if uf.size(c1) == N:
                break
        xi += 1
    else:
        if not uf.same(c3, c4):
            uf.union(c3, c4)
            cost += d2
            if uf.size(c3) == N:
                break
        yi += 1
print(cost)

Submission status: Time Limit Exceeded

Solution code:

class UnionFind:
    def __init__(self, n):
        # total number of nodes.
        self.n = n
        # node id -> root node id
        self._root_table = list(range(n))
        # root node id -> group size
        self._size_table = [1] * n

    def find(self, x):
        """Returns x's root node id."""
        r = self._root_table[x]
        if r != x:
            # Update the cache on query.
            r = self._root_table[x] = self.find(r)
        return r

    def union(self, x, y):
        """Merges two groups."""
        x = self.find(x)
        y = self.find(y)

        if x == y:
            return

        # Ensure that x is the larger (or equal) group.
        if self._size_table[x] < self._size_table[y]:
            x, y = y, x

        self._size_table[x] += self._size_table[y]
        self._root_table[y] = x

    def size(self, x):
        return self._size_table[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._root_table) if x == i]

    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 = int(input())
cities, xs, ys = [], [], []
for i in range(N):
    x, y = map(int, input().split())
    cities.append((x, y))
    xs.append((x, i))
    ys.append((y, i))
xs.sort()
ys.sort()
xd, yd = [], []
for i in range(1, N):
    x1, c1 = xs[i - 1]
    x2, c2 = xs[i]
    xd.append((x2 - x1, c1, c2))
    y1, c1 = ys[i - 1]
    y2, c2 = ys[i]
    yd.append((y2 - y1, c1, c2))
xd.sort()
yd.sort()
uf = UnionFind(N)
xi = yi = 0
cost = 0
INF = 10**10
while xi < N-1 and yi < N-1:
    if xi < N-1:
        d1, c1, c2 = xd[xi]
    else:
        d1 = INF
    if yi < N-1:
        d2, c3, c4 = yd[yi]
    else:
        d2 = INF
    if d1 <= d2:
        if not uf.same(c1, c2):
            uf.union(c1, c2)
            cost += d1
            if uf.size(c1) == N:
                break
        xi += 1
    else:
        if not uf.same(c3, c4):
            uf.union(c3, c4)
            cost += d2
            if uf.size(c3) == N:
                break
        yi += 1
print(cost)

Submission status: Time Limit Exceeded

Solution code:

class UnionFind:
    def __init__(self, n):
        # total number of nodes.
        self.n = n
        # node id -> root node id
        self._root_table = list(range(n))
        # root node id -> group size
        self._size_table = [1] * n

    def find(self, x):
        """Returns x's root node id."""
        r = self._root_table[x]
        if r != x:
            # Update the cache on query.
            r = self._root_table[x] = self.find(r)
        return r

    def union(self, x, y):
        """Merges two groups."""
        x = self.find(x)
        y = self.find(y)

        if x == y:
            return

        # Ensure that x is the larger (or equal) group.
        if self._size_table[x] < self._size_table[y]:
            x, y = y, x

        self._size_table[x] += self._size_table[y]
        self._root_table[y] = x

    def size(self, x):
        return self._size_table[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._root_table) if x == i]

    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 = int(input())
cities, xs, ys = [], [], []
for i in range(N):
    x, y = map(int, input().split())
    cities.append((x, y))
    xs.append((x, i))
    ys.append((y, i))
xs.sort()
ys.sort()
xd, yd = [], []
for i in range(1, N):
    x1, c1 = xs[i - 1]
    x2, c2 = xs[i]
    xd.append((x2 - x1, c1, c2))
    y1, c1 = ys[i - 1]
    y2, c2 = ys[i]
    yd.append((y2 - y1, c1, c2))
xd.sort()
yd.sort()
uf = UnionFind(N)
xi = yi = 0
cost = 0
INF = 10**10
while xi < len(xd) and yi < len(yd):
    if xi < len(xd):
        d1, c1, c2 = xd[xi]
    else:
        d1 = INF
    if yi < len(yd):
        d2, c3, c4 = yd[yi]
    else:
        d2 = INF
    if d1 <= d2:
        if not uf.same(c1, c2):
            uf.union(c1, c2)
            cost += d1
        xi += 1
    else:
        if not uf.same(c3, c4):
            uf.union(c3, c4)
            cost += d2
        yi += 1
    if len(uf.roots()) == 1:
        break
print(cost)

Submission status: Time Limit Exceeded

Solution code:
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)

N = int(input())
X = []
Y = []
for i in range(N):
    x, y = map(int,input().split())
    X.append((x, i))
    Y.append((y, i))
X.sort()
Y.sort()
Distance = []
for i in range(N-1):
    Distance.append((X[i+1][0] - X[i][0], X[i][1], X[i+1][1]))
    Distance.append((Y[i+1][0] - Y[i][0], Y[i][1], Y[i+1][1]))
Distance.sort()
UFT = UnionFind(N)
ans = 0
for i in range(2*(N-1)):
    d, p, q = Distance[i]
    if not UFT.same(p, q):
        UFT.union(p, q)
        ans += d
    if UFT.size(0) == N:
        break
print(ans)

Submission status: Time Limit Exceeded

Solution code:
import sys
input = sys.stdin.readline
import heapq
def prim_heap():
    used = [True] * n #True:不使用
    edgelist = []
    for e in edge[0]:
        heapq.heappush(edgelist,e)
    used[0] = False
    res = 0
    while len(edgelist) != 0:
        minedge = heapq.heappop(edgelist)
        if not used[minedge[1]]:
            continue
        v = minedge[1]
        used[v] = False
        for e in edge[v]:
            if used[e[1]]:
                heapq.heappush(edgelist,e)
        res += minedge[0]
    return res

n = int(input())
st = []

from collections import deque
edge = deque([[] for i in range(n)])
for i in range(n):
    x,y = map(int,input().split())
    st_append = st.append
    st_append((i,x,y))
    
from operator import itemgetter
bb = tuple(sorted(st,key=itemgetter(1)))
chk = tuple(sorted(st,key=itemgetter(2)))
#print(bb,chk)

for i in range(n-1):
  x = bb[i][0]
  y = bb[i+1][0]
  z = bb[i+1][1]-bb[i][1]
  edge[x].append([z,y])
  edge[y].append([z,x])
  
for i in range(n-1):
  a = chk[i][0]
  b = chk[i+1][0]
  c = chk[i+1][2]-chk[i][2]
  edge[a].append([c,b])
  edge[b].append([c,a])
  
edge = tuple(edge)
print(prim_heap())

Submission status: Time Limit Exceeded

Solution code:
import sys
input = sys.stdin.readline
import heapq
def prim_heap():
    used = [True] * n #True:不使用
    edgelist = []
    for e in edge[0]:
        heapq.heappush(edgelist,e)
    used[0] = False
    res = 0
    while len(edgelist) != 0:
        minedge = heapq.heappop(edgelist)
        if not used[minedge[1]]:
            continue
        v = minedge[1]
        used[v] = False
        for e in edge[v]:
            if used[e[1]]:
                heapq.heappush(edgelist,e)
        res += minedge[0]
    return res

n = int(input())
st = []
edge = [[] for i in range(n)]
for i in range(n):
    x,y = map(int,input().split())
    st.append((i,x,y))
    
from operator import itemgetter
bb = tuple(sorted(st,key=itemgetter(1)))
chk = tuple(sorted(st,key=itemgetter(2)))
#print(bb,chk)

for i in range(n-1):
  x = bb[i][0]
  y = bb[i+1][0]
  z = bb[i+1][1]-bb[i][1]
  #print(z)
  edge[x].append([z,y])
  edge[y].append([z,x])
  
for i in range(n-1):
  a = chk[i][0]
  b = chk[i+1][0]
  c = chk[i+1][2]-chk[i][2]
  #print(c)
  edge[a].append([c,b])
  edge[b].append([c,a])
  
print(prim_heap())

Submission status: Time Limit Exceeded

Solution code:
import sys
from collections import *
import heapq
import math
import bisect
from itertools import permutations,accumulate,combinations,product
from fractions import gcd
def input():
    return sys.stdin.readline()[:-1]
def ruiseki(lst):
    return [0]+list(accumulate(lst))
mod=pow(10,9)+7
al=[chr(ord('a') + i) for i in range(26)]

n=int(input())
xy=[0]*n
for i in range(n):
    x,y=map(int,input().split())
    xy[i]=[x,y,i]

def prim_heap():
    used = [True] * n #True:不使用
    edgelist = []
    for e in edge[0]:
        heapq.heappush(edgelist,e)
    used[0] = False
    res = 0
    while len(edgelist) != 0:
        minedge = heapq.heappop(edgelist)
        if not used[minedge[1]]:
            continue
        v = minedge[1]
        used[v] = False
        for e in edge[v]:
            if used[e[1]]:
                heapq.heappush(edgelist,e)
        res += minedge[0]
    return res

#########################

xy.sort()
edge = [[] for i in range(n)]
#隣接リスト edge[i]:[コスト,行先]
for i in range(n-1):
    x1,x2=xy[i][0],xy[i+1][0]
    n1,n2=xy[i][2],xy[i+1][2]
    edge[n1].append([x2-x1,n2])
    edge[n2].append([x2-x1,n1])

xy.sort(key=lambda x: x[1])
for i in range(n-1):
    x1,x2=xy[i][1],xy[i+1][1]
    n1,n2=xy[i][2],xy[i+1][2]
    edge[n1].append([x2-x1,n2])
    edge[n2].append([x2-x1,n1])

print(prim_heap())

Submission status: Time Limit Exceeded

Solution code:
import sys
from collections import *
import heapq
import math
import bisect
from itertools import permutations,accumulate,combinations,product
from fractions import gcd
def input():
    return sys.stdin.readline()[:-1]
def ruiseki(lst):
    return [0]+list(accumulate(lst))
mod=pow(10,9)+7
al=[chr(ord('a') + i) for i in range(26)]

n=int(input())
xy=[list(map(int,input().split())) for i in range(n)]
for i in range(n):
    xy[i].append(i)

def prim_heap():
    used = [True] * n #True:不使用
    edgelist = []
    for e in edge[0]:
        heapq.heappush(edgelist,e)
    used[0] = False
    res = 0
    while len(edgelist) != 0:
        minedge = heapq.heappop(edgelist)
        if not used[minedge[1]]:
            continue
        v = minedge[1]
        used[v] = False
        for e in edge[v]:
            if used[e[1]]:
                heapq.heappush(edgelist,e)
        res += minedge[0]
    return res

#########################

xy.sort()
edge = [[] for i in range(n)]
#隣接リスト edge[i]:[コスト,行先]
for i in range(n-1):
    x1,x2=xy[i][0],xy[i+1][0]
    n1,n2=xy[i][2],xy[i+1][2]
    edge[n1].append([x2-x1,n2])
    edge[n2].append([x2-x1,n1])

xy.sort(key=lambda x: x[1])
for i in range(n-1):
    x1,x2=xy[i][1],xy[i+1][1]
    n1,n2=xy[i][2],xy[i+1][2]
    edge[n1].append([x2-x1,n2])
    edge[n2].append([x2-x1,n1])
print(prim_heap())

Submission status: Time Limit Exceeded

Solution code:
import sys
from collections import *
import heapq
import math
import bisect
from itertools import permutations,accumulate,combinations,product
from fractions import gcd
def input():
    return sys.stdin.readline()[:-1]
def ruiseki(lst):
    return [0]+list(accumulate(lst))
mod=pow(10,9)+7
al=[chr(ord('a') + i) for i in range(26)]

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

import heapq
def prim_heap():
    used = [True] * n #True:不使用
    edgelist = []
    for e in edge[0]:
        heapq.heappush(edgelist,e)
    used[0] = False
    res = 0
    while len(edgelist) != 0:
        minedge = heapq.heappop(edgelist)
        if not used[minedge[1]]:
            continue
        v = minedge[1]
        used[v] = False
        for e in edge[v]:
            if used[e[1]]:
                heapq.heappush(edgelist,e)
        res += minedge[0]
    return res

#########################

xy.sort()
edge = [[] for i in range(n)]
#隣接リスト edge[i]:[コスト,行先]
for i in range(n-1):
    x1,x2=xy[i][0],xy[i+1][0]
    n1,n2=xy[i][2],xy[i+1][2]
    edge[n1].append([x2-x1,n2])
    edge[n2].append([x2-x1,n1])

xy.sort(key=lambda x: x[1])
for i in range(n-1):
    x1,x2=xy[i][1],xy[i+1][1]
    n1,n2=xy[i][2],xy[i+1][2]
    edge[n1].append([x2-x1,n2])
    edge[n2].append([x2-x1,n1])
print(prim_heap())

Submission status: Time Limit Exceeded

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

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

    def unite(self, x, y):
        x = self.root(x)
        y = self.root(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.root(x)]

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

    def members(self, x):
        root = self.root(x)
        return [i for i in range(self.n) if self.root(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 = int(input())
    
    x, y = [[0, 0] for _ in range(N)], [[0, 0] for _ in range(N)]
    for i in range(N):
        x[i][0], y[i][0] = map(int, input().split())
        x[i][1], y[i][1] = i, i
    x, y = sorted(x), sorted(y)
    
    L = [[0, 0, 0] for _ in range((N - 1) * 2)]
    for i in range(N - 1):
        L[i * 2][0] = x[i + 1][0] - x[i][0]
        L[i * 2][1] = x[i][1]
        L[i * 2][2] = x[i + 1][1]
        L[i * 2 + 1][0] = y[i + 1][0] - y[i][0]
        L[i * 2 + 1][1] = y[i][1]
        L[i * 2 + 1][2] = y[i + 1][1]
    L = sorted(L)

    tree = UnionFind(N)
    ans = 0
    for i in range((N - 1) * 2):
        if not tree.same(L[i][1], L[i][2]):
            ans += L[i][0]
            tree.unite(L[i][1], L[i][2])
    print(ans)
    

if __name__ == '__main__':
    main()

Submission status: Time Limit Exceeded

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

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

    def unite(self, x, y):
        x = self.root(x)
        y = self.root(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.root(x)]

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

    def members(self, x):
        root = self.root(x)
        return [i for i in range(self.n) if self.root(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())


from heapq import heapify, heappop, heappush, heappushpop


class PriorityQueue:
    def __init__(self, heap):
        self.heap = heap
        heapify(self.heap)

    def push(self, item):
        heappush(self.heap, item)

    def pop(self):
        return heappop(self.heap)

    def pushpop(self, item):
        return heappushpop(self.heap, item)

    def __call__(self):
        return self.heap

    def __len__(self):
        return len(self.heap)


def main():
    N = int(input())
    x_q, y_q = PriorityQueue([]), PriorityQueue([])
    for i in range(N):
        x, y = map(int, input().split())
        x_q.push([x, i])
        y_q.push([y, i])

    l_q = PriorityQueue([])
    x, id_x = x_q.pop()
    y, id_y = y_q.pop()
    for i in range(N - 1):
        xn, id_xn = x_q.pop()
        yn, id_yn = y_q.pop()
        l_q.push([abs(xn - x), id_x, id_xn])
        l_q.push([abs(yn - y), id_y, id_yn])
        x, y = xn, yn
        id_x, id_y = id_xn, id_yn

    tree = UnionFind(N)
    ans = 0
    while len(l_q):
        cost, i, j = l_q.pop()
        if not tree.same(i, j):
            ans += cost
            tree.unite(i, j)
    print(ans)


if __name__ == '__main__':
    main()

Submission status: Time Limit Exceeded

Solution code:
from heapq import *
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 unite(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 -size.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())
n=int(input())
X=[]
Y=[]
edge=[] 
for i in range(n):
  x,y=map(int,input().split())
  X.append((x,i))
  Y.append((y,i))
  edge.append((x,y))
X.sort()
Y.sort()
hq=[]
heapify(hq)
for i in range(n-1):
  x1,j1=X[i]
  x2,j2=X[i+1]
  y1,k1=Y[i]
  y2,k2=Y[i+1]
  heappush(hq,(x2-x1,j1,j2))
  heappush(hq,(y2-y1,k1,k2))
uf=UnionFind(n)
ans=0
while hq:
  w,s,t=heappop(hq)
  if uf.find(s)!=uf.find(t):
    uf.unite(s,t)
    ans+=w
print(ans)

Submission status: Time Limit Exceeded

Solution code:
class UnionFind():
    def __init__(self,n):
        self.n=n
        self.par=[i for i in range(n)]
        self.size=[1]*n
    def find(self,x):
        if x==self.par[x]:
            return self.par[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.size[x]>self.size[y]:
            self.size[x]+=self.size[y]
            self.par[y]=x
        else:
            self.size[y]+=self.size[x]
            self.par[x]=y

n=int(input())

x_list=[]
y_list=[]

for i in range(n):
    x,y=map(int,input().split())
    x_list.append((x,i))
    y_list.append((y,i))
x_list.sort()
y_list.sort()
edges=[]

for i in range(1,n):
    edges.append((x_list[i][0]-x_list[i-1][0],x_list[i][1],x_list[i-1][1]))

    edges.append((y_list[i][0]-y_list[i-1][0],y_list[i][1],y_list[i-1][1]))

edges.sort()
uf=UnionFind(n)
ans=0
for e in edges:
    wt=e[0]
    x=e[1]
    y=e[2]
    if uf.find(x)==uf.find(y):
        continue
    ans+=wt
    uf.unite(x,y)
print(ans)

Submission status: Time Limit Exceeded

Solution code:
import heapq
class Graph:
    def __init__(self,v,edgelist,w_v = None,directed = False):
        super().__init__()
        self.v = v
        self.w_e = [{} for _ in [0]*self.v]
        self.neighbor = [[] for _ in [0]*self.v]
        self.w_v = w_v
        self.directed = directed

        for i,j,w in edgelist:
            self.w_e[i][j] = w
            self.neighbor[i].append(j)

    def dijkstra(self,v_n):
        d = [float('inf')]*self.v
        d[v_n] = 0
        prev = [-1]*self.v

        queue = []
        for i,d_i in enumerate(d): heapq.heappush(queue,(d_i,i))
        
        while len(queue)>0:
            d_u,u = queue.pop()
            if d[u]<d_u :continue
            for v in self.neighbor[u]:
                alt = d[u]+self.w_e[u][v]
                if d[v]>alt:
                    d[v] = alt
                    prev[v] = u
                    heapq.heappush(queue,(alt,v))

        return d,prev

    def warshallFloyd(self):
        d = [[10**18]*self.v for _ in [0]*self.v]
        for i in range(self.v):
            d[i][i] = 0
            
        for i in range(self.v):
            for j in self.neighbor[i]:
                d[i][j] = self.w_e[i][j]
            
        for i in range(self.v):
            for j in self.neighbor[i]:
                d[i][j] = self.w_e[i][j]
        
        for k in range(self.v):
            for i in range(self.v):
                for j in range(self.v):
                    check = d[i][k] + d[k][j]
                    if d[i][j] > check:
                        d[i][j] = check
        return d

    def prim(self):
        gb = GraphBuilder(self.v,self.directed)
        queue = []
        for i,w in self.w_e[0].items(): heapq.heappush(queue,(w,0,i))
        rest = [True]*self.v
        rest[0] = False

        v = 1
        while len(queue)>0:
            w,i,j = heapq.heappop(queue)
            if rest[j]:
                gb.addEdge(i,j,w)
                rest[j] = False
                for k,w in self.w_e[j].items():
                    if rest[k]:heapq.heappush(queue,(w,j,k))

        return gb

class Tree():
    def __init__(self,v,e):
        pass

class GraphBuilder():
    def __init__(self,v,directed = False):
        self.v = v
        self.directed = directed
        self.edge = []

    def addEdge(self,i,j,w=1):
        if not self.directed:
            self.edge.append((j,i,w))
        self.edge.append((i,j,w))

    def addEdges(self,edgelist,weight = True):
        if weight:
            if self.directed:
                for i,j,w in edgelist:
                    self.edge.append((i,j,w))
            else:
                for i,j,w in edgelist:
                    self.edge.append((i,j,w))
                    self.edge.append((j,i,w))
        else:
            if self.directed:
                for i,j,w in edgelist:
                    self.edge.append((i,j,1))
            else:
                for i,j,w in edgelist:
                    self.edge.append((i,j,1))
                    self.edge.append((j,i,1))
            

    def addAdjMat(self, mat):
        for i,mat_i in enumerate(mat):
            for j,w in enumerate(mat_i):
                self.edge.append((i,j,w))

    def buildTree(self):
        pass

    def buildGraph(self):
        return Graph(self.v,self.edge,directed=self.directed)

def main():

    n= int(input())
    edge = []
    for i in range(n):
      x,y = list(map(int,input().split()))
      edge.append((x,y,i))
    
    xs = sorted(edge,key=lambda a:a[0])
    ys = sorted(edge,key=lambda a:a[1])

    edge = []
    
    for i in range(n-1):
      x1,y1,p1 = xs[i]
      x2,y2,p2 = xs[i+1]
      edge.append((p1,p2,min(x2-x1,abs(y2-y1))))
      
      x1,y1,p1 = ys[i]
      x2,y2,p2 = ys[i+1]
      edge.append((p1,p2,min(abs(x2-x1),y2-y1)))
      
      
    gb = GraphBuilder(n)
    gb.addEdges(edge)

    mint = gb.buildGraph().prim()

    ans = 0
    for a in mint.edge:
      ans+=a[2]
    print(ans//2)
      
if __name__ == "__main__":
    main()