You are given an array points representing integer coordinates of some points on a 2D-plane, where points[i] = [xi, yi].
The cost of connecting two points [xi, yi] and [xj, yj] is the manhattan distance between them: |xi - xj| + |yi - yj|, where |val| denotes the absolute value of val.
Return the minimum cost to make all points connected. All points are connected if there is exactly one simple path between any two points.
 
Example 1:

Input: points = [[0,0],[2,2],[3,10],[5,2],[7,0]]
Output: 20
Explanation:

We can connect the points as shown above to get the minimum cost of 20.
Notice that there is a unique path between every pair of points.

Example 2:
Input: points = [[3,12],[-2,5],[-4,1]]
Output: 18

Example 3:
Input: points = [[0,0],[1,1],[1,0],[-1,1]]
Output: 4

Example 4:
Input: points = [[-1000000,-1000000],[1000000,1000000]]
Output: 4000000

Example 5:
Input: points = [[0,0]]
Output: 0

 
Constraints:

1 <= points.length <= 1000
-106 <= xi, yi <= 106
All pairs (xi, yi) are distinct.

Difficulty: interview

Starter code:

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        

Solutions:
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        dist = [float(\"inf\")] * n
        remain = set()
        for i in range(0,n):
            remain.add(i)
        dist[0] = 0
        remain.discard(0)
        curr = 0
        res = 0
        while len(remain) > 0:
            lo = float(\"inf\")
            loind = -1
            # curr is the next lowest
            a,b = points[curr]
            for r in remain:
                x,y = points[r]
                tempdist = abs(x-a) + abs(y-b)
                if tempdist < dist[r]:
                    dist[r] = tempdist
                tempdist = dist[r]
                
                if tempdist < lo:
                    lo = tempdist
                    loind = r
            
            res += lo
            
            curr = loind
            # remove curr from remain
            remain.discard(curr)
            
        return res
            

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        score = [-1] * len(points)
        total_score = 0
        for i in range(1, len(points)):
            x, y = points[i-1][0], points[i-1][1]
            cur_min_idx, cur_min_val = -1, -1
            for j in range(i, len(points)):
                cur_dist = abs(x - points[j][0]) + abs(y - points[j][1])
                if score[j] == -1:
                    score[j] = cur_dist
                elif cur_dist < score[j]:
                    score[j] = cur_dist
                if cur_min_val == -1 or score[j] < cur_min_val:
                    cur_min_val, cur_min_idx = score[j], j
            total_score += cur_min_val
            if i != j:
                score[cur_min_idx], score[i] = score[i], score[cur_min_idx]
                points[cur_min_idx], points[i] = points[i], points[cur_min_idx]
        return total_score
                    


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        '''
        prim's algorithm.
        for each left over points:
                add the shortest edge to the tree.
                update the shortest edge from the left over points.
        '''
        cost = 0
        Left_over_points_minEdge = [(abs(points[i][0]-points[0][0])+abs(points[i][1]-points[0][1]),0,i) for i in range(1,len(points))]
        heapq.heapify(Left_over_points_minEdge)
        #mst = [] # to store the minimal spanning tree. Not necessary here.
        while Left_over_points_minEdge: # K for K in N-1... 1
            shortest, frm, to = heapq.heappop(Left_over_points_minEdge) #(O(1))
            cost += shortest
            #mst.append((frm,to))
            
            # \"add or rather use\" new edges from \"to\" and update the min distance to the tree
            for pos,(d, _, i ) in enumerate( Left_over_points_minEdge ): #O(K-1)
                dist = abs(points[i][0]-points[to][0])+abs(points[i][1]-points[to][1])
                if dist < d:
                    Left_over_points_minEdge[pos] = (dist,to,i)
                    heapq._siftdown(Left_over_points_minEdge,0,pos) #(O(log(K))
            
            #heapq.heapify(Left_over_points_minEdge) #O(K-1)
            
        #print(mst)    
        return cost
            
        
        
        
        
        
                
        
        
        
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def manhattan(x, y):
            return abs(x[0] - y[0]) + abs(x[1] - y[1])
        ans, n = 0, len(points)
        seen = set()
        edges = [(0, 0, 0)]
        while len(seen) < n:
            w, u, v = heapq.heappop(edges)
            if v in seen:
                continue
            seen.add(v)
            ans += w
            for i in range(len(points)):
                if i not in seen and i != u:
                    heapq.heappush(edges, (manhattan(points[v], points[i]), v, i))
        return ans                           
                
        
                
                
            
            


class DisjointSet:
    def __init__(self, n):
        self.parent = [-1] * n #If a node is root, its parent is the negative size
        
    def find(self, x):
        if self.parent[x] < 0:
            return x
        else:
            # Path compression
            root = self.find(self.parent[x])
            self.parent[x] = root
            return root
    
    def union(self, a, b):
        root_a = self.find(a)
        root_b = self.find(b)
        if root_a == root_b:
            return False
        
        if self.parent[root_a] > self.parent[root_b]:
            temp = root_a
            root_a = root_b
            root_b = temp
            
        self.parent[root_a] += self.parent[root_b]
        self.parent[root_b] = root_a
        return True
        
    def size(self, x):
        root = self.find(x)
        return self.parent[root] *-1

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        edges = []
        for i, point1 in enumerate(points):
            for j in range(i+1, len(points)):
                point2 = points[j]
                cost = abs(point2[0] - point1[0]) + abs(point2[1] - point1[1])
                edges.append([cost, i, j])
                
        ans = 0
        edges.sort()
        graph = DisjointSet(len(points))
        for edge in edges:
            if graph.union(edge[1], edge[2]):
                ans += edge[0]
                
        return ans
                
        
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        parent = [i for i in range(len(points))]
        size = [1 for _ in range(len(points))]
        
        def root(p):
            while parent[p] != p:
                parent[p] = parent[parent[p]]
                p = parent[p]
                
            return p
        
        def union(p, q):
            root_p, root_q = root(p), root(q)
            if root_p != root_q:
                if size[root_p] < size[root_q]:
                    parent[root_p] = root_q
                    size[root_q] += size[root_p]
                else:
                    parent[root_q] = root_p
                    size[root_p] += size[root_q]
        
        def connected(p, q):
            return root(p) == root(q)
        
        # connected = set()
        p = points
        ans = 0
        def dist(p1, p2):
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        
        d = [ [(0, _)] * (len(p)) for _ in range(len(p))]
        heap = []
        for i in range(len(p)):
            for j in range(i+1, len(p)):
                temp = dist(p[i],p[j])
                d[i][j] = (temp, j)
                d[j][i] = (temp, i)
                heappush(heap, (temp, (i, j)))
        
        while heap:
            dis, (i, j) = heappop(heap)
            if not connected(i, j):
                ans += dis
                union(i, j)
                                
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # try minimum spanning treee
        
        to_visit = set(range(1, len(points)))
        pq = [(abs(points[0][0] - points[x][0]) + abs(points[0][1] - points[x][1]), x) for x in range(1, len(points))]
        heapq.heapify(pq)
        ans = 0
        while pq:
            cost, to = heapq.heappop(pq)
            if to in to_visit:
                to_visit.remove(to)
                ans += cost
                for nei in to_visit:
                    x, y = points[nei]
                    heapq.heappush(pq, (abs(x-points[to][0]) + abs(y-points[to][1]), nei))

        return ans
        
        
        
            
            



import queue
import sys

class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:
        n = len(p)
        graph = [[] for i in range(n + 1)]
        dist = [1000000000 for i in range(n + 1)]
        for i in range(len(p)):
            for j in range(len(p)):
                if i == j: 
                    continue
                graph[i].append((j, abs(p[i][0] - p[j][0]) + abs(p[i][1] - p[j][1])))
                graph[j].append((i, abs(p[i][0] - p[j][0]) + abs(p[i][1] - p[j][1])))
        pq = queue.PriorityQueue()
        pq.put((0, 0))
        dist[0] = 0
        res = 0
        while pq.empty() == False:
            (du, u) = pq.get()
            if du != dist[u]:
                continue

            dist[u] = 0
            res += du
            for (v, uv) in graph[u]:
                if dist[v] > uv:
                    dist[v] = uv
                    pq.put((uv, v))
        return res                

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def build_graph(points):
            g = {i:{} for i in range(len(points))}
            for i in range(len(points)):
                for j in range(i+1, len(points)):
                    dist = abs(points[j][0] - points[i][0]) + abs(points[j][1] - points[i][1])
                    g[i][j] = dist
                    g[j][i] = dist
            return g
        
        def min_span_tree(g):
            import heapq
            
            cost = 0
            min_heap = []
            heapq.heappush(min_heap, (0, 0))
            visited = set()
            
            while len(min_heap):
                nxt_cost, idx = heapq.heappop(min_heap)
                if idx in visited:
                    continue
                visited.add(idx)
                cost += nxt_cost
                # print('visit', idx, nxt_cost, cost, visited, min_heap)

                for adj in g[idx]:
                    if adj not in visited:
                        heapq.heappush(min_heap, (g[idx][adj], adj))
            return cost
        
        g = build_graph(points)
        return min_span_tree(g)

class DSU:
    def __init__(self, N):
        self.par = list(range(N))
        self.sz = [1]*N
        
    def find(self, x):
        if self.par[x] != x:
            self.par[x] = self.find(self.par[x])
        return self.par[x]
    
    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        
        if xr == yr:
            return False
        if self.sz[xr] < self.sz[yr]:
            xr, yr = yr, xr
            
        self.par[yr] = xr
        self.sz[xr] += self.sz[yr]
        return True
    
    def size(self, x):
        return self.sz[self.find(x)]
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        edges = []
        N = len(points)
        for i in range(N):
            for j in range(i+1,N):
                d = abs(points[i][0]-points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append([d, i, j])
                
        edges.sort()
        
        u = DSU(N)
        res = 0
        
        for edge in edges:
            if u.union(edge[1], edge[2]):
                res += edge[0]
                
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        dist = collections.defaultdict(dict)
        n = len(points)
        for i in range(n):
            for j in range(i+1,n):
                d = abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                dist[i][j] = dist[j][i] = d
        # print(dist)
        ret = 0
        visited = set([])
        pq = [(0,0)] # dist to s, index, dist to neighbour
        while pq:
            cnt,ind = heapq.heappop(pq)
            if ind not in visited:
                ret += cnt
                visited.add(ind)
                # print(ret,pq)
                for nei in dist[ind]:
                    if nei not in visited:
                        heapq.heappush(pq,(dist[ind][nei],nei))
        return ret
                
                


class Solution:
    
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def find(a):
            if parents[a]!=a:
                return find(parents[a])
            return a


        def union(a,b):
            xa=find(a)
            xb=find(b)
            if xa==xb:
                return
            if rank[xa]>rank[xb]:
                parents[xb]=xa

            elif rank[xa]<rank[xb]:
                parents[xa]=xb
            else:
                parents[xa]=xb
                rank[xb]+=1
        n=len(points)
        parents=[i for i in range(n)]
        rank=[i for i in range(n)]
        edges = []
        for i in range(n):
            for j in range(i+1, n):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((dist, i, j))
        edges.sort()
        
        # using Kruskal's algorithm to find the cost of Minimum Spanning Tree
        res = 0
        
        for cost, u, v in edges:
            if find(u) != find(v):
                union(u, v)
                res += cost
        
        return res
                    


from heapq import *
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        heap = []
        d = collections.defaultdict(list)
        
        n = len(points)
        for i in range(n):
            for j in range(i+1, n):
                x = tuple(points[i])
                y = tuple(points[j])
                distance = abs(x[0]-y[0]) + abs(x[1]- y[1])
                d[x].append((distance, y))
                d[y].append((distance, x))
        
        start=tuple(points[0])
        heap = d[start].copy()
        heapify(heap)
        res, s = 0, set([start])
        while len(s) < n:
            closest = heappop(heap)
            while closest[1] in s:
                closest = heappop(heap)
            
            s.add(closest[1])
            res += closest[0]
            for neig in d[closest[1]]:
                if neig not in s:
                    heappush(heap, neig)
        
        return res
            
            
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) <= 1:
            return 0
        
        def find(x):
            if x != parent[x]:
                parent[x] = find(parent[x])
                return parent[x]
            
            return x
                
        n = len(points)
                
        parent = list(range(n))
        
        dists = []
        
        for i in range(n - 1):
            for j in range(i + 1, n):
                mand = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                heapq.heappush(dists, (mand, i, j))
                
        # dists.sort(key=lambda item: item[0])
        
        res = 0
        
        while dists:
            w, a, b = heapq.heappop(dists)
            pa = find(a)
            pb = find(b)
            
            if pa != pb:
                res += w
                parent[pa] = parent[pb]
                    
        return res

\"\"\"
This is a minimum spanning tree problem, which can be solved by kruskal's algo or Prim's algo.
We need to pre-compute all the possible edges' weights
\"\"\"
import heapq
from typing import Tuple
class Solution:
    def __init__(self):
      self.roots = {}
      self.ranks = {}
      
    def find(self, point: Tuple[int, int]) -> Tuple[int, int]:
      self.roots.setdefault(point, point)
      self.ranks.setdefault(point, 1)
      if point != self.roots[point]:
        self.roots[point] = self.find(self.roots[point])
      return self.roots[point]
    
    def union(self, point1: Tuple[int, int], point2: Tuple[int, int], root1: Tuple[int, int], root2: Tuple[int, int]):
      if self.ranks[root1] > self.ranks[root2]:
        self.roots[root2] = root1
      elif self.ranks[root1] < self.ranks[root2]:
        self.roots[root1] = root2
      else:
        self.roots[root1] = root2
        self.ranks[root2] += 1
      
    \"\"\"
    Kruskal's algo: always select the lightest edge, and use a union find to detect cycles. If there are cycles ignore that edge.
    Time:
    For minimum spanning tree, V vertices have E=V-1 edges.
      * Compute all edge weights and sort: E^2 + ElogE
      * union find: amortized O(1), need to do this for all edges, so O(V). (Yes union-find with path compession and rank by union, has amortized time O(1))
      Over all E^2 + ElogE + V
    Interestingly, bisect performs a lot worse than heapq for this question. bisect.insort would result in a TLE.
    \"\"\"
#     def minCostConnectPoints(self, points: List[List[int]]) -> int:
#       min_cost = 0
#       edge_count = 0
#       all_weights = []
#       for i in range(len(points)):
#         for j in range(i + 1, len(points)):
#           xi, yi, xj, yj = (*points[i], *points[j])
#           dist = abs(xi - xj) + abs(yi - yj)
#           heapq.heappush(all_weights, (dist, xi, yi, xj, yj))
      
#       # print(\"all_weights: \", all_weights)
      
#       while len(all_weights) > 0:
#         weight, xi, yi, xj, yj = heapq.heappop(all_weights)
#         rooti, rootj = self.find((xi, yi)), self.find((xj, yj))
#         if rooti != rootj:
#           self.union((xi, yi), (xj, yj), rooti, rootj)
#           # print(\"selected: \", weight, xi, yi, xj, yj)
#           min_cost += weight
#           edge_count += 1
          
#           if edge_count == len(points) - 1: break
      
#       return min_cost
    \"\"\"
    Prim's algo: this is very similar to Dijkstra's algo: start from one point, and BFS to expand to other points. 
    \"\"\"
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
      if len(points) == 0: return 0
      min_cost = 0
      cur = points[0]
      unvisited = {(x, y) for x, y in points[1:]}
      all_edges = []

      while cur:
        if len(unvisited) == 0: break
        for nbr in unvisited:
          dist = abs(cur[0] - nbr[0]) + abs(cur[1] - nbr[1])
          heapq.heappush(all_edges, (dist, tuple(cur), tuple(nbr)))

        while all_edges:
          weight, cur, nbr = heapq.heappop(all_edges)
          if nbr in unvisited:
            min_cost += weight
            cur = nbr
            unvisited.remove(nbr)
            break
      return min_cost

            
          
        
        
        
      

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        costMap = [0] * len(points)
        
        minHeap = []
        heappush(minHeap, (0, points[0], 0))
        visited = set()
        
        while minHeap:
            cost, [currentX, currentY], currentIndex = heappop(minHeap)
            if (currentX, currentY) in visited:
                if costMap[currentIndex] <= cost:
                    continue

            for i, p in enumerate(points):
                if not ((p[0], p[1]) in visited) and i != currentIndex:
                    nextCost = abs(currentX - p[0]) + abs(currentY - p[1])
                    heappush(minHeap, (nextCost, p, i))
            if (currentX, currentY) in visited:
                costMap[currentIndex] = min(costMap[currentIndex], cost)
            else:
                costMap[currentIndex] = cost

            visited.add((currentX, currentY) )
        
        return sum(costMap)

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        distance = []
        for i in range(N):
            for j in range(i + 1, N):
                dist= abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                distance.append((dist, i, j))
        heapq.heapify(distance)
        
        parent = [i for i in range(N)]
        def find(x):
            while x != parent[x]:
                parent[x] = parent[parent[x]]
                x = parent[x]
            return x

        res = 0
        while distance:
            dist, i, j = heapq.heappop(distance)
            pi = find(i)
            pj = find(j)
            if pi != pj:
                parent[pi] = pj
                res += dist
        
        return res

from heapq import heappush, heappop
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = [[0 for j in range(len(points))] for i in range(len(points))]
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                edges[i][j] = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                edges[j][i] = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
        inf = 1234567890
        # distances = [inf for i in range(n)]
        frontier = [(0, 0)]
        gotem = set()
        ans = 0
        while len(frontier) > 0:
            cost, ex = heappop(frontier)
            if ex in gotem:
                continue
            ans += cost
            gotem.add(ex)
            for i in range(len(points)):
                if i not in gotem and i != ex:
                    heappush(frontier, (edges[ex][i], i))
        return ans
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def cost_of(i, j):
            x1, y1 = points[i]
            x2, y2 = points[j]
            
            return abs(x1 - x2) + abs(y1 - y2)
            
        N = len(points)
        parent = list(range(N))
        size = [1] * N
        
        def union(x, y):
            x = find(x)
            y = find(y)
            
            if x == y:
                return False
            
            if size[x] < size[y]:
                x, y = y, x
            
            parent[y] = x
            size[x] += size[y]
            
            return True
            
            
        def find(x):
            if parent[x] != x:
                parent[x] = find(parent[x])
            return parent[x]
        
        edges = []
        
        for i in range(N):
            for j in range(i + 1, N):
                edges.append((cost_of(i, j), i, j))
        
        heapq.heapify(edges)
        total_cost = 0
        
        while edges:
            cost, p1, p2 = heapq.heappop(edges)
            
            if union(p1, p2):
                total_cost += cost
        
        return total_cost
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        connections = []
        for i in range(N):
            for j in range(i+1, N):
                connections.append([abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]), i, j])
        
        if len(connections) < N - 1:
            return -1
        elif N == 1:
            return 0
        uf = {}
        def find(x):
            uf.setdefault(x, x)
            if uf[x] != x:
                uf[x] = find(uf[x])
            return uf[x]
        def union(x, y):
            uf[find(x)] = find(y)
        
        res = 0
        for cost, start, end in sorted(connections):
            if find(start) != find(end):
                res += cost
                union(start, end)
        if len({find(c) for c in uf}) == 1:
            return res
        return -1


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
    # 940        
        dsu = DSU()
        min_heap = []
        for i in range(len(points)):
            x1, y1 = points[i][0], points[i][1]
            for j in range(i + 1, len(points)):
                x2, y2 = points[j][0], points[j][1]
                heappush(min_heap, (abs(x1 - x2) + abs(y1 - y2), (x1,y1,x2,y2)))
    
        cost = 0
        while min_heap:
            c, (x1,y1,x2,y2) = heappop(min_heap)
            if dsu.find((x1,y1)) != dsu.find((x2,y2)):
                cost += c
                dsu.union((x1,y1), (x2, y2))
        return cost
    
    
    
class DSU:
    def __init__(self):
        self.father = {}
    
    def find(self, a):
        self.father.setdefault(a, a)
        if a != self.father[a]:
            self.father[a] = self.find(self.father[a])
        return self.father[a]
    
    def union(self, a, b):
        _a = self.find(a)
        _b = self.find(b)
        if _a != _b:
            self.father[_a] = _b
        
        
        
        
        
        
        
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        e = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                e.append([i,j])
        def h(x):
            return abs(points[x[0]][0]-points[x[1]][0]) + abs(points[x[0]][1]-points[x[1]][1])
        e.sort(key=lambda x : h(x))
        
        #print([[points[x], points[y], h((x,y))] for x,y in e])
                
        n = len(points)
        v = set()
        s = 0
        c = []
        
        def find(x):
            nonlocal c
            for i,cc in enumerate(c):
                if x in cc:
                    return i
        
        for ee in e:
            x,y = ee
            if y not in v and x not in v:
                c.append([x,y])    
                v.add(x)
                v.add(y)
                s+=h(ee)
            elif x not in v:
                yi = find(y)
                c[yi].append(x)
                v.add(x)
                s+=h(ee)
            elif y not in v:
                xi = find(x)
                c[xi].append(y)
                v.add(y)
                s+=h(ee)
            else:
                xi = find(x)
                yi = find(y)
                if xi == yi:
                    continue
                s+=h(ee)
                c[xi]+=c[yi]
                del c[yi]
                if len(v) == n and len(c) == 1:
                    return s
        #print(v)
        return s

class UnionFind:
    def __init__(self, n): 
        self.parent = list(range(n))
        self.count = n
        self.rank = [1]*n
        
    def find(self, p): 
        if p != self.parent[p]:
            self.parent[p] = self.find(self.parent[p]) # path compression 
        return self.parent[p]
    
    def union(self, p, q): 
        prt = self.find(p)
        qrt = self.find(q)
        if prt == qrt: return False # already connected 
        if self.rank[prt] > self.rank[qrt]: prt, qrt = qrt, prt
        self.parent[prt] = qrt 
        self.rank[qrt] += self.rank[prt]
        return True 
    

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        uf = UnionFind(n)
        
        hp = [] # min heap 
        
        for i in range(n):
            x, y = points[i]
            for ii in range(i+1, n):
                xx, yy = points[ii]
                cost = abs(x - xx) + abs(y - yy)
                heappush(hp, (cost, i, ii))
        
        ans = 0
        while hp and uf.count != 1: 
            cost, i, ii = heappop(hp)
            if uf.union(i, ii): ans += cost 
        return ans 

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n <= 1:
            return 0
        
        distances = []
        for i in range(n):
            for j in range(i+1, n):
                xi, yi = points[i]
                xj, yj = points[j]
                heapq.heappush(distances, (abs(xi-xj) + abs(yi-yj), i, j))
        
        uf = {}
        
        def find(i: int) -> int:
            if i not in uf:
                uf[i] = i

            while uf[i] != uf[uf[i]]:
                uf[i] = find(uf[i])
            return uf[i]
        
        def union(i: int, j: int) -> None:
            uf[find(i)] = find(j)
        
        dist = 0
        
        while distances:
            d, i, j = heapq.heappop(distances)
            if find(i) != find(j):
                union(i, j)
                dist += d
        
        return dist


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        parents = [i for i in range(len(points))]
        
        pq = []
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                x, y = points[i], points[j]
                heapq.heappush(pq, (abs(x[0] - y[0]) + abs(x[1] - y[1]), i, j))
        
        res = 0
        while pq:
            dist, i, j = heapq.heappop(pq)
            if self.find(i, parents) == self.find(j, parents):
                continue
            # print(i, j, dist)
            res += dist
            self.union(i, j, parents)
        
        return res
    
    def find(self, p, parents):
        while p != parents[p]:
            parents[p] = parents[parents[p]]
            p = parents[p]
        return p
    
    def union(self, p, q, parents):
        p_root = self.find(p, parents)
        q_root = self.find(q, parents)
        if p_root != q_root:
            parents[p_root] = q_root

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n, curr, ans = len(points), 0, 0 # curr is a random point as the base of the MST
        cost = [math.inf] * n # the minimum cost to add point i to form the MST
        used = set()
        for i in range(n - 1): # n - 1 is because we need n - 1 edges totally
            x, y = points[curr]
            used.add(curr)
            for j, (u, v) in enumerate(points):
                if j in used: continue
                cost[j] = min(cost[j], abs(u - x) + abs(v - y))
            delta, curr = min((d, j) for j, d in enumerate(cost))
            cost[curr] = math.inf
            ans += delta
        return ans


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n=len(points)
        if n==1:
            return 0
        heap=[]
        dsu=DisjointSetUnion(n)
        for i in range(n-1):
            for j in range(i+1,n):
                distance=abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                heappush(heap,(distance,i,j))
        ans=0
        while heap:
            distance,i,j=heappop(heap)
            if dsu.find(i)!=dsu.find(j):
                ans += distance
                dsu.union(i,j)
        return ans
            
class DisjointSetUnion(object):

    def __init__(self, size):
        # initially, each node is an independent component
        self.parent = [i for i in range(size+1)]
        # keep the size of each component
        self.size = [1] * (size+1)
    
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        
        # the two nodes share the same set
        if px == py:
            return px
        
        # otherwise, connect the two sets (components)
        if self.size[px] > self.size[py]:
            # add the node to the union with less members.
            # keeping px as the index of the smaller component
            px, py = py, px
        # add the smaller component to the larger one
        self.parent[px] = py
        self.size[py] += self.size[px]
        # return the final (merged) group
        return py          

# Python program for Kruskal's algorithm to find 
# Minimum Spanning Tree of a given connected, 
# undirected and weighted graph 
from collections import defaultdict 
  
#Class to represent a graph 
class Graph: 
  
    def __init__(self,vertices): 
        self.V= vertices #No. of vertices 
        self.graph = [] # default dictionary  
                                # to store graph 
          
   
    # function to add an edge to graph 
    def addEdge(self,u,v,w): 
        self.graph.append([u,v,w]) 
  
    # A utility function to find set of an element i 
    # (uses path compression technique) 
    def find(self, parent, i): 
        if parent[i] == i: 
            return i 
        return self.find(parent, parent[i]) 
  
    # A function that does union of two sets of x and y 
    # (uses union by rank) 
    def union(self, parent, rank, x, y): 
        xroot = self.find(parent, x) 
        yroot = self.find(parent, y) 
  
        # Attach smaller rank tree under root of  
        # high rank tree (Union by Rank) 
        if rank[xroot] < rank[yroot]: 
            parent[xroot] = yroot 
        elif rank[xroot] > rank[yroot]: 
            parent[yroot] = xroot 
  
        # If ranks are same, then make one as root  
        # and increment its rank by one 
        else : 
            parent[yroot] = xroot 
            rank[xroot] += 1
  
    # The main function to construct MST using Kruskal's  
        # algorithm 
    def KruskalMST(self): 
  
        result =[] #This will store the resultant MST 
  
        i = 0 # An index variable, used for sorted edges 
        e = 0 # An index variable, used for result[] 
  
            # Step 1:  Sort all the edges in non-decreasing  
                # order of their 
                # weight.  If we are not allowed to change the  
                # given graph, we can create a copy of graph 
        self.graph =  sorted(self.graph,key=lambda item: item[2]) 
  
        parent = [] ; rank = [] 
  
        # Create V subsets with single elements 
        for node in range(self.V): 
            parent.append(node) 
            rank.append(0) 
      
        # Number of edges to be taken is equal to V-1 
        while e < self.V -1 : 
  
            # Step 2: Pick the smallest edge and increment  
                    # the index for next iteration 
            u,v,w =  self.graph[i] 
            i = i + 1
            x = self.find(parent, u) 
            y = self.find(parent ,v) 
  
            # If including this edge does't cause cycle,  
                        # include it in result and increment the index 
                        # of result for next edge 
            if x != y: 
                e = e + 1     
                result.append([u,v,w]) 
                self.union(parent, rank, x, y)             
            # Else discard the edge 
  
        # print the contents of result[] to display the built MST 
        # print \"Following are the edges in the constructed MST\"
        minSum = 0
        for u,v,weight  in result: 
            #print str(u) + \" -- \" + str(v) + \" == \" + str(weight) 
            print (\"%d -- %d == %d\" % (u,v,weight))
            minSum += weight
        return minSum

# Driver code 
# g = Graph(4) 
# g.addEdge(0, 1, 10) 
# g.addEdge(0, 2, 6) 
# g.addEdge(0, 3, 5) 
# g.addEdge(1, 3, 15) 
# g.addEdge(2, 3, 4) 

# g.KruskalMST() 

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # generate the graph
        
        nV = len(points)
        g = Graph(nV)
        for i in range(nV):
            for j in range(nV):
                modX = abs(points[i][0] - points[j][0])
                modY = abs(points[i][1] - points[j][1])
                manhattanDist = modX + modY
                g.addEdge(i, j, manhattanDist)
        
        # implement Kruskal's
        return g.KruskalMST()
        
        # return 0

class dsu:
    def __init__(self,n):
        self.parents = [i for i in range(n)]
        self.rank = [0 for i in range(n)]
    def find(self,u):
        if u != self.parents[u]:
            self.parents[u] = self.find(self.parents[u])
        return self.parents[u]
    def union(self,u,v):
        pu = self.parents[u]
        pv = self.parents[v]
        if pu != pv:
            if self.rank[pu] < self.rank[pv]:
                self.parents[pu] = pv
            elif self.rank[pu] > self.rank[pv]:
                self.parents[pv] = pu
            else:
                self.parents[pu] = pv
                self.rank[pv] += 1
        
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def get_dist(i,j):
            return abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
        h = []
        n = len(points)
        uf = dsu(n)
        for i in range(n):
            for j in range(i):
                heapq.heappush(h,(get_dist(i,j),i,j))
        # print(h)
        cost = 0
        count = 0
        while h:
            c,u,v = heapq.heappop(h)
            if uf.find(u) != uf.find(v):
                uf.union(u,v)
                cost += c
                count += 1
        return cost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        eg = defaultdict(list)
        n = len(points)
        for i in range(n):
            for j in range(n):
                if i != j:
                    eg[i].append([j, abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])])
        d, q = {}, [[0, 0]]
        while q:
            dis, a = heapq.heappop(q)
            if a not in d:
                d[a] = dis
                for b, c in eg[a]:
                    if b not in d:
                        heapq.heappush(q, [c, b])
        return sum(d.values())

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        if len(points) ==1:
            return 0
        heap = []
        
        f = [d for d in range(len(points))]
        
        def find(x):
            if x!=f[x]:
                f[x] = find(f[x])
            return f[x]
        
        def union(x, y):
            f[find(x)] = find(y)
            
                
        res = 0
        
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                heapq.heappush(heap, (abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1]), i, j))
                
        while heap:
            val, i, j = heapq.heappop(heap)
            if find(i)!= find(j):
                union(i, j)
                res+=val
        return res
            
        


class UnionFind:
    def __init__(self, n):
        self.parents = [i for i in range(n)]

    def find(self, x):
        if self.parents[x] == x:
            return x
        self.parents[x] = self.find(self.parents[x])
        return self.parents[x]

    def union(self, x, y):
        px = self.find(x)
        py = self.find(y)

        if px != py:
            self.parents[py] = px

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


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        graph = []
        uf = UnionFind(len(points))
        res = 0

        for i in range(len(points)):
            for j in range(len(points)):
                if i != j:
                    graph.append((i, j, abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])))
        graph.sort(key=lambda x: x[2])

        for i, j, w in graph:
            if not uf.connected(i, j):
                uf.union(i, j)
                res += w
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def dist(i, j):
            p1, p2 = points[i], points[j]
            res = abs(p1[0]-p2[0])+abs(p1[1]-p2[1])
            
            return res
        
        graph = collections.defaultdict(list)
        
        for i in range(len(points)):
            for j in range(len(points)):
                if i != j:
                    graph[i].append((dist(i, j), j))
        
        visited = set([])
        root = 0
        visited.add(root)
        edges = [pair for pair in graph[root]]
        res = 0
        heapq.heapify(edges)
      
        while edges:
            cost, nex = heapq.heappop(edges)
            
            if nex not in visited:
                #print(cost, nex)
                res += cost
                visited.add(nex)
                
                for pair in graph[nex]:
                    if pair[1] not in visited:
                        heapq.heappush(edges, pair)
            #print(edges)
        return res
        
                    
                    


class Solution:
    parents = [i for i in range(1005)]
    def findParent(i):
        if(Solution.parents[i] != i):
            Solution.parents[i] = Solution.findParent(Solution.parents[i])
        return Solution.parents[i]
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        distances = []
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                distance = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                distances.append([distance, i, j])
        distances.sort()
        ans = 0
        for distance in distances:
            if(Solution.findParent(distance[1]) != Solution.findParent(distance[2])):
                Solution.parents[Solution.parents[distance[1]]] = Solution.parents[Solution.parents[distance[2]]]
                ans += distance[0]
        Solution.parents = [i for i in range(1005)]
        return ans
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        #prims
        def manhattan(p1, p2):
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])

        g = collections.defaultdict(list)
        n = len(points)
        #create graph
        for i in range(n):
            for j in range(n):
                if i != j:
                    g[i].append((manhattan(points[i], points[j]), j))

        heap = [(0,0)]
        ans = 0
        visited = set()
        while heap:
            weight, to = heapq.heappop(heap)
            if to in visited:
                continue
            ans += weight
            visited.add(to)

            for cost, nei in g[to]:
                if nei not in visited:
                    heapq.heappush(heap, (cost, nei))

        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points)<=1:return 0
        ans=0
        par={}
        def find(x):
            if x not in par:return x
            res=find(par[x])
            par[x]=res
            return res
        def union(a,b):
            n1=find(a)
            n2=find(b)
            if n1!=n2:
                if n1<n2:
                    par[n2]=n1
                else:
                    par[n1]=n2
                return True
            else:return False
        arr=set()
        for i in range(len(points)):
            _min=10e9
            ix=-1
            for j in range(len(points)):
                if i!=j:
                    n=abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                    arr.add((n,(min(i,j),max(i,j))))
                    if n<_min:
                        ix=j
                        _min=n
            if union(i,ix):
                ans+=_min
        arr=list(arr)
        arr.sort()
        for x in arr:
            i=x[1][0]
            j=x[1][1]
            n1=find(i)
            n2=find(j)
            if n1!=n2:
                union(i,j)
                ans+=x[0]
        return ans         

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # # https://leetcode.com/problems/min-cost-to-connect-all-points/discuss/843995/Python-3-or-Min-Spanning-Tree-or-Prim's-Algorithm
        # manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        # n, c = len(points), collections.defaultdict(list)
        # for i in range(n):
        #     for j in range(i+1, n):
        #         d = manhattan(points[i], points[j])
        #         c[i].append((d, j))
        #         c[j].append((d, i))
        # cnt, ans, visited, heap = 1, 0, [0] * n, c[0]
        # visited[0] = 1
        # heapq.heapify(heap)
        # while heap:
        #     d, j = heapq.heappop(heap)
        #     if not visited[j]:
        #         visited[j], cnt, ans = 1, cnt+1, ans+d
        #         for record in c[j]: heapq.heappush(heap, record)
        #     if cnt >= n: break        
        # return ans
    
        n = len(points)
        if len(points) == 1: return 0
        res = 0
        curr = 0 # select a random point as the starting point
        dis = [math.inf] * n
        explored = set()
        
        for _ in range(n - 1):
            x0, y0 = points[curr]
            explored.add(curr)
            for j, (x, y) in enumerate(points):
                if j in explored: continue
                dis[j] = min(dis[j], abs(x - x0) + abs(y - y0))
            delta, curr = min((d, j) for j, d in enumerate(dis)) 
            dis[curr] = math.inf
            res += delta
            
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        l = len(points)
        h = []
        for i in range(l):
            for j in range(i):
                (x1, y1), (x2, y2) = points[i], points[j]
                dis = abs(x1-x2) + abs(y1-y2)
                heapq.heappush(h,[dis,i,j])
        dp = [i for i in range(l)]
        
        def find(x):
            if dp[x] != x:
                dp[x] = find(dp[x])
            return dp[x]
            
        ans = 0
        while h:
            dis, x, y = heapq.heappop(h)
            if find(x) != find(y):
                ans += dis
            dp[find(x)] = find(y)
            
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def cost_of(i, j):
            x1, y1 = points[i]
            x2, y2 = points[j]
            
            return abs(x1 - x2) + abs(y1 - y2)
            
        N = len(points)
        parent = list(range(N))
        size = [1] * N
        
        def union(x, y):
            x = find(x)
            y = find(y)
            
            if x == y:
                return False
            
            if size[x] < size[y]:
                x, y = y, x
            
            parent[y] = x
            size[x] += size[y]
            
            return True
            
            
        def find(x):
            if parent[x] != x:
                parent[x] = find(parent[x])
            return parent[x]
        
        edges = []
        
        for i in range(N):
            for j in range(i + 1, N):
                edges.append((cost_of(i, j), i, j))
        
        heapq.heapify(edges)
        total_cost = 0
        c = 0
        
        while edges:
            cost, p1, p2 = heapq.heappop(edges)
            
            if union(p1, p2):
                c += 1
                total_cost += cost
                if c == N:
                    break
        
        return total_cost
        


'''
https://leetcode.com/problems/min-cost-to-connect-all-points/
'''
from typing import List
import heapq

class Solution:
    '''
    Minimum Spanning Tree (Kruskal)
    https://leetcode.com/problems/min-cost-to-connect-all-points/discuss/843940/C%2B%2B-Minimum-Spanning-Tree-(Kruskal)

    Intuition:
    Imagine all the points form a complete graph, and length of an edge is the manhattan distance between the 2 points
    To find the min cost, we therefore need to find the minimum spanning tree

    Algorithm:
    Use the Kruskal algorithm, which invovles min heap to pick the smallest edge, and union-find to check if the edge is redundant.
    Exit when all points are connected.

    The complexity when using sort is O(n * n log (n * n)) - we have n * n edges. Using a min heap is O(k log (n * n)),
    where k is the number of edges we need to pull to complete the tree. It's much smaller than n * n in the average case.
    '''
    def minCostConnectPoints(self, points: List[List[int]]) -> int:

        n, cost = len(points), 0
        p = list(range(n))
        arr = []
        for i in range(n):
            for j in range(i+1, n):
                heapq.heappush(arr, [abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1]), i, j])

        def find(x):
            if x != p[x]: p[x] = find(p[p[x]])
            return p[x]

        while arr:
            w, i, j = heapq.heappop(arr)
            i, j = find(i), find(j)
            if i == j: continue
            cost += w
            p[i] = j

        return cost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        min_cost = 0
        msp = set()
        distances = self.compute_all_distances(points)
        groups = defaultdict(set)
        for i in range(len(points)):
            groups[i].add(i)
        while distances:
            next_min = heapq.heappop(distances)
            g1 = self.find_group(groups, next_min[1])
            g2 = self.find_group(groups, next_min[2])
            if g1 != g2:
                min_cost += next_min[0]
                groups[g1] = groups[g1] | groups[g2]
                del groups[g2]
        return min_cost
    
    def find_group(self, groups: dict, i: int) -> int:
        for group in groups: 
            if i in groups[group]: return group
        return 0
    
    def compute_all_distances(self, points: List[List[int]]) -> List[int]:
        distances = list()
        for i in range(len(points)-1):
            p1 = points[i]
            for j in range(i+1, len(points)):
                p2 = points[j]
                d = self.dist(p1, p2)
                distances.append((d, i, j))
        heapq.heapify(distances)
        return distances
    
    def dist(self, p1: List[int], p2: List[int]) -> int:
        return abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])        

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        dis = lambda x,y,x1,y1: abs(x-x1) + abs(y-y1)
        distances = []
        for i, (x, y) in enumerate(points):
            for x1, y1 in points[i+1:]:
                d = dis(x, y, x1, y1)
                distances.append((d, x, y, x1, y1))
        uf = UnionFind(len(points))
        for x, y in points:
            uf.parents[(x, y)] = (x, y)
        distances.sort()
        ans = 0
        for d, x, y, x1, y1 in distances:
            if uf.union((x, y), (x1, y1)):
                ans += d
        return ans
        
        
class UnionFind:
    def __init__(self, n):
        self.component_count = n
        self.parents = {}

    def find(self, x):
        if self.parents[x] != x:
            self.parents[x] = self.find(self.parents[x])
        return self.parents[x]

    # return true if two are newly unioned, false if already unioned.
    def union(self, x, y):
        x0 = self.find(x)
        y0 = self.find(y)
        if x0 == y0:
            return False
        self.parents[y0] = x0
        return True

class Solution:
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def dist(i,j):
            return abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
        
        n = len(points)
        fa = [i for i in range(n)]
        def findfa(x):
            if fa[x] == x:
                return x
            else:
                fa[x] = findfa(fa[x])
                return fa[x]
        e = [(dist(i,j),i,j) for j in range(n) for i in range(n)]
        e.sort()
        ans = 0
        for edge in e:
            if findfa(edge[1]) != findfa(edge[2]):
                ans += edge[0]
                fa[findfa(edge[1])] = findfa(edge[2])
        return ans
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n <= 1:
            return 0

        graph = defaultdict(list)

        for i in range(n):
            for j in range(n):
                if i != j:
                    dist = abs(points[i][0]-points[j][0]) + \\
                        abs(points[i][1]-points[j][1])
                    graph[i].append((j, dist))

        def mst(graph):
            total = 0
            seen = set()
            start = next(iter(graph))
            unseen = [(0, start)]
            while unseen:
                cost, node = heappop(unseen)
                if node not in seen:
                    seen.add(node)
                    total += cost
                    for nei, cost in graph[node]:
                        if nei not in seen:
                            heappush(unseen, (cost, nei))
            return total

        return mst(graph)

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        graph = defaultdict(list)
        start = 0
        for src in range(N):
            for dst in range(N):
                wt = abs(points[src][0]-points[dst][0]) + abs(points[src][1]-points[dst][1])
                graph[src].append((dst, wt))
                #graph[dst].append((src, wt))
         
        dist = {}
        heap = [(0, start)]
        while heap:
            ddist, node = heapq.heappop(heap)
            if node in dist:
                continue        
            dist[node] = ddist
            for neighbor, d in graph[node]:
                if neighbor not in dist:
                    heapq.heappush (heap, (d, neighbor))
                    
        return sum(dist.values())

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        manhattan = lambda x, y: abs(x[0] - y[0]) + abs(x[1] - y[1])
        res, length, heap, visited = 0, len(points), [(0, 0)], set()
        while len(visited) < length:
            w, u = heapq.heappop(heap)
            if u not in visited:
                res += w
                visited.add(u)
                for v in range(length):
                    if v not in visited:
                        heapq.heappush(heap, (manhattan(points[u], points[v]), v))
        return res

class Solution:
    def find(self, pt):
        if pt == self.roots[pt]:
            return pt
        self.roots[pt] = self.find(self.roots[pt])
        return self.roots[pt]
    
    def union(self, p1, p2):
        parent1, parent2 = self.find(p1), self.find(p2)
        if parent1 == parent2:
            return False
        if self.rank[parent2] < self.rank[parent1]:
            parent1, parent2 = parent2, parent1
            p1, p2 = p2, p1
        if self.rank[parent1] == self.rank[parent2]:
            self.rank[parent2] += 1
        self.roots[parent1] = parent2
        # self.find(p1)
        # self.find(p2)
        return True
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        self.roots = {(x, y): (x, y) for (x, y) in points}
        self.rank = {(x, y): 0 for (x, y) in points}
        ans = 0
        edges = []
        for i in range(len(points)):
            p1 = points[i][0], points[i][1]
            for j in range(i+1, len(points)):
                p2 = points[j][0], points[j][1]
                # if p1 != p2:
                dist = abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
                edges.append((dist, p1, p2))
        edges.sort()
        for dist, p1, p2 in edges:
            if self.union(p1, p2):
                ans += dist
        return ans
        
        # for i in range(len(points)):
        #     x1, y1 = points[i]
        #     best = (float('inf'), (x1, y1))
        #     for j in range(len(points)):
        #         if i == j:
        #             continue
        #         x2, y2 = points[j]
        #         dist = abs(x1-x2) + abs(y1-y2)
        #         best = min(best, (dist, (x2, y2)))
        #     p1 = x1, y1
        #     dist, p2 = best
        #     if self.union(p1, p2):
        #         print(\"connecting {}, {} distance {}\".format(p1, p2, dist))
        #         ans += dist
        # return ans


import heapq

class DSU:
    def __init__(self, n):
        self.roots = [i for i in range(n)]
    def find(self, x):
        if self.roots[x] != x:
            self.roots[x] = self.find(self.roots[x])
        return self.roots[x]
    def union(self, x, y):
        self.roots[self.find(x)] = self.find(y)
        
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        # minimum spanning tree
        
        n = len(points)
        if n == 1:
            return 0
        
        heap = []
        
        for i in range(n-1):
            for j in range(i+1, n):
                ax, ay = points[i]
                bx, by = points[j]
                heapq.heappush(heap, [abs(ax-bx) + abs(ay-by), i, j])
        #print(heap)
        count = 0
        dsu = DSU(n)
        while heapq:
            
            dist, i, j = heapq.heappop(heap)
            
            if dsu.find(i) != dsu.find(j):
                #print(dist, i, j)
                count += dist
                dsu.union(i, j)
            for i in range(n):
                dsu.find(i)
            if len(set(dsu.roots)) == 1:
                break
        
        return count

class Solution:
    
    def d(self,p1,p2):
        return abs(p1[0]-p2[0])+abs(p1[1]-p2[1])
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
      
        f = [[x] for x in points]
        c = [float('inf') for x in points]
        g = [-1 for x in points]
        
        r = []
        
        while len(f)>1:
            i = 0
            c = [float('inf') for x in f]
            
            while i<len(f):
                dx = -1
                j = 0
                while j<len(f):
                    if i!=j:
                        for x in f[i]:
                            for y in f[j]:
                                val = self.d(x,y)
                                if val<c[i]:
                                    c[i]=val
                                    g[i]=i
                                    dx = j
                            
                                
                    j+=1
                if dx!=-1:
                    
                    r.append(c[i])
                    f[i]+=f[dx]
                    del f[dx]
                    del c[dx]
                    del g[dx]
                
                    i-=1
                
                i+=1
        
        return sum(r)


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        dis = [[0] * N for _ in range(N)]
        for i in range(N):
            for j in range(N):
                if i == j: continue
                dis[i][j] = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
        vis = [False] * N
        heap = [(0, 0)]
        res = 0
        while heap:
            weight, node = heapq.heappop(heap)
            if vis[node]: continue
            vis[node] = True
            res += weight
            for i in range(N):
                if vis[i]: continue
                heapq.heappush(heap, (dis[node][i], i))
        return res


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n=len(points)
        def find(x):
            if par[x]==x:
                return x
            par[x]=find(par[x])
            return par[x]
        def union(x,y):
            a,b=find(x),find(y)
            
            if a==b:
                return False
            par[a]=b
            return True
        edges=[]
        for i in range(n):
            for j in range(i+1,n):
                edges.append([abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1]),i,j])
        edges.sort()
       
        par=[i for i in range(n)]
        ans=0
        for i in edges:
            d,u,v=i[0],i[1],i[2]
            if union(u,v):
                ans+=d
           
        return ans

from heapq import *
class Solution:
    def minCostConnectPoints(self, points):
        N = len(points)
        parent = [i for i in range(N)]
        def find(v):
            while parent[v] != parent[parent[v]]:
                parent[v] = parent[parent[v]]
            return parent[v]
        dist = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        heap, total_cost = [], 0
        for u in range(N-1):
            for v in range(u+1, N):
                heappush(heap, [dist(points[u], points[v]), u, v])
        while heap:
            cost, u, v = heappop(heap)
            pu, pv = find(u), find(v)
            if pu != pv:
                parent[pu] = pv
                N -= 1
                total_cost += cost
                if N == 0:
                    break
        return total_cost

    
    
    
    
    
    
    
    
from heapq import *
class Solution:
    def minCostConnectPoints(self, points):
        dist = lambda p1, p2: abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        N = len(points)
        parent = [i for i in range(N)]
        def find(v):
            while parent[v] != parent[parent[v]]:
                parent[v] = parent[parent[v]]
            return parent[v]
        heap = []
        for i in range(N-1):
            for j in range(i+1, N):
                heappush(heap, (dist(points[i], points[j]), i, j))
        res = 0
        while heap:
            d, u, v = heappop(heap)
            pu, pv = find(u), find(v)
            if pu != pv:
                parent[pu] = pv
                res += d
                N -= 1
                if N == 0:
                    break
        return res
            
                
 
    


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        #prims
        g = defaultdict(list)
        n = len(points)
        for i in range(n):
            for j in range(n):
                if i != j:
                    g[i].append((abs(points[j][0]-points[i][0])+abs(points[j][1]-points[i][1]), j))
        # print(g)
        heap = [(0,0)]
        ans = 0
        visited = set()
        while heap:
            weight, to = heapq.heappop(heap)
            if to in visited:
                continue
            ans += weight
            visited.add(to)
            
            for cost, nei in g[to]:
                if nei not in visited:
                    heapq.heappush(heap, (cost, nei))
            
        

        
        return ans
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        hp, uf = [], UF(len(points))
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                p1, p2 = points[i], points[j]
                weight = abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
                heapq.heappush(hp, (weight, i, j))
        res = 0
        while hp:
            weight, a, b = heapq.heappop(hp)
            if uf.find(a) != uf.find(b):
                uf.union(a, b)
                res += weight
        return res
    
class UF:
    def __init__(self, n):
        self.uf = list(range(n))
        self.sz = [1] * n
        self.root_cnt = n
    
    def find(self, c):
        root = c
        while root != self.uf[root]:
            root = self.uf[root]
        while self.uf[c] != root:
            p = self.uf[c]
            self.uf[c] = root
            c = p
        return root
    
    def union(self, a, b):
        ra, rb = self.find(a), self.find(b)
        if ra == rb: return False
        if self.sz[ra] < self.sz[rb]:
            self.uf[ra] = rb
            self.sz[rb] += self.sz[ra]
        else:
            self.uf[rb] = ra
            self.sz[ra] += self.sz[rb]
        self.root_cnt -= 1
        return True

class Solution:
  def minCostConnectPoints(self, points: List[List[int]]) -> int:
    def manhattan(p1,p2):
      x1,y1 = p1
      x2,y2 = p2
      return abs(x1-x2) + abs(y1-y2)
         
    s = len(points)
    components = [i for i in range(s)]
    costs = [(manhattan(points[j],points[i]),j,i) for i in range(s) for j in range(s)]
    costs = sorted(costs, key=lambda x: x[0])
    
    totalCost = 0
    for c, p1, p2 in costs:
      if p1 != p2:
        if not self.find(p1,p2, components):
          self.union(p1,p2, components)
          totalCost += c
    
    return totalCost
  
  def root(self, a, roots):
    while(roots[a] != a):
      roots[a] = roots[roots[a]]
      a = roots[a]
    return a
  
  def find(self, a,b, roots):
    return self.root(a,roots) == self.root(b, roots)
  
  def union(self, a,b, roots):
    ra = self.root(a, roots)
    rb = self.root(b, roots)
    
    roots[rb] = ra

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        res = 0
        dis = [math.inf] * n
        curr = 0
        explored = set()
        for _ in range(n - 1):
            x0, y0 = points[curr]
            explored.add(curr)
            for i, (x, y) in enumerate(points):
                if i in explored : continue
                dis[i] = min(dis[i], abs(x - x0) + abs(y - y0))
            delta, curr = min( (d, idx) for idx, d in enumerate(dis))
            res += delta
            dis[curr] = math.inf
        return res


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        total = 0
        edges = []
        N = len(points)
        parent = [x for x in range(N)]
        
        def ufind(x):
            if parent[x] != x:
                return ufind(parent[x])
            return x
            
        def uunion(x, y):
            ux = ufind(x)
            uy = ufind(y)
            
            parent[uy] = ux
            
        def dist(xi, yi, xj, yj):
            return abs(xi-xj) + abs(yi-yj)
        
        for i in range(N):
            xi, yi = points[i]
            for j in range(i+1, N):
                xj, yj = points[j]
                edges.append((dist(xi, yi, xj, yj), i, j))
                
        edges.sort()
        
        for edge, i, j in edges:
            if ufind(i) != ufind(j):
                uunion(i, j)
                total += edge
        
        return total

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def find(e1):
            if a[e1]==-1:
                return e1
            return find(a[e1])
            
        n=len(points)
        a=[-1]*n
        def dist(i,j):
            return abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
        temp=[]
        for i in range(n):
            for j in range(i+1,n):
                temp.append((dist(i,j),i,j))
        temp.sort()
        #print(temp)
        ans=0
        for d,x,y in temp:
            u1,u2=find(x),find(y)
            if u1!=u2:
                a[u2]=u1
                ans+=d
                #print(d,x,y)
        return ans
            
        
        
        


import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def dis(s, e):
            return abs(s[0] - e[0]) + abs(s[1] - e[1])
        
        def find(u):
            if root[u] != u:
                root[u] = find(root[u])
            return root[u]
        
        def union(u, v):
            ru, rv = find(u), find(v)
            if ru == rv:
                return False
            if rank[ru] < rank[rv]:
                root[ru] = rv
                rank[rv] = rank[ru] + rank[rv]
            else:
                root[rv] = ru
                rank[ru] = rank[ru] + rank[rv]
            return True
        
        n = len(points)
        res = 0
        queue = []
        root = [i for i in range(n)]
        rank = [1] * n
        for i in range(n):
            s = points[i]
            for j in range(i+1, n):
                e = points[j]
                heapq.heappush(queue, (dis(s, e), i, j))
        while queue:
            dis, s, e = heapq.heappop(queue)
            if union(s, e):
                res += dis
        return res


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        min_cost = 0
        msp = set()
        distances = self.compute_all_distances(points)
        groups = defaultdict(set)
        for i in range(len(points)):
            groups[i].add(i)
            
        #print(distances)
        while distances:
            #print(groups)
            next_min = heapq.heappop(distances)
            #print(f\"considering dist: {next_min}\")
            g1 = self.find_group(groups, next_min[1])
            g2 = self.find_group(groups, next_min[2])
            if g1 != g2:
                min_cost += next_min[0]
                groups[g1] = groups[g1] | groups[g2]
                del groups[g2]
        return min_cost
    
    def find_group(self, groups: dict, i: int) -> int:
        for group in groups:
            if i in groups[group]: return group
        return 0
    
    def compute_all_distances(self, points: List[List[int]]) -> List[int]:
        distances = list()
        for i in range(len(points)-1):
            p1 = points[i]
            for j in range(i+1, len(points)):
                p2 = points[j]
                d = self.dist(p1, p2)
                distances.append((d, i, j))
        heapq.heapify(distances)
        return distances
    
    def dist(self, p1: List[int], p2: List[int]) -> int:
        return abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])        

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        ll = len(points)
        if ll == 1:
            return 0
        distances = []
        def get_distance(i, j):
            return abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
        
        for i in range(ll):
            for j in range(i + 1, ll):
                distances.append((get_distance(i, j), i, j))
        distances.sort()
        parents = list(range(len(points)))
    
        def ufind(x):
            if parents[x] != x:
                return ufind(parents[x])
            return x
        
        def uunion(x, y):
            ux = ufind(x)
            uy = ufind(y)
            parents[uy] = ux
        res = 0
        for d, x, y in distances:
            ux = ufind(x)
            uy = ufind(y)
            if ux != uy:
                uunion(ux, uy)
                res += d
        return res
                
        


class UnionFind:
    def __init__(self, n):
        self.parent = list(range(n))
        
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        if px == py:
            return False
        
        self.parent[px] = py
        return True


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n, res, pq = len(points), 0, list()
        for i in range(n):
            for j in range(i + 1, n):
                d = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                heapq.heappush(pq, (d, i, j))
                
        uf = UnionFind(n)
        while pq:
            d, i, j = heapq.heappop(pq)
            if uf.union(i, j):
                res += d
        return res

class DSU:
    
    def __init__(self, N):
        self.parents = list(range(N))
        self.size = [1] * N
    
    def __find(self, x):
        if self.parents[x] != x:
            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 False
    
        if self.size[x] < self.size[y]:
            x, y = y, x
        
        self.parents[y] = x
        self.size[x] += self.size[y]
    
        return True

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # minimum spanning tree.
        edges = []
        
        def kruskals(N, edges):
            cost = 0
            dsu = DSU(N)
            for i,j, dist in edges:
                if dsu.union(i,j):
                    cost += dist
            
            return cost
        
        for i, (x,y) in enumerate(points):
            for j, (x1,y1) in enumerate(points):
                
                if i != j:
                    dist = abs(x1 - x) + abs(y1 - y)
                    edges.append([i, j, dist])
            
        edges.sort(key = lambda v : v[2])
    
        return kruskals(len(points), edges)

#Build weighted graph and then use Union-Find to get MST
import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N, g = len(points), []
        res = 0
        
        #build the weighted graph
        for i in range(N - 1):
            x0, y0 = points[i]
            for j in range(i + 1, N):                
                x1, y1 = points[j]
                dist = abs(x0 - x1) + abs(y0 - y1)
                g.append((dist, (i, j)))
                
        #Heap sort the array: O(|E|)
        heapq.heapify(g)
        
        #Union-Find to get MST
        parents = [None] * N
        for i in range(N): parents[i] = i
            
        def findParent(x):
            if parents[x] != x:
                parents[x] = findParent(parents[x])
            
            return parents[x]
        
        while g:
            w, (a, b) = heapq.heappop(g)
            pa = findParent(a)
            pb = findParent(b)
            
            #union sub-graphs if not connected yet
            if pa != pb:
                res += w
                parents[pa] = pb
        
        return res


class UnionFind:
    def __init__(self, n):
        self.p = list(range(n))
        
    def find(self, i):
        if self.p[i] != i:
            self.p[i] = self.find(self.p[i])
        return self.p[i]
    
    def union(self, x, y):
        rx, ry = self.find(x), self.find(y)
        self.p[rx] = ry

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) < 2:
            return 0
        hq = []
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                heapq.heappush(hq, (dist, i, j))
        connect = 0
        uf = UnionFind(len(points))
        cost = 0
        while connect != len(points) - 1 and hq:
            d, i, j = heapq.heappop(hq)
            ri, rj = uf.find(i), uf.find(j)
            if ri != rj:
                cost += d
                uf.union(i, j)
        return cost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if len(points) == 1: return 0
        res = 0
        curr = 0 # select a random point as the starting point
        dis = [math.inf] * n
        explored = set()
        
        for i in range(n - 1):
            x0, y0 = points[curr]
            explored.add(curr)
            for j, (x, y) in enumerate(points):
                if j in explored: continue
                dis[j] = min(dis[j], abs(x - x0) + abs(y - y0))
                
            delta, curr = min((d, j) for j, d in enumerate(dis)) 
            dis[curr] = math.inf
            res += delta
            
        return res    
    def minCostConnectPoints2(self, P: List[List[int]]) -> int:
        res=0
        n=len(P)
        px,py=P[0]
        seen={0}
        todo=set(range(1,n))
        while len(seen)<n:
            mn=float('inf')
            used=-1
            for i in todo:
                cx,cy=P[i]
                for j in seen:
                    px,py=P[j]
                    can=abs(cx-px)+abs(cy-py)
                    if can <mn:
                        mn=can
                        used=i
            res+=mn
            todo.remove(used)
            seen.add(used)
        return res

    # def minCostConnectPoints1(self, P: List[List[int]]) -> int:
    #     P.sort(key=lambda a:(abs(a[0])+abs(a[1])))
    #     print(P)
    #     res=0
    #     px,py=P[0]
    #     for cx,cy in P[1:]:
    #         res+=abs(cx-px)+abs(cy-py)
    #         px,py=cx,cy
    #     return res    


import heapq

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        dic = {}
        for i in range(len(points)):
            val = []
            for j in range(len(points)):
                if points[j] != points[i]:
                    val = (abs(points[j][0]-points[i][0]) + abs(points[j][1] - points[i][1]))   
                    dic[i,j] = val
        #print(dic)
        g = Graph(len(points))
        for k,v in dic.items():
            g.addEdge(k[0],k[1],v)
        
        #g.printAll()
        res = g.Prims()
        #print(res)
        return res
        
class Graph:
    def __init__(self, N):
        self.V = N
        self.adj = [[] for i in range(self.V)]
        
    def addEdge(self, u,v,w):
        self.adj[u].append([v,w])
        
    def printAll(self):
        for i in range(self.V):
            print(i, self.adj[i])
            
    def Prims(self):
        pq = [(0,0)]
        visited = [False for i in range(self.V)]
        cost = 0
        #print(pq)
        while len(pq) != 0:
            cur_cost, cur_node = heapq.heappop(pq)
            #print(cur_cost, cur_node)
            if visited[cur_node]:
                continue
            visited[cur_node] = True
            cost += cur_cost
            
            for neighbor_node, w in self.adj[cur_node]:
                if not visited[neighbor_node]:
                    heapq.heappush(pq, (w, neighbor_node))
                    
        return -1 if sum(visited) != self.V else cost
            
\"\"\"
class Graph:
    def __init__(self, vertices):
        self.v = vertices
        self.graph = []
        
    def addEdge(self, u, v, w):
        self.graph.append([u,v,w])
        
    def find(self,parent, i):
        if parent[i] == -1:
            return i
        return self.find(parent, parent[i])
    
    def union(self, parent, x, y):
        x_set = self.find(parent, x)
        y_set = self.find(parent, y)
        parent[x_set] = y_set
        
    def KruskalMST(self):
        MST = []
        i = 0
        e = 0
        self.graph = sorted(self.graph, key = lambda e:e[2])
        parent = [-1] * self.v
        while e < self.v -1:
            u,v,w = self.graph[i]
            i += 1
            x = self.find(parent,u)
            y = self.find(parent, v)
            #print(x,y)
            if x!= y:
                e += 1
                MST.append([u,v,w])
                self.union(parent,x,y)
                #print(MST)
        s = 0
        for u,v,w in MST:
            s += w
        return s
\"\"\"
        

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        dists = []
        n = len(points)
        for i in range(n - 1):
            x1, y1 = points[i]
            for j in range(i + 1, n):
                x2, y2 = points[j]
                dists.append((abs(x1 - x2) + abs(y1 - y2), i, j))
        
        roots = [-1] * n
        def find(p1):
            while roots[p1] >= 0:
                p1 = roots[p1]
            return p1
        
        def union(r1, r2):
            if roots[r1] < roots[r2]:
                roots[r1] += roots[r2]
                roots[r2] = r1
            else:
                roots[r2] += roots[r1]
                roots[r1] = r2
                
        #print(roots)
        #union(0, 3)
        #print(roots)
        
        res = 0
        heapq.heapify(dists)
        while dists:
            dist, p1, p2 = heapq.heappop(dists)
            r1 = find(p1)
            r2 = find(p2)
            if r1 != r2:
                union(r1, r2)
                res += dist
        
        return res
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        total = 0
        edges = []
        N = len(points)
        parent = [x for x in range(N)]
        rank = [1 for x in range(N)]
        
        def ufind(x):
            if parent[x] == x:
                return parent[x]
            return ufind(parent[x])
            
        def uunion(x, y):
            ux = ufind(x)
            uy = ufind(y)
            if rank[ux] > rank[uy]:
                parent[uy] = ux
                rank[ux] += rank[uy]
            else:
                parent[ux] = uy
                rank[uy] += rank[ux]
            
        def dist(xi, yi, xj, yj):
            return abs(xi-xj) + abs(yi-yj)
        
        for i in range(N):
            xi, yi = points[i]
            for j in range(i+1, N):
                xj, yj = points[j]
                edges.append((dist(xi, yi, xj, yj), i, j))
                
        heapq.heapify(edges)
        
        for v in range(len(edges)):
            edge, i, j = heapq.heappop(edges)
            if ufind(i) != ufind(j):
                uunion(i, j)
                total += edge
        # for edge, i, j in edges:
        #     if ufind(i) != ufind(j):
        #         uunion(i, j)
        #         total += edge
        
        return total

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        d = {}
        min_heap = []
        n = len(points)
        for i in range(n):
            for j in range(i + 1, n):
                x1, y1 = points[i][0], points[i][1]
                x2, y2 = points[j][0], points[j][1]
                dist = abs(x1 - x2) + abs(y1 - y2)
                d[(x1, y1)] = (x1, y1)
                d[(x2, y2)] = (x2, y2)
                heapq.heappush(min_heap, (dist, (x1, y1), (x2, y2)))
        
        def find(x):
            px = d[x]
            if px != x:
                d[x] = find(px)
            return d[x] 
        
        def union(x, y):
            px, py = find(x), find(y)
            if px != py:
                d[px] = py
                
        min_cost = 0
        while min_heap:
            c, p1, p2 = heapq.heappop(min_heap)
            pa1, pa2 = find(p1), find(p2)
            if pa1 != pa2:
                union(p1, p2)
                min_cost += c
        return min_cost


from queue import PriorityQueue
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        q = []
        N = len(points)
        
        for i in range(N):
            for j in range(i+1, N):
                a,b = points[i]
                c,d = points[j]
                dist = abs(a-c) + abs(b-d)
                q.append((dist, i, j))
        
        heapify(q)
        ans = 0
        par = list(range(N))
        rank = [0] * N
        
        def find_parent(a):
            if par[a] == a:
                return a
            par[a] = find_parent(par[a])
            return par[a]
        
        def join(a, b):
            pa, pb = find_parent(a), find_parent(b)
            if pa == pb:
                return 0
            # Attach smaller rank tree under root of  
            # high rank tree (Union by Rank) 
            if rank[pa] < rank[pb]: 
                par[pa] = pb
            elif rank[pa] > rank[pb]: 
                par[pb] = pa 
            # If ranks are same, then make one as root  
            # and increment its rank by one 
            else : 
                par[pb] = pa
                rank[pa] += 1
            return 1
        
        while q:
            dist, i, j = heappop(q)
            if join(i, j):
                ans += dist
        
        return ans

class DSU:
    
    def __init__(self, n):
        self.parents = [i for i in range(n)]
        self.sizes = [1] * n
        
    def find(self, x):
        p = self.parents[x]
        if p == x: return x
        self.parents[x] = self.find(p)
        return self.parents[x]
    
    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        if px == py: return False
        sx, sy = self.sizes[px], self.sizes[py]
        if sy > sx: px, py = py, px
        self.parents[py] = px
        self.sizes[px] = sx + sy
        return True

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        for i1, p1 in enumerate(points):
            for i2 in range(i1+1, len(points)):
                p2 = points[i2]
                d = abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
                edges.append([d, i1, i2])
                
        edges.sort()
        
        dsu = DSU(len(points))
        
        t = 0
        for c, i1, i2 in edges:
            if dsu.union(i1, i2):
                t += c
                
        return t
            


class UnionFind:
    def __init__(self, size):
        self.parent = [i for i in range(size)]
        self.rank = [1] * size
    
    def find(self, x):
        if x != self.parent[x]:
            self.parent[x] = self.find(self.parent[x])
        
        return self.parent[x]
    
    def union(self, x, y):
        p_x, p_y = self.find(x), self.find(y)
        
        if p_x == p_y:
            return 
        
        if self.rank[p_x] < self.rank[p_y]:
            self.parent[p_x] = p_y
            self.rank[p_y] += self.rank[p_x]
        else:
            self.parent[p_y] = p_x
            self.rank[p_x] += self.rank[p_y]
        
        
        
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # build graph by using edge list (x, y, weight)
        n = len(points)
        
        edge_list = []
        for i in range(n):
            for j in range(n):
                if i != j:
                    edge_list.append([i, j, self.dist(points[i], points[j])])
        
        # find the final result: each time select the edge with minimun weight, and vertices come from different component, merge the component, add the cost
        uf = UnionFind(n)
        cost = 0
        edge_list.sort(key = lambda x : x[2])
        
        for u, v, w in edge_list:
            p_u, p_v = uf.find(u), uf.find(v)
            
            if p_u == p_v:
                continue
            
            uf.union(u, v)
            cost += w
        
        return cost
    
    def dist(self, point1, point2):
        return abs(point1[0] - point2[0]) + abs(point1[1] - point2[1])
                


import heapq

class UnionFind:
    \"\"\"
    Class that implements the union-find structure with
    union by rank and find with path compression
    \"\"\"
     
    def __init__(self, n):
        self.parent = list(range(n))
        self.rank = [0 for x in range(n)]
 
    def find(self, v):
        if not v == self.parent[v]:
            self.parent[v] = self.find(self.parent[v])
        return self.parent[v]
 
    def union(self, x, y):
        xRoot = self.find(x)
        yRoot = self.find(y)
        if xRoot == yRoot:
            return
        if self.rank[xRoot] > self.rank[yRoot]:
            self.parent[yRoot] = xRoot
        else:
            self.parent[xRoot] = yRoot
            if self.rank[xRoot] == self.rank[yRoot]:
                self.rank[yRoot] += 1
                
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        mat = [[0] * len(points) for _ in range(len(points))]
        heap = []
        union_find = UnionFind(len(points))
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                mat[i][j] = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                heapq.heappush(heap, (mat[i][j], i, j))
        
        total_cost = 0
        while heap:
            dist, a, b = heapq.heappop(heap)
            
            # if a, b not in same group:
            if union_find.find(a) != union_find.find(b):
                union_find.union(a, b)
                total_cost += dist
            
        return total_cost

#Build weighted graph and then use Union-Find to get MST
import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N, g = len(points), []
        res = 0
        
        #build the weighted graph
        for i in range(N - 1):
            x0, y0 = points[i]
            for j in range(i + 1, N):                
                x1, y1 = points[j]
                dist = abs(x0 - x1) + abs(y0 - y1)
                g.append((dist, (i, j)))
                
        #Heap sort the array: O(|E|)
        heapq.heapify(g)
        
        #Union-Find to get MST
        parents = [None] * N
        for i in range(N): parents[i] = i
            
        def findParent(x):
            if parents[x] != x:
                parents[x] = findParent(parents[x])
            
            return parents[x]
        
        used_edges = 0
        while used_edges < N - 1 and g:
            w, (a, b) = heapq.heappop(g)
            pa = findParent(a)
            pb = findParent(b)
            
            #union sub-graphs if not connected yet
            if pa != pb:
                res += w
                parents[pa] = pb
                used_edges += 1
        
        return res


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        graph = defaultdict(list)
        visited = set()
        res = 0
        for idx1, point1 in enumerate(points):
            for idx2, point2 in enumerate(points):
                if idx1 != idx2:
                    man = abs(point1[0]-point2[0]) + abs(point1[1]-point2[1])
                    graph[idx1].append((man,idx2))
                    graph[idx2].append((man,idx1))
        con = set([0])
        heap = graph[0][:]
        heapify(heap)
        while len(con) != len(points):
            while heap:
                cur = heappop(heap)
                if cur[1] not in con:
                    for neig in graph[cur[1]]:
                        heappush(heap, neig)
                    con.add(cur[1])
                    res += cur[0]
                    break
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        p = [0]*len(points)
        for i in range(len(points)):
            p[i] = i
        pq = []
        for i in range(len(points)-1):
            for j in range(i+1, len(points)):
                dis = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                heapq.heappush(pq, [dis, i, j])
        def find(x):
            if p[x] != x:
                p[x] = find(p[x])
            return p[x]
        def union(x, y):
            if x > y:
                x, y = y, x
            p[y] = x
        
        res = 0
        while len(pq) > 0:
            dis, i, j = heapq.heappop(pq)
            if find(i) == find(j):
                continue
            res += dis
            union(find(i), find(j))
        return res


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        parents = [i for i in range(n)]
        groups = n
        def find(x):
            if parents[x] != x:
                parents[x] = find(parents[x])
            return parents[x]
        
#         def merge(x, y):
            
#             rx, ry = find(x), find(y)
#             if rx != ry:
#                 groups -= 1
#                 parents[rx] = ry
        
        distance = 0
        heap = []
        for i in range(n):
            for j in range(i):
                heapq.heappush(heap, (abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]), i, j))
        
        while heap or groups > 1:
            dist, i, j = heapq.heappop(heap)
            ri, rj = find(i), find(j)
            if ri != rj:
                groups -= 1
                parents[ri] = rj
                distance += dist
        return distance
            
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        graph = []
        self.parent = [i for i in range(len(points))]
        cost = 0
        
        for i in range(len(points)-1):
            for j in range(len(points)):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                graph.append([i, j, dist])
                
        graph = sorted(graph, key = lambda x: x[2])
        
        for u, v, c in graph:
            if self.union(u, v):
                cost += c
                
        return cost
    
    
    def union(self, x, y):
        parentX = self.find(x)
        parentY = self.find(y)
        
        if parentX == parentY:
            return False
        
        if self.parent[parentX] <= self.parent[parentY]:
            self.parent[parentY] = parentX
        else:
            self.parent[parentX] = parentY
            
        return True
    
    
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
            
        return self.parent[x]


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        graph = collections.defaultdict(list)
        
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                dist = abs(points[j][1]-points[i][1]) + abs(points[j][0] - points[i][0])
                
                graph[i].append((j, dist))
                graph[j].append((i, dist))
        #print(graph)
        dist = {}
\t\t# Using heap to find min wt
        heap = [(0, 0)]
        while heap:
            ddist, node = heapq.heappop(heap)
            if node in dist:
                continue
            dist[node] = ddist
            for neighbor, d in graph[node]:
                if neighbor not in dist:
                    heapq.heappush (heap, (d, neighbor))
        return sum(dist.values())

from heapq import heappush, heappop

class UnionFind:
    def __init__(self, n):
        self.group = list(range(n))
        self.size = [0] * n
    
    def find(self, i):
        if i == self.group[i]:
            return i
        p = self.find(self.group[i])
        self.group[i] = p
        return p
    
    def union(self, i, j):
        i = self.find(i)
        j = self.find(j)
        if self.size[i] <= self.size[j]:
            self.group[i] = j
            self.size[j] += self.size[i]
        else:
            self.group[j] = i
            self.size[i] += self.size[j]

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # minuim spining tree
        weights = []
        for i in range(len(points) - 1):
            for j in range(i + 1, len(points)):
                weight = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                heappush(weights, (weight, i,j))
                
                
        # print(weights)
        uf = UnionFind(len(points))
        res = 0
        
        while weights:
            min_edge, i, j = heappop(weights)
            if uf.find(i) == uf.find(j):
                continue
            uf.union(i, j)
            res += min_edge
                
        return res
            
            
        
      

            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def cal(p1, p2):
            return abs(p1[0]-p2[0])+abs(p1[1]-p2[1])
        d, q = {}, [[0, 0]]
        ans = 0
        while q:
            dis, a = heapq.heappop(q)
            if a not in d:
                d[a] = dis
                ans += dis
                for b in range(len(points)):
                    if b not in d:
                        heapq.heappush(q, [cal(points[a], points[b]), b])
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        parent = collections.defaultdict(int)

        def find(p):
            if parent[p] == 0:
                return p
            return find(parent[p])

        def union(p1, p2):
            if p1 != p2:
                if p1 < p2:
                    parent[p2] = p1
                else:
                    parent[p1] = p2

        V = points
        E = []
        for p1 in V:
            for p2 in V:
                if p1 != p2:
                    E.append((tuple(p1),tuple(p2)))
        W = {}
        for edge in E:
            W[edge] = abs(edge[0][0]-edge[1][0]) + abs(edge[0][1]-edge[1][1])
        sorted_W = {k: v for k, v in sorted(W.items(), key=lambda item: item[1])}
    
        count = 0
        cost = 0
        for e in sorted_W:
            x, y = e[0], e[1]
            x_set, y_set = find(x), find(y)
            if x_set != y_set:
                union(x_set, y_set)
                count += 1
                cost += sorted_W[e]
            if count ==  len(V) - 1:
                break
        return cost

class Solution:
    
    def calculateDistance(self, point1, point2):
        return abs(point1[0]-point2[0]) + abs(point1[1]-point2[1])
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        queue = []
        queueSet = [0]*len(points)
        setDict = {}
        for i in range(len(points)):
            for j in range(i+1,len(points)): 
                heappush(queue, (self.calculateDistance(points[i],points[j]),points[i],points[j]))
            queueSet[i]=[tuple(points[i])]
            setDict[tuple(points[i])] = i
        totalCost = 0
        while queue:
            p = heappop(queue)
            t1 = tuple(p[1])
            t2 = tuple(p[2])
            if setDict[t1]!=setDict[t2]:
                totalCost = totalCost + p[0]
                if setDict[t1]<setDict[t2]:
                    queueSet[setDict[t1]].extend(queueSet[setDict[t2]])
                    for ch in queueSet[setDict[t2]]:
                        setDict[ch] = setDict[t1]
                    setDict[t2] = setDict[t1]
                else:
                    queueSet[setDict[t2]].extend(queueSet[setDict[t1]])
                    for ch in queueSet[setDict[t1]]:
                        setDict[ch] = setDict[t2]
                    
                    setDict[t1] = setDict[t2]
    
        return totalCost
        
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        graph = []
        self.parent = [i for i in range(len(points))]
        cost = 0
        self.N = len(points)
        
        for i in range(len(points)-1):
            for j in range(len(points)):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                graph.append([i, j, dist])
                
        graph = sorted(graph, key = lambda x: x[2])
        
        for u, v, c in graph:
            if self.union(u, v):
                cost += c
            if self.N == 0:
                break
                
        return cost
    
    
    def union(self, x, y):
        parentX = self.find(x)
        parentY = self.find(y)
        
        if parentX == parentY:
            return False
        
        if self.parent[parentX] <= self.parent[parentY]:
            self.parent[parentY] = parentX
        else:
            self.parent[parentX] = parentY
        self.N -= 1
        return True
    
    
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
            
        return self.parent[x]

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) == 1: return 0
        
        res = 0
        n = len(points)
        visited = set([0])
        cur = 0
        dist = [float('inf')] * n
        
        for _ in range(n-1):
            x, y = points[cur]
            for j, (u, v) in enumerate(points):
                if j in visited: continue
                dist[j] = min(dist[j], abs(x - u) + abs(y - v))

            d, cur = min([(d, j) for j, d in enumerate(dist)])
            dist[cur] = float('inf')
            res += d
            visited.add(cur)

        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        visited = [False] * len(points)
        distance = [[0]*len(points) for p in points]
        queue = [(0,0)] # cost, point_index
        for i in range(len(points)):
            for j in range(len(points)):
                distance[i][j] = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])

        res = 0
        while queue:
            cost, point = heapq.heappop(queue)
            if visited[point] == True: continue
            visited[point] = True
            res += cost
            for i in range(len(points)):
                if not visited[i]:
                    heapq.heappush(queue, (distance[point][i], i))
        
        return res           
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        parent = {}
        size = defaultdict(lambda: 1)

        def find(u):
            if u != parent.get(u, u):
                parent[u] = find(parent[u])  # path compression
            return parent.get(u, u)

        def union(u, v):
            u, v = find(u), find(v)
            if u != v:
                if size[u] < size[v]:  # union by size / rank
                    u, v = v, u

                parent[u] = v
                size[u] += size[v]

        total = 0
        edges = []
        for i in range(len(points)):
            for j in range(len(points)):
                if i!=j:
                    edges.append((abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1]),i,j))
        edges.sort()

        for cost, u, v in edges:
            if find(u) != find(v):
                total += cost
                union(u, v)

        return total
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def calculate_distance(x1, y1, x2, y2):
            return abs(x1 - x2) + abs(y1 - y2)

        res = 0
        n = len(points)
        visited = set()
        d = defaultdict(list)

        for i in range(n):
            for j in range(n):
                if i != j:
                    d[i].append((calculate_distance(points[i][0], points[i][1], points[j][0], points[j][1]), j))
                    d[j].append((calculate_distance(points[i][0], points[i][1], points[j][0], points[j][1]), i))

        heap = d[0]
        heapq.heapify(heap)
        visited.add(0)
        count = 1

        while heap and count < n:
            dist, j = heapq.heappop(heap)

            if j not in visited:
                visited.add(j)
                res += dist
                count += 1
                for r in d[j]:
                    heapq.heappush(heap, r)

        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if not points: return 0        
        
        n = len(points)
        dist = [[0] * n for _ in range(n)]
        for i in range(n):
            x1, y1 = points[i]
            for j in range(n):
                x2, y2 = points[j]
                dist[i][j] = abs(x1 - x2) + abs(y1 - y2)
                
        origin = 0
        q = []
        for j, d in enumerate(dist[0]):
            heapq.heappush(q, (d, j))
        
        ans = 0
        visited = set([0])
        while q:
            d, child = heapq.heappop(q)
            if child not in visited:
                ans += d
                visited.add(child)
                for j, n_d in enumerate(dist[child]):
                    if j not in visited:
                        heapq.heappush(q, (n_d, j))
        return ans
            
        
        
        
                


class Solution:
    def minCostConnectPoints(self,points: List[List[int]]) -> int:
        n = len(points)
        if n == 1:
            return 0
        costs = []
        for i in range(n):
            cost = [0] * n
            costs.append(cost)

        for i in range(n):
            ax = points[i][0]
            ay = points[i][1]
            for j in range(i + 1, n):
                bx = points[j][0]
                by = points[j][1]
                costs[i][j] = abs(ax - bx) + abs(ay - by)
                costs[j][i] = costs[i][j]
        conn = [-1] * n

        for i in range(n):
            for j in range(n):
                cs = costs[i][j]
                if cs != 0:
                    if conn[i] == -1:
                        conn[i] = j
                    else:
                        if cs < costs[i][conn[i]]:
                            conn[i] = j
        groups = []
        toset = list(range(n))
        conngroupcost = 0
        while len(toset) > 0:
            point = toset[0]
            g = [point]
            toset.remove(point)
            while conn[point] not in g:
                g.append(conn[point])
                conngroupcost+=costs[point][conn[point]]
                toset.remove(conn[point])
                point = conn[point]
            while len(toset) > 0:
                npoint = []
                for x in toset:
                    if conn[x] in g:
                        npoint.append(x)
                        g.append(x)
                        conngroupcost += costs[x][conn[x]]
                if len(npoint) == 0:
                    break
                else:
                    for np in npoint:
                        toset.remove(np)
            groups.append(g)

        while len(groups) > 1:
            minlen=-1
            minindex=-1
            for gi in range(len(groups)):
                if minlen==-1:
                    minlen=len(groups[gi])
                    minindex=gi
                else:
                    if len(groups[gi])<minlen:
                        minlen = len(groups[gi])
                        minindex = gi
            gps = groups[minindex]
            mincost = -1
            mincostp = -1
            for gp in gps:
                for i in range(n):
                    if i not in gps:
                        if mincost == -1:
                            mincost = costs[gp][i]
                            mincostp = i
                        else:
                            if mincost > costs[gp][i]:
                                mincost = costs[gp][i]
                                mincostp = i

            conngroupcost += mincost
            conngindex = -1
            for gindex in range(len(groups)):
                if mincostp in groups[gindex]:
                    conngindex = gindex
                    break
            groups[minindex] = groups[minindex] + groups[conngindex]
            del groups[conngindex]
        return conngroupcost
                    
        
        
                
                


from heapq import *
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        points = [tuple(point) for point in points]
        currPoint = points[0]
        vis = set()
        que = [[0, currPoint]]
        
        def getDist(a, b):
            return abs(a[0]-b[0])+abs(a[1]-b[1])
        ans = 0
        while que:
            dist, cpoint = heappop(que);
            if cpoint in vis:
                continue
            ans+=dist
            vis.add(cpoint)
            for point in points:
                if point not in vis:
                    newDist = getDist(cpoint, point)
                    heappush(que, [newDist, point])
        return ans
            
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n <=1: return 0
        minHeap = []
        for i in range(n):
            for j in range(i+1, n):
                x1, y1 = points[i]
                x2, y2 = points[j]
                dx, dy = abs(x1-x2), abs(y1-y2)
                heapq.heappush(minHeap,(dx+dy, i, j))
                
        #print(minHeap)
        
        uf = [i for i in range(n)]
        
        def find(x):
            if uf[x] == x:
                return x
            uf[x] = find(uf[x])
            return uf[x]
        
        res = 0 
        while minHeap:
            d, x, y = heapq.heappop(minHeap)
            px, py = find(x), find(y)
            if px == py:
                continue
            else:
                res += d
                uf[px] = py
        return res

import heapq

class UnionFind:
    def __init__(self, n):
        self.parent = {i: i for i in range(n)}
        self.rank = {i: 1 for i in range(n)}

    def add(self, x):
        self.parent[x] = x
        self.rank[x] = 0

    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]

    def union(self, x, y):
        xRoot, yRoot = self.find(x), self.find(y)

        if xRoot == yRoot:
            return

        xRank, yRank = self.rank[xRoot], self.rank[yRoot]
        
        # let yRoot be the one with smaller rank
        if xRank < yRank:
            yRoot, xRoot = xRoot, yRoot
            
        # small rank points to large rank
        self.parent[yRoot] = xRoot
        # large rank takes the small rank to count total #
        self.rank[xRoot] += self.rank[yRoot]
        

        return

class Solution:
    def dist(self, p1, p2):
        return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        dsu = UnionFind(len(points))
        edges = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                edges.append((self.dist(points[i], points[j]), i, j))
                
        
        heapq.heapify(edges)
        ans = 0
        while edges:
            d, u, v = heapq.heappop(edges)
            if dsu.find(u) != dsu.find(v):
                ans += d
                dsu.union(u, v)
        
        return ans
        


class Node:
    def __init__(self, parent, value):
        self.parent = parent
        self.rank = 0
        self.size = 1
        self.value = value

class UnionFind:
    def __init__(self, nodes):
        self.subsets = [Node(i, v) for i, v in enumerate(nodes)]
        self.maxSubsetSize = 1

    def union(self, i, j):
        irep = self.find(i)
        jrep = self.find(j)
        if irep == jrep:
            return
        # union by rank
        if self.subsets[irep].rank > self.subsets[jrep].rank:
            self.subsets[jrep].parent = irep
            self.subsets[irep].size += self.subsets[jrep].size
        elif self.subsets[jrep].rank > self.subsets[irep].rank:
            self.subsets[irep].parent = jrep
            self.subsets[jrep].size += self.subsets[irep].size
        else:
            self.subsets[irep].parent = jrep
            self.subsets[jrep].rank += 1
            self.subsets[jrep].size += self.subsets[irep].size
        self.maxSubsetSize = max(self.maxSubsetSize, max(self.subsets[irep].size, self.subsets[jrep].size))

    def find(self, i):
        if self.subsets[i].parent != i:
            # path compression
            self.subsets[i].parent = self.find(self.subsets[i].parent)
        return self.subsets[i].parent

from heapq import heapify, heappop
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        for i in range(len(points)):
            x1, y1 = points[i]
            for j in range(i+1, len(points), 1):
                x2, y2 = points[j]
                edges.append((abs(x1-x2)+abs(y1-y2), i, j))
        heapify(edges)
        uf = UnionFind(range(len(points)))
        total = 0
        while len(edges) > 0:
            d, i, j = heappop(edges)
            if uf.find(i) != uf.find(j):
                total += d
                uf.union(i, j)
        return total

from heapq import heappop, heappush, heapify 
from collections import defaultdict

def distance(pointA, pointB):
    
    return abs(pointA[0]-pointB[0]) + abs(pointA[1]-pointB[1])

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        n = len(points)
        
        mat = [[float('inf')] * n for i in range(n)]
        
        lookup = defaultdict(list)
        minHeap = []
        
        for idx, aPoint in enumerate(points):
            for bIdx in range(idx+1, n):
                bPoint = points[bIdx]
                
                dist = distance(aPoint, bPoint)
                
                minHeap.append(dist)
                
                lookup[dist].append([idx, bIdx])
                                
        if n == 1:
            return 0
        
        visited = set()
        cost = 0
        
        minHeap = sorted(minHeap)
        minValue = minHeap[0]
        minIndex = lookup[minValue][0]
        visited.add(minIndex[0])
        visited.add(minIndex[1])
        cost += minValue
        
        while len(visited) != n:
            for minValue in minHeap:
                minIndexs = lookup[minValue]
                ifFound = False
                                    
                for minIndex in minIndexs:
                    x = minIndex[0]
                    y = minIndex[1]
                    if x in visited and y in visited:
                        continue
                    elif x in visited or y in visited:
                        visited.add(x)
                        visited.add(y)
                        cost += minValue
                        ifFound = True
                        break
                if ifFound:
                    break
                
                        
        return cost
        
        
#         visited = set()
#         costs = []
#         minValue = float('inf')
#         minIndex = (0,0)
#         for i in range(n):
#             for j in range(n):
#                 if mat[i][j] < minValue:
#                     minValue = min(minValue, mat[i][j])
#                     minIndex = (i,j)
        
#         visited.add(minIndex[0])
#         visited.add(minIndex[1])
#         costs.append(minValue)
                
#         while len(visited) != n:
#             minValue = float('inf')
#             minIndex = (0,0)
#             for i in visited:
#                 for idx, value in enumerate(mat[i]):
#                     if value < minValue and idx not in visited:
#                         minValue = min(minValue, value)
#                         minIndex = (i, idx)
                                
#             visited.add(minIndex[0])
#             visited.add(minIndex[1])
#             costs.append(minValue)
#             mat[minIndex[0]][minIndex[1]] = float('inf')
#             mat[minIndex[1]][minIndex[0]] = float('inf')
         
#         return sum(costs)
        
            
        
        
        
        
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if len(points) == 1: return 0
        res = 0
        curr = 0 # select a random point as the starting point
        dis = [math.inf] * n
        explored = set()
        
        for i in range(n - 1):
            x0, y0 = points[curr]
            explored.add(curr)
            for j, (x, y) in enumerate(points):
                if j in explored: continue
                dis[j] = min(dis[j], abs(x - x0) + abs(y - y0))
                
            delta, curr = min((d, j) for j, d in enumerate(dis)) 
            dis[curr] = math.inf
            res += delta
            
        return res

from math import inf
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def dis(i,j):
            x1,y1,x2,y2=points[i][0],points[i][1],points[j][0],points[j][1]
            ans=abs(x1-x2)+abs(y1-y2)
            return ans
        
        n=len(points)
        connected=set()       
        connected.add(0)
        uncon=set()
        for i in range(1,n):
            uncon.add(i)
        
        edges={}
        for i in range(n):
            for j in range(n):
                if i!=j:
                    edges[(i,j)]=dis(i,j)
                    edges[(j,i)]=edges[(i,j)]
                    
        total=0
        dis=[inf for _ in range(n)]
        pt=0
        for _ in range(n-1):
            for i in uncon:
                dis[i]=min(edges[(i,pt)],dis[i])
            score,pt=min((score,i) for i,score in enumerate(dis))
            dis[pt]=inf
            total+=score
            connected.add(pt)
            uncon.remove(pt)
        
        return total
            





class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        graph = collections.defaultdict(list)
        n = len(points)
        for i in range(n):
            for j in range(n):
                if i != j:
                    graph[i].append((abs(points[j][0]-points[i][0])+abs(points[j][1]-points[i][1]), j))

        heap = [(0,0)]
        res = 0
        visited = set()
        while heap:
            weight, dest = heapq.heappop(heap)
            if dest in visited:
                continue
            res += weight
            visited.add(dest)

            for cost, nei in graph[dest]:
                if nei not in visited:
                    heapq.heappush(heap, (cost, nei))

        return res

    
    
    


class order(tuple):
    def __lt__(a,b):
        return a[0] < b[0]
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        adjList = {}
        edges,n,ans = [],len(points),0
        # add edges
        for i in range(n):
            for j in range(i+1,n):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((dist,i,j))
        
        parent = [i for i in range(n)]
        rank = [0 for i in range(n)]
        def find(x):
            if parent[x] != x:
                parent[x] = find(parent[x])
            return parent[x]
        
        def union(x,y):
            x,y = find(x),find(y)
            if rank[x] > rank[y]:
                parent[y] = x
            else:
                parent[x] = y
            
            if rank[x] == rank[y]:
                rank[x] += 1
            return
        edges = sorted(edges, key=order)
        for d,u,v in edges:
            x,y = find(u),find(v)
            if x != y:
                union(x,y)
                ans += d
        return ans


class UnionFind:
  def __init__(self):
    self.father = {}
    self.size = {}

  def find(self, p):
    while self.father[p] != p:
      self.father[p] = p = self.father[self.father[p]]
    return p

  def union(self, p, q):
    self.insert(p)
    self.insert(q)

    p, q = map(self.find, (p, q))
    if p == q:
      return False

    if self.size[p] < self.size[q]:
      p, q = q, p

    self.size[p] += self.size[q]
    self.father[q] = p

    return True

  def insert(self, p):
    if p not in self.father:
      self.father[p] = p
      self.size[p] = 1

      
class Solution:
  def minCostConnectPoints(self, points: List[List[int]]) -> int:
    dis = []
    for i, (x, y) in enumerate(points):
      for u, v in points[:i]:
        dis.append((abs(x-u) + abs(y-v), (x, y), (u, v)))
    dis.sort()
    
    uf, r = UnionFind(), 0
    for d, p1, p2 in dis:
      if uf.union(p1, p2):
        r += d
    return r

class UnionFind:
    def __init__(self, n): 
        self.parent = list(range(n))
        self.count = n
        self.rank = [1]*n
        
    def find(self, p): 
        if p != self.parent[p]:
            self.parent[p] = self.find(self.parent[p]) # path compression 
        return self.parent[p]
    
    def union(self, p, q): 
        prt = self.find(p)
        qrt = self.find(q)
        if prt == qrt: return False # already connected 
        if self.rank[prt] > self.rank[qrt]: prt, qrt = qrt, prt
        self.parent[prt] = qrt 
        self.rank[qrt] += self.rank[prt]
        return True 
    

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        uf = UnionFind(n)
        hp = [] # min heap 
        
        for i in range(n):
            for ii in range(i+1, n):
                cost = abs(points[i][0] - points[ii][0]) + abs(points[i][1] - points[ii][1])
                heappush(hp, (cost, i, ii))
        
        ans = 0
        while hp and uf.count != 1: 
            cost, i, ii = heappop(hp)
            if uf.union(i, ii): ans += cost 
        return ans 

from heapq import heappop, heappush, heapify

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        graph = [[] for i in range(len(points))]
        
        def dist(p1, p2):
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        
        start_point = 0
        min_edge = 1000000000
        for i, p_i in enumerate(points[:-1]):
            for j, p_j in enumerate(points[i+1:], i + 1):
                d = dist(p_i, p_j)
                graph[i].append((j, d))
                graph[j].append((i, d))
                if d < min_edge:
                    min_edge = d
                    start_point = i
        
        
        total_dist = 0
        pq = [(d, n) for n, d in graph[start_point]]
        heapify(pq)
        visited = [False] * len(points)
        visited[start_point] = True
        
        while len(pq) > 0:
            d, node = heappop(pq)
            if visited[node]:
                continue
            visited[node] = True
            total_dist += d
            for child, child_d in graph[node]:
                if visited[child]:
                    continue
                heappush(pq, (child_d, child))
        
        return total_dist
            
            
            
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # return self.MSTkruskal(points) # 8504ms
        return self.MSTprim(points) # 7640 ms
        
    def MSTkruskal(self, points):
        X = dict()      
        R = dict()

        # 初始化并查集
        def make_set(point):
            X[point] = point
            R[point] = 0

        # 找到节点的根
        def find(point):
            if X[point] != point:
                X[point] = find(X[point])
            return X[point]

        # 连接两个节点
        def merge(point1,point2):
            r1 = find(point1)
            r2 = find(point2)
            if r1 != r2:
                if R[r1] > R[r2]:
                    X[r2] = r1
                else:
                    X[r1] = r2
                    if R[r1] == R[r2]: 
                        R[r2] += 1

        #KRUSKAL算法实现
        def kruskal(graph):
            # 遍历顶点，初始化并查集
            for vertex in graph['vertices']:
                make_set(vertex)

            k_tree = set()

            edges = graph['edges']
            # 按照权重从小到大排序
            edges.sort()    

            # 遍历每一条边        
            for weight, vertex1, vertex2 in edges:
                # 判断两个顶点是否联通：即是否在属于一棵树
                if find(vertex1) != find(vertex2):
                    # 如果未联通，则将其联通
                    merge(vertex1, vertex2)
                    # 加入生成树
                    k_tree.add((weight, vertex1, vertex2))

            return k_tree
        
        N = len(points)
        graph = {'vertices' : list(range(N)), 'edges' : list()}
        for i in graph['vertices']:
            for j in graph['vertices']:
                if i != j:
                    graph['edges'].append((abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]), i, j))
        return sum(weight for weight, _, _ in kruskal(graph))
    
    def MSTprim(self, points):

        def prim(origin_vertex, edges):
            adjacent_vertex = defaultdict(list)      

            # 将edges列表中各项归类成以某点为dictionary的key，其value则是其相邻的点及其权重
            # 形如：{'A': [(7, 'A', 'B'), (5, 'A', 'D')], 
            #       'C': [(8, 'C', 'B'), (5, 'C', 'E')]}
            for weight, vertex1, vertex2 in edges:
                adjacent_vertex[vertex1].append((weight, vertex1, vertex2))

            p_tree = []        
            # 标记是否已选择：这里首先选择源点
            chosed = set([origin_vertex]) 

            # 得到与源点直连的相邻点边
            adjacent_vertexs_edges = adjacent_vertex[origin_vertex]  

            # 将源点所有的直连边加入小顶堆中
            heapify(adjacent_vertexs_edges)

            # 循环遍历小顶堆
            while adjacent_vertexs_edges:
                # 从堆中取出边权值最小的点信息。
                weight, vertex1, vertex2 = heappop(adjacent_vertexs_edges) 

                # 如果边权值最小的对端点还没有加入生成树中    
                if vertex2 not in chosed:
                    # 将该点标记已选择
                    chosed.add(vertex2)

                    # 将该最小边加入生成树中
                    p_tree.append((vertex1,vertex2,weight))

                    # 遍历与该点直连的相邻点边
                    for next_vertex in adjacent_vertex[vertex2]:   
                        # 如果该点的对端点还没有被选择，则将其对应的边加入堆中             
                        if next_vertex[2] not in chosed:
                            heappush(adjacent_vertexs_edges,next_vertex)

            return p_tree
        
        N = len(points)
        graph = {'vertices' : list(range(N)), 'edges' : list()}
        for i in graph['vertices']:
            for j in graph['vertices']:
                if i != j:
                    graph['edges'].append((abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]), i, j))   
        return sum(weight for _, _, weight in prim(graph['vertices'][0], graph['edges']))
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        #prims
        g = defaultdict(list)
        n = len(points)
\t    #create graph
        for i in range(n):
            for j in range(n):
                if i != j:
                    g[i].append((abs(points[j][0]-points[i][0])+abs(points[j][1]-points[i][1]), j)) 
    
        heap = [(0,0)]
        ans = 0
        visited = set()
        while heap:
            weight, to = heapq.heappop(heap)
            if to in visited:
                continue
            ans += weight
            visited.add(to)
        
            for cost, nei in g[to]:
                if nei not in visited:
                    heapq.heappush(heap, (cost, nei))
    
        return ans
                            
        

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        #prims
        g = defaultdict(list)
        n = len(points)
        #create graph
        for i in range(n):
            for j in range(n):
                if i != j:
                    g[i].append((abs(points[j][0]-points[i][0])+abs(points[j][1]-points[i][1]), j))

        heap = [(0,0)]
        ans = 0
        visited = set()
        while heap:
            weight, to = heapq.heappop(heap)
            if to in visited:
                continue
            ans += weight
            visited.add(to)

            for cost, nei in g[to]:
                if nei not in visited:
                    heapq.heappush(heap, (cost, nei))

        return ans

class DSU:
    def __init__(self, n):
        self.n = n
        self.fa = list(range(n))

    def find(self, x):
        r = x
        while self.fa[r] != r:
            r = self.fa[r]
        i = x
        while i != r:
            i, self.fa[i] = self.fa[i], r
        return r
    
    def join(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x != y:
            self.fa[x] = y

class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:
        n = len(p)
        e = []
        for i in range(n):
            for j in range(n):
                if i == j:
                    continue
                d = abs(p[i][0] - p[j][0]) + abs(p[i][1] - p[j][1])
                e.append((d, i, j))
        
        e.sort()
        
        dsu = DSU(n)
        m = 0
        ans = 0
        for (d, i, j) in e:
            if m == n - 1:
                break
            if dsu.find(i) != dsu.find(j):
                ans += d
                dsu.join(i, j)
        return ans


from heapq import *
class Solution:
    def minCostConnectPoints(self, points):
        N = len(points)
        parent = [i for i in range(N)]
        def find(v):
            while parent[v] != parent[parent[v]]:
                parent[v] = parent[parent[v]]
            return parent[v]
        dist = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        heap, total_cost = [], 0
        for u in range(N-1):
            for v in range(u+1, N):
                heappush(heap, [dist(points[u], points[v]), u, v])
        while heap:
            cost, u, v = heappop(heap)
            pu, pv = find(u), find(v)
            if pu != pv:
                parent[pu] = pv
                N -= 1
                total_cost += cost
                if N == 0:
                    break
        return total_cost

    
    
    
    
    
    
    
    
from heapq import *
class Solution:
    def minCostConnectPoints(self, points):
        dist = lambda p1, p2: abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        N = len(points)
        parent = [i for i in range(N)]
        def find(v):
            while parent[v] != parent[parent[v]]:
                parent[v] = parent[parent[v]]
            return parent[v]
        heap = []
        for i in range(N-1):
            for j in range(i+1, N):
                heappush(heap, (dist(points[i], points[j]), i, j))
        res = 0
        while heap:
            d, u, v = heappop(heap)
            pu, pv = find(u), find(v)
            if pu != pv:
                parent[pu] = pv
                res += d
                N -= 1
                if N == 0:
                    break
        return res
            


    
    
class Solution:
    def minCostConnectPoints(self, points):
        distance = lambda p1, p2: abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        points.sort(key = lambda p: abs(p[0]) + abs(p[1]))
        total_cost = 0
        points = [[p, distance(p, points[0])] for p in points]
        while points:
            minIdx, mindist = None, float('inf')
            for i, (p1, dist) in enumerate(points):
                if dist < mindist:
                    minIdx, mindist = i, dist
            p1, cost = points.pop(minIdx)
            total_cost += cost
            for i, (p2, dist) in enumerate(points):
                newdist = distance(p1, p2)
                if newdist < dist:
                    points[i][1] = newdist
        return total_cost        

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def calculate_distance(x1, y1, x2, y2):
            return abs(x1 - x2) + abs(y1 - y2)

        n = len(points)
        visited = set()
        res = 0
        m = 0
        dp = [sys.maxsize for _ in range(n)]

        for i in range(n - 1):
            x, y = points[m]
            visited.add(m)
            for j in range(n):
                if j in visited:
                    continue

                x1, y1 = points[j]
                dp[j] = min(dp[j], calculate_distance(x, y, x1, y1))

            v, m = min((j, i) for i, j in enumerate(dp))
            dp[m] = sys.maxsize
            res += v

        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        cnt = len(points)
        dist = []
        connected = [False] * cnt
        
        for i in range(cnt):
            for j in range(i):
                p1, p2 = points[i], points[j]
                tmp_d = abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
                dist.append([(i, j), tmp_d])
        
        res = 0
        dist = sorted(dist, key = lambda d: d[1])
        
        parent = [i for i in range(cnt)]
        
        def findp(x):
            if parent[x] != x: return findp(parent[x])
            return x
        
        def combine(x, y):
            px, py = findp(x), findp(y)
            parent[px] = py
            
        for d in dist:
            if findp(d[0][0]) != findp(d[0][1]):
                combine(d[0][0], d[0][1])
                res += d[1]
        
        return res
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        pointSet = set()
        CostHeap = []
        
        for i in range(len(points)):
            pointSet.add(i)
            for j in range(i+1, len(points)):
                heapq.heappush(CostHeap, [abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1]), i, j])
        
        parent = defaultdict(lambda: -1)
        def find(x):
            if parent[x] == -1:
                return x
            else:
                parent[x] = find(parent[x])
                return parent[x]
            
        COST = 0
        #print(CostHeap)
        while CostHeap:
            node = heapq.heappop(CostHeap)
            cost,x,y = node
            #print(parent)
            u = find(x)
            v = find(y)
            if u != v:
                parent[u] = v               
                COST+=cost
                #if x in pointSet:
                #    pointSet.remove(x)
                #if y in pointSet:
                #    pointSet.remove(y)
                #if len(pointSet) == 0:
                #    break
        return COST
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        total = 0
        mst = defaultdict(set)
        graph = collections.defaultdict(dict)
        visited = [False for i in range(len(points))]
        visited[0] = True
        for i in range(len(points)):
            for j in range(len(points)):
                if j == i:
                    continue
                graph[i][j] = (self.getDist(points[i][0], points[i][1], points[j][0], points[j][1]))
        edges = [(cost, 0, to) for to, cost in graph[0].items()]
        heapq.heapify(edges)
        while edges:
            cost, frm, to = heapq.heappop(edges)
            if not visited[to]:
                visited[to] = True
                total += cost
                for to_next, cost_next in graph[to].items():
                    if not visited[to_next]:
                        heapq.heappush(edges, (cost_next, to, to_next))
        return total
                
                
    def getDist(self, x1, y1, x2, y2):
        return abs(x1 - x2) + abs(y1 - y2)

from collections import defaultdict
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        return kruskal(points)


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 union(self, x, y):
        
        xpar = self.find(x)
        ypar = self.find(y)
        
        if self.rank[xpar] > self.rank[ypar]:
            self.par[ypar] = xpar
        elif  self.rank[xpar] < self.rank[ypar]:
            self.par[xpar] = ypar
        elif self.rank[xpar] == self.rank[ypar]:
            self.par[xpar] = ypar
            self.rank[xpar] += 1
            
    
    def connected(self, x, y):
        return self.find(x) == self.find(y)
            
    

def kruskal(points):
    
    n     = len(points)
    V     = UnionFind(n)
    mst   = set()
    edges = set()
    
    for i, (x1, y1) in enumerate(points):
        for j, (x2, y2) in enumerate(points):
            edges.add((i,j,abs(x2-x1)+abs(y2-y1)))

    edges = sorted(edges, key=lambda e: e[2])
    
    cost = 0
    for e in edges:
        
        i, j, w = e
        if V.connected(i,j):
            continue
        
        V.union(i,j)
        mst.add(i)
        mst.add(j)
        cost += w
    return cost    


from heapq import heapify, heappop, heappush
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def dist(p1, p2):
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        
        n = len(points)
        edges = []
        for i in range(n):
            for j in range(i+1, n):
                l = dist(points[i], points[j])
                edges.append((i, j, l))
        
        
        def prim(nodes, edges):
            conn = defaultdict( list )
            for n1,n2,c in edges:
                conn[n1].append((c, n1, n2))
                conn[n2].append((c, n2, n1))

            mst = []
            used = set([nodes[ 0 ]])
            usable_edges = conn[nodes[0]][:]
            heapify(usable_edges)
            ans = 0
            while usable_edges:
                cost, n1, n2 = heappop(usable_edges)
                if n2 not in used:
                    used.add(n2)
                    mst.append((n1, n2, cost))
                    ans += cost
                    for e in conn[n2]:
                        if e[2] not in used:
                            heappush(usable_edges, e)
            return ans
        
        nodes = list(range(n))
        return prim(nodes, edges)


class UnionFindGraph(dict):
    def union(self, p: Hashable, q: Hashable):
        rootOfP = self.root(p)
        rootOfQ = self.root(q)
        self[rootOfP] = rootOfQ

    def isConnected(self, p: Hashable, q: Hashable) -> bool:
        return self.root(p) == self.root(q)

    def root(self, r: Hashable) -> Hashable:

        while r != self[r]:
            self[r] = self[self[r]]
            r = self[r]

        return r

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        graph = UnionFindGraph()
        edges = []

        for i, v in enumerate(points):

            for j, w in enumerate(points[i + 1: ], i + 1):
                if i != j:
                    edges.append(((tuple(v), tuple(w)), self.distance(v, w)))

        edges.sort(key=lambda v: v[1])
        res = 0

        for (a, b), distance in edges:
            if a not in graph:
                graph[a] = a
            if b not in graph:
                graph[b] = b

            if not graph.isConnected(a, b):
                res += distance
                graph.union(a, b)

        return res

    def distance(self, a: Tuple[int, int], b: Tuple[int, int]) -> int:
        return abs(a[0] - b[0]) + abs(a[1] - b[1])


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def buildmst(graph, starting_vertex):
            mst = defaultdict(set)
            visited = set([starting_vertex])
            edges = [
                (cost, starting_vertex, to)
                for to, cost in list(graph[starting_vertex].items())
            ]
            # print(edges)
            heapq.heapify(edges)

            while edges:
                cost, frm, to = heapq.heappop(edges)
                if to not in visited:
                    visited.add(to)
                    mst[frm].add(to)
                    for to_next, cost in list(graph[to].items()):
                        if to_next not in visited:
                            heapq.heappush(edges, (cost, to, to_next))

            return mst
        
        graph = defaultdict(dict)
        
        for x in points:
            t = (x[0], x[1])
            for y in points:
                if x != y:
                    graph[t][(y[0], y[1])] = abs(x[0] - y[0]) + abs(x[1] - y[1])
                    
        mst = dict(buildmst(graph, (points[0][0], points[0][1])))
        ans = 0
        # print(mst)
        # for k, v in mst.items():
        #     print(k, v)
        
        for k, v in list(mst.items()):
            for p in v:
                ans += abs(k[0] - p[0]) + abs(k[1] - p[1])
                
        return ans
                    
                    
                    
                    
                    


parent = 0
def find(i):
    nonlocal parent
    l1 = []
    while parent[i] != i:
        l1.append(i)
        i = parent[i]
    j = i
    for i in l1:
        parent[i] = j
    return j
    
    
    
def givedistance(a, b):
    return abs(a[0] - b[0]) + abs(a[1] - b[1])
class Solution:
    def minCostConnectPoints(self, l: List[List[int]]) -> int:
        nonlocal parent
        
        visited = {}
        
        l1 = []
        n = len(l)
        for i in range(n):
            for j in range(i + 1, n):
                l1.append([givedistance(l[i], l[j]), tuple(l[i]), tuple(l[j])])
                
        l1.sort()
        l1.reverse()

        ans = 0

        if n == 1:return 0
        
        d = {}
        ind = 0
        for i in l:
            d[tuple(i)] = ind
            ind += 1
        
        for i in range(len(l1)):
            l1[i][1] = d[l1[i][1]]
            l1[i][2] = d[l1[i][2]]
        parent = {}
        for i in l1:
            parent[i[1]] = i[1]
            parent[i[2]] = i[2]
        
        taken = 0
        while taken != n - 1:
            curr, i, j = l1.pop()
            
            p1 = find(i)
            p2 = find(j)
            
            if p1 != p2:
                parent[p1] = parent[p2]
                ans += curr
                taken += 1
        return ans
            
        
        
        
        
        
        


from collections import defaultdict

class UnionFind:
\tdef __init__(self):
\t\tself.parentsMap = {}\t# tracks the parents of nodes
\t\tself.rootLen = defaultdict(lambda:1)\t# tracks no. of nodes in it
\t
\tdef find(self, node: object)-> object:
\t\t\"returns the root node to the given (arg) node\"
\t\t# 1. creates parent-node of node if node not in parentsMap
\t\t# 2. loops through the parents of given node till the root 
\t\t# (the parent of given node is itself) not found and updates 
\t\t# the parent of the nodes and returns the root of node.
\t\tif node not in self.parentsMap:\tself.parentsMap[node]=node
\t\twhile node!=self.parentsMap[node]:
\t\t\ttemp = self.parentsMap[node]
\t\t\tself.parentsMap[node] = self.parentsMap[temp]
\t\t\tnode=temp
\t\treturn self.parentsMap[node]

\tdef union(self, node1: object, node2: object)-> None:
\t\t# finds the roots of the given nodes and points a lower len root 
\t\t# to other root
\t\tparent1 = self.find(node1)
\t\tparent2 = self.find(node2)
\t\tif parent1!=parent2:
\t\t\tif self.rootLen[parent1]<self.rootLen[parent2]:
\t\t\t\tself.parentsMap[parent1]=parent2
\t\t\t\tself.rootLen[parent2]+=self.rootLen[parent1]
\t\t\telse:
\t\t\t\tself.parentsMap[parent2]=parent1
\t\t\t\tself.rootLen[parent1]+=self.rootLen[parent2]

\tdef isConnected(self, node1: object, node2: object)-> bool:
\t\t# checks if roots of the given nodes are same and return true if 
\t\t# they are else false
\t\treturn self.find(node1)==self.find(node2)

        
class Solution:
    def minCostConnectPoints(self, A: List[List[int]]) -> int:
        dist = lambda a, b: sum(abs(i-j) for i,j in zip(a,b))
        n = len(A)
        # m = sum(i for i,j in A)/n, sum(j for i,j in A)/n
        u = UnionFind()
        res = 0
        d = []
        # A.sort(key = lambda x: dist(m, x))
        # print(A)
        
        for i in range(1, len(A)):
            for j in range(i):
                e1 = tuple(A[i])
                e2 = tuple(A[j])
                d.append((dist(e1, e2), e1, e2))
                # e1 = tuple(A[i])
                # print(e1, sorted(A, key = lambda x: dist(e1, x), reverse=1))
                # for e2 in map(tuple, sorted(A, key = lambda x: dist(e1, x), reverse=1)):
                    # if e1==e2:
                    #     continue
                    # if u.isConnected(e1, e2):
                    #     continue
                    # dis = dist(e1, e2)
                    # u.union(e1, e2)
                    # res+=dis
        
        for w, e1, e2 in sorted(d):
            # e2, w = e
            # print(e1, e2, w)
            if u.isConnected(e1, e2):
                continue
            u.union(e1, e2)
            res+=w
        
        return res
        
        
        
        

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def find(p, u):
            if p[u] == u:
                return u
            root_u = find(p, p[u])
            p[u] = root_u
            return root_u
        
        def union(p, rank, root_u, root_v):
            if rank[root_u] < rank[root_v]:
                p[root_u] = root_v
            elif rank[root_v] < rank[root_u]:
                p[root_v] = root_u
            else:
                rank[root_u] += 1
                p[root_v] = root_u
            
        
        h = []
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                cost = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                heapq.heappush(h, [cost, i, j])
        
        p = list(range(len(points)))
        rank = [1] * len(points)
        total_cost = 0
        while len(h):
            cost, u, v = heapq.heappop(h)
            root_u, root_v = find(p, u), find(p, v)
            if root_u == root_v:
                continue
            union(p, rank, root_u, root_v)
            total_cost += cost
    
        return total_cost
            
            
        
                
                    


from collections import defaultdict
import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        s, heap, c, ans = set(), list(), 0, 0
        parent = [-1]*len(points)
        
        if len(points) == 1 or not points:
            return 0
        
        def give_dist(x, y):
            return abs(x[0] - y[0]) + abs(x[1] - y[1])
        
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                heap.append([give_dist(points[i], points[j]), i, j])
        
        heapq.heapify(heap)
        
        def find(x):
            if parent[x] == -1:
                return x
            parent[x] = find(parent[x])
            return parent[x]
        
        def union(x, y):
            px, py = find(x), find(y)
            parent[px] = py
        
        while c < len(points) - 1:
            d, x, y = heapq.heappop(heap)
            if find(x) != find(y):
                ans += d
                union(x, y)
                c += 1
        return ans
        
                


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        \"\"\"
        sets, edges = [], []
        res = []

        for i in range(len(points)):
            sets.append([i])
        
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                val = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((i,j,val))
        def custom_sort(t):
            return t[2]
        edges.sort(key=custom_sort)
        #print(edges); print(sets)
        
        for (u,v,cost) in edges:
            for i in range(len(sets)):
                if u in sets[i]:
                    setu = i
                    break
            for i in range(len(sets)):
                if v in sets[i]:
                    setv = i
                    break
            if setu != setv:
                w1 = sets[setu]
                w2 = sets[setv]
                res.append((u,v,cost))
                [w1.append(x) for x in w2 if x not in w1]
                sets = sets[:setv]+sets[setv+1:]
        
        sum = 0
        for e in res:
            sum += e[2]
        return sum
        \"\"\"
        edges = [[None] * len(points) for _ in range(len(points))]
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                val = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges[i][j] = val
                edges[j][i] = val
        
        cost = 0
        min_heap = [(0, 0)]
        visited = set()
        while len(min_heap):
            min_node = heapq.heappop(min_heap)
            if min_node[1] in visited: continue
            vertex = min_node[1]
            weight = min_node[0]
            cost += weight
            visited.add(vertex)
            #print('visted vertex is ', vertex, 'cost is', weight, 'total', cost, 'cur_min_heap', min_heap)
            for neigh in range(len(edges[vertex])):
                if neigh not in visited:
                    heapq.heappush(min_heap, (edges[vertex][neigh], neigh))
        
        return cost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        uf = {}
        
        def find(x):
            uf.setdefault(x, x)
            if uf[x] != x:
                uf[x] = find(uf[x])
            return uf[x]
        
        def union(x, y):
            px, py = find(x), find(y)
            if px != py:
                uf[px] = py
                
        @lru_cache(None)
        def dist(i, j):
            x1, y1 = points[i]
            x2, y2 = points[j]
            return abs(x1 - x2) + abs(y1 - y2)
                
        hp = []
        n = len(points)
        ans = 0
        for i in range(n):
            for j in range(i + 1, n):
                heapq.heappush(hp, (dist(i, j), i, j))
        
        while hp:
            d, i, j = heapq.heappop(hp)
            if find(i) != find(j):
                ans += d
                union(i, j)
                
        return ans
                
        

        
#         n = len(points)
#         U = {0}
#         V = set(range(n)) - U
#         ans = 0
#         while V:
#             cand = set()
#             mind = float(\"inf\")
#             for u in U:
#                 for v in V:
#                     if dist(u, v) < mind:
#                         mind = dist(u, v)
#                         tmp = v
#             ans += mind
#             U |= {tmp}
#             V -= {tmp}
#         return ans
                        


import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def manhattanDistance(x1,y1,x2,y2):
            return abs(x1-x2) + abs(y1-y2)
        
        n = len(points)
        
        distsMap = {}
        for i in range(n):
            for j in range(i+1, n):
                x1,y1 = points[i]
                x2,y2 = points[j]
                distsMap[(i,j)] = manhattanDistance(x1,y1,x2,y2)
                distsMap[(j,i)] = distsMap[(i,j)]
        
        result = 0
        pq = [(0,0)]
        seen = set()
        minDists = {i:float('inf') for i in range(n)}
        while len(pq) != 0:
            (dist,i) = heapq.heappop(pq)
            # print(dist,i)
            if i in seen:
                continue
            seen.add(i)
            result += dist
            
            minDists[i] = 0
            for j in range(n):
                if j in seen:
                    continue
                minDists[j] = min(minDists[j], distsMap[(i,j)])
                heapq.heappush(pq, (minDists[j],j) )
            
            # for j in range(n):
            #     if j in seen:
            #         continue
            #     # nextDist = min(distsMap[(ip,j)] for ip in seen)
            #     heapq.heappush(pq, (minDists[j],j) )
                # for ip in seen:
                    
                
        return result

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edge_heap = []
        cost_map = {}
        for i, point1 in enumerate(points):
            for j, point2 in enumerate(points):
                if point1 == point2:
                    continue
                cost_map[(min(i, j), max(i,j))] = abs(point1[1] - point2[1]) + abs(point1[0] - point2[0])
        
        forest = set([0])
        for i in range(1, len(points)):
            heapq.heappush(edge_heap, (cost_map[(0, i)], (0, i)))
        
        total_cost = 0
        
        while len(forest) != len(points):
            cost, (v1, v2) = heapq.heappop(edge_heap)
            v1_new = v1 not in forest
            v2_new = v2 not in forest
            if v1_new == v2_new:
                continue
            # print(f\"Adding edge {(points[v1], points[v2])} with cost {cost}\")
            forest.add(v1)
            forest.add(v2)
            total_cost += cost
            
            v_search = v1 if v1_new else v2
            for vx in range(len(points)):
                if vx == v_search or vx in forest:
                    continue
                i, j = min(v_search, vx), max(v_search, vx)
                heapq.heappush(edge_heap, (cost_map[i, j], (i, j)))
            
        return total_cost

from collections import defaultdict
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        return kruskal(points)


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 union(self, x, y):
        
        xpar = self.find(x)
        ypar = self.find(y)
        
        if self.rank[xpar] > self.rank[ypar]:
            self.par[ypar] = xpar
        elif  self.rank[xpar] < self.rank[ypar]:
            self.par[xpar] = ypar
        elif self.rank[xpar] == self.rank[ypar]:
            self.par[xpar] = ypar
            self.rank[xpar] += 1
            
    
    def connected(self, x, y):
        return self.find(x) == self.find(y)
            

def kruskal(points):
    
    n     = len(points)
    V     = UnionFind(n)
    #mst   = set()
    edges = set()
    
    for i, (x1, y1) in enumerate(points):
        for j, (x2, y2) in enumerate(points):
            edges.add((i,j,abs(x2-x1)+abs(y2-y1)))

    edges = sorted(edges, key=lambda e: e[2])
    
    cost = 0
    for e in edges:
        
        i, j, w = e
        if V.connected(i,j):
            continue
        
        V.union(i,j)
        #mst.add(i)
        #mst.add(j)
        cost += w
    return cost    


class DSU:
    def __init__(self, n):
        self.p = list(range(n))
    
    def find(self, i):
        if self.p[i] == i:
            return i
        self.p[i] = self.find(self.p[i])
        return self.p[i]
    
    def unite(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return False
        self.p[x] = y
        return True

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        n = len(points)
        
        def w(u, v):
            return sum(abs(points[u][i] - points[v][i]) for i in range(2))
        
        edges = [(u, v, w(u, v)) for u in range(n) for v in range(n)]
        edges.sort(key = lambda x: x[-1])
        ans = 0
        dsu = DSU(n)
        return sum(cost for [u, v, cost] in edges if dsu.unite(u, v))

from itertools import combinations
from collections import defaultdict
import heapq


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        points = [(i, *point) for i, point in enumerate(points)]

        edges = defaultdict(list)
        heap = []
        for (i, xi, yi), (j, xj, yj) in combinations(points, 2):
            dest = abs(xi - xj) + abs(yi - yj)
            # print(i, j, dest)
            edges[i].append((j, dest))
            edges[j].append((i, dest))
            heapq.heappush(heap, (dest, i, j))

        # print(heap)

        selected = set()
        answer = 0
        pending = []
        while heap:
            dest, i, j = heapq.heappop(heap)
            # print(i, j, dest)
            if not selected or ((i in selected) ^ (j in selected)):
                # print(selected)
                selected.add(i)
                selected.add(j)
                answer += dest
                while pending:
                    heapq.heappush(heap, pending.pop())
            elif (i not in selected) and (j not in selected):
                pending.append((dest, i, j))

        return answer


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:

        n = len(points)

        q = [(0, 0)]
        visited = set()
        G = defaultdict(list)
        for i in range(n):
            for j in range(n):
                if i!=j:
                    xi,yi = points[i]
                    xj,yj = points[j]
                    cost = abs(xi-xj) + abs(yi-yj)
                    G[i].append( (cost, j) )
                    G[j].append( (cost, i) )

        total = 0
        while q and len(visited) < n:
            cost1, v1 = heappop(q)
            if v1 not in visited:
                visited.add(v1)
                total += cost1
                for cost2, v2 in G[v1]:
                    heappush(q, (cost2, v2))

        return total


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        uf = {}
        
        def find(x):
            uf.setdefault(x, x)
            if uf[x] != x:
                uf[x] = find(uf[x])
            return uf[x]
        
        def union(x, y):
            px, py = find(x), find(y)
            if px != py:
                uf[px] = py
                
        @lru_cache(None)
        def dist(i, j):
            x1, y1 = points[i]
            x2, y2 = points[j]
            return abs(x1 - x2) + abs(y1 - y2)
        
        n = len(points)
        hp = [(dist(i, j), i, j) for i in range(n) for j in range(i + 1, n)]
        heapq.heapify(hp)
        ans = 0
        
        while hp:
            d, i, j = heapq.heappop(hp)
            if find(i) != find(j):
                ans += d
                union(i, j)
                
        return ans
                
        

        
#         n = len(points)
#         U = {0}
#         V = set(range(n)) - U
#         ans = 0
#         while V:
#             cand = set()
#             mind = float(\"inf\")
#             for u in U:
#                 for v in V:
#                     if dist(u, v) < mind:
#                         mind = dist(u, v)
#                         tmp = v
#             ans += mind
#             U |= {tmp}
#             V -= {tmp}
#         return ans
                        


from queue import PriorityQueue
from collections import defaultdict
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        parent = defaultdict(int)
        weight = defaultdict(int)
        
        def make_set(x: int):
            if x in parent:
                return
            parent[x] = x
            weight[x] = 1

        def find(x: int) -> int:
            if parent[x] == x:
                return parent[x]
            parent[x] = find(parent[x])
            return parent[x]
        
        def union_set(x: int, y: int):
            px, py = find(x), find(y)
            if px == py:
                return
            if weight[px] > weight[py]:
                parent[py] = px
                weight[px] += weight[py]
            else:
                parent[px] = py
                weight[py] += weight[px]
        
        n = len(points)
        ls = [] # list of(edge_weight, x, y)
        for i in range(n):
            for j in range(i + 1, n):
                x1, y1 = points[i]
                x2, y2 = points[j]
                ls.append([abs(x1 - x2) + abs(y1 - y2), i, j])
        ls.sort()
        cost = 0
        for c, x, y in ls:
            make_set(x)
            make_set(y)
            if find(x) == find(y):
                continue
            union_set(x, y)
            cost += c
        return cost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def dist(p1, p2):
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        res = 0
        dis = [float('inf')] * len(points)
        visited = set()
        cur = 0
        for i in range(len(points) - 1):
            visited.add(cur)
            for j in range(len(points)):
                if j not in visited:
                    dis[j] = min(dis[j], dist(points[cur], points[j]))
            d, cur = min((d, j) for j, d in enumerate(dis))
            dis[cur] = float('inf')
            res += d
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        distance=lambda p1,p2 : abs(p1[0]-p2[0])+ abs(p1[1]-p2[1])
        from collections import defaultdict
        n=len(points)
        c=defaultdict(list)
        for i in range(n):
            for j in range(i+1,n):
                d=distance(points[i],points[j])
                c[i].append((d,j))
                c[j].append((d,i))
        visited=[False]*n
        answer=0
        cnt=0
        import heapq
        heap=c[0]
        visited[0]=True
        heapq.heapify(heap)
        while heap:
            d,j=heapq.heappop(heap)
            if visited[j]==False:
                visited[j]=True
                answer=answer+d
                cnt+=1
                for record in c[j]:
                    heapq.heappush(heap,record)


        return answer





class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        res=0
        n=len(points)
        g=collections.defaultdict(list)
        tmp=[]
        vst=set()
        for i in range(n):
            for j in range(n):
                if i!=j and (i,j) not in vst:
                    vst.add((i,j))
                    vst.add((j,i))
                    dist=abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                    tmp.append([i,j,dist])
        
        parents=[i for i in range(n)]
        ranks=[1]*n
        
        def find(u):
            while u!=parents[u]:
                parents[u]=parents[parents[u]]
                u=parents[u]
            return u
  
        def union(u,v):
            root_u,root_v=find(u),find(v)
            if root_u==root_v:
                return False
            if ranks[root_v] > ranks[root_u]:
                root_u, root_v = root_v, root_u
            parents[root_v] = root_u
            ranks[root_u] += ranks[root_v]
            return True
        
        tmp.sort(key=lambda x:x[2])
        ans=0
        for u,v,val in tmp:
            if union(u,v):
                ans+=val
        groups=len({find(x) for x in parents})
        return ans if groups==1 else -1
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # Minimum spanning tree
        # Prim's algorithm
        
        def dist(p1, p2):
            return abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        

        ans = 0
        d = collections.defaultdict(list)
        
        for i, p1 in enumerate(points):
            for j, p2 in enumerate(points):
                # don't use list slicing because the index j will not be the index for the full points list
                if i != j:
                    cost = dist(p1, p2)
                    d[i].append((cost, j))
                    d[j].append((cost, i)) 
                    
        heap = d[0]
        # heap is a list of costs in ascending order for a given point p1
        heapq.heapify(heap)
        n = len(points)
        visited = [0] * n
        visited[0] = 1
        count = 1
        
        while heap:
            cost, j = heapq.heappop(heap)
            # ensure cycles are not formed
            if not visited[j]:
                # not yet visit p2 where cost is minimum, can connect p1 and p2
                visited[j] = 1
                count += 1
                ans += cost
                for item in d[j]:
                    # since p1 and p2 are now connected, focus on p2
                    # push items in dict at p2 to heap
                    heapq.heappush(heap, item)
                    
            if count >= n:
                # already connected all points
                break
                
        return ans
        
        # # solution
        # manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        # n, c = len(points), collections.defaultdict(list)
        # for i in range(n):
        #     print(\"i: \", i)
        #     for j in range(i+1, n):
        #         print(\"j:\", j)
        #         d = manhattan(points[i], points[j])
        #         c[i].append((d, j))
        #         c[j].append((d, i))
        # cnt, ans, visited, heap = 1, 0, [0] * n, c[0]
        # visited[0] = 1
        # heapq.heapify(heap)
        # while heap:
        #     d, j = heapq.heappop(heap)
        #     if not visited[j]:
        #         visited[j], cnt, ans = 1, cnt+1, ans+d
        #         for record in c[j]: heapq.heappush(heap, record)
        #     if cnt >= n: break        
        # return ans


from heapq import heappop, heappush, heapify
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n =len(points)
        if n<=1:
            return 0
        ds = UFind(n)
        hp = []
        for i in range(n-1):
            for j in range(i+1,n):
                mhd = abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                hp.append((mhd, i, j))
        heapq.heapify(hp)
        ans = 0
        while ds.count>1:
            mhd, i, j = heapq.heappop(hp)
            if ds.union(i,j):
                ans+=mhd
        return ans
class UFind:
    def __init__(self, n):
        self.parent = list(range(n))
        self.rank = [1]*n
        self.count = n
    def find(self,x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    def union(self, x, y):
        x_par, y_par = self.find(x), self.find(y)
        if x_par == y_par:
            return False
        else:
            self.count-=1
            if self.rank[x_par]<self.rank[y_par]:
                self.parent[x_par] = y_par
            elif self.rank[x_par]>self.rank[y_par]:
                self.parent[y_par] = x_par
            else:
                self.parent[x_par] = y_par
                self.rank[y_par]+=1  
            return True

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        heap = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                x1, y1 = points[i]
                x2, y2 = points[j]
            
                dist = abs(x1-x2) + abs(y1-y2)
                heap.append((dist, i, j))
        
        heapify(heap)
        uf = UnionFind(len(points))
        res = 0
        num_edges = 0
        
        while heap:
            dist, x, y = heappop(heap)
            if uf.union(x, y):
                res += dist
                num_edges += 1
            if num_edges == len(points)-1:
                break
                
        return res
    
class UnionFind:
    def __init__(self, n):
        self.parent = list(range(n))
        self.rank = [0]*n
        
    def union(self, x, y):
        root_x = self.find(x)
        root_y = self.find(y)
        
        if root_x == root_y:
            return False
        
        if self.rank[root_x] > self.rank[root_y]:
            self.parent[root_y] = root_x
        
        else:
            self.parent[root_x] = root_y
            if self.rank[root_x] == self.rank[root_y]:
                self.rank[root_y] += 1
        
        return True
    
    def find(self, x):
        while x != self.parent[x]:
            self.parent[x] = self.parent[self.parent[x]]
            x = self.parent[x]
        return x
                
        
        
        
        


import heapq

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def dist(p1, p2):
            return abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        
        h = [(0, 0, 0)]
        seen = set()
        res = 0
        n = len(points)
        
        while len(seen) < n:
            d, u, v = heapq.heappop(h)
            if v in seen: continue
            seen.add(v)
            res += d
            for w in range(n):
                if w in seen or w == v: continue
                heapq.heappush(h, (dist(points[v], points[w]), v, w))                
        
        return res

import heapq

def dist(i, j, points):
    return abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])

class UnionFind:
    def __init__(self, n):
        self.root = [i for i in range(n)]
        self.cnt = n
        
    def find(self, x):
        if self.root[x] == x:
            return x
        p = self.root[x]
        self.root[x] = self.find(p)
        return self.root[x]
    
    def union(self, i, j):
        ri, rj = self.find(i), self.find(j)
        self.root[ri] = rj
        self.cnt -= 1

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        n = len(points)
        for i in range(n):
            for j in range(i+1, n):
                edges.append((dist(i, j, points), i, j))
        
        heapq.heapify(edges)
        res = 0
        uf = UnionFind(n)
        while uf.cnt > 1:
            e = None
            while True:
                e = heapq.heappop(edges)
                if uf.find(e[1]) != uf.find(e[2]):
                    break
            res += e[0]
            uf.union(e[1], e[2])
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if len(points) == 1: return 0
        res = 0
        curr = 0 # select a random point as the starting point
        dis = [math.inf] * n
        explored = set()
        
        for i in range(n - 1):
            x0, y0 = points[curr]
            explored.add(curr)
            dis[curr] = math.inf
            for j, (x, y) in enumerate(points):
                if j in explored: continue
                dis[j] = min(dis[j], abs(x - x0) + abs(y - y0))
                
            delta, curr = min((d, j) for j, d in enumerate(dis)) 
            res += delta
            
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def find(x):
            if parent[x] != x:
                return find(parent[x])
            return parent[x]
        
        def union(x, y):
            xroot, yroot = find(x), find(y)
            if xroot == yroot: return
            parent[xroot] = yroot
            
        l = len(points)
        parent = [i for i in range(l)]
        dis = []
        for i in range(l):
            for j in range(i+1, l):
                dis.append(
                    (abs(points[j][1] - points[i][1]) + abs(points[j][0] - points[i][0]), i, j)
                )
    
        
        heapq.heapify(dis)
        # l-1 break
        count = 0
        ans = 0
        while dis:
            temp, node1, node2 = heapq.heappop(dis)
            if find(node1) != find(node2):
                union(node1, node2)
                ans += temp
                count += 1
            if count == l-1:
                break
        return ans


from collections import defaultdict
import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        heap, c, ans = list(), 0, 0
        parent = [-1]*len(points)
        if len(points) == 1 or not points:
            return 0
        def give_dist(x, y):
            return abs(x[0] - y[0]) + abs(x[1] - y[1])
        
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                heap.append([give_dist(points[i], points[j]), i, j])
        
        heapq.heapify(heap)
        
        def find(x):
            if parent[x] == -1:
                return x
            parent[x] = find(parent[x])
            return parent[x]
        
        def union(x, y):
            px, py = find(x), find(y)
            parent[px] = py
        
        while c < len(points) - 1:
            d, x, y = heapq.heappop(heap)
            if find(x) != find(y):
                ans += d
                union(x, y)
                c += 1
        return ans
        
                


class Solution:
    def minCostConnectPoints(self, points):
        distance = lambda p1, p2: abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        points.sort(key = lambda p: p[0] + p[1])
        points = [[p, distance(p, points[0])] for i, p in enumerate(points)]
        total_cost = 0
        while points:
            minI, minD = None, float('inf')
            for i, (p1, dist) in enumerate(points):
                if dist < minD:
                    minI, minD = i, dist
            p1, cost = points.pop(minI)
            total_cost += cost
            for i, (p2, _) in enumerate(points):
                points[i][1] = min(points[i][1], distance(p1, p2))
        return total_cost
    
class Solution:
    def minCostConnectPoints(self, points):
        distance = lambda p1, p2: abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        points.sort(key = lambda p: p[0] + p[1])   # points.sort(key = lambda p: abs(p[0]) + abs(p[1]))
        total_cost = 0
        points = [[p, distance(p, points[0])] for p in points]
        while points:
            minIdx, mindist = None, float('inf')
            for i, (p1, dist) in enumerate(points):
                if dist < mindist:
                    minIdx, mindist = i, dist
            p1, cost = points.pop(minIdx)
            total_cost += cost
            for i, (p2, dist) in enumerate(points):
                #points[i][1] = min(points[i][1], distance(p1, p2))
                newdist = distance(p1, p2)
                if newdist < dist:
                    points[i][1] = newdist
        return total_cost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        ans = i = connected = 0
        min_d = [10 ** 7] * n
        while connected < n - 1:
            min_d[i] = float('inf')
            min_j = i
            for j in range(n):
                if min_d[j] != float('inf'):
                    min_d[j] = min(min_d[j], abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]))
                    min_j = j if min_d[j] < min_d[min_j] else min_j
            ans += min_d[min_j]
            i = min_j
            connected += 1
            
        return ans

import heapq

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def dist(p1, p2):
            return abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        
        def find(i):
            if parent[i] < 0: return i
            parent[i] = find(parent[i])
            return parent[i]
            
        res = 0
        n = len(points)
        parent = [-1]*n
        rank = [0]*n
        h = []
        
        for u in range(n):
            for v in range(u+1, n):
                h.append((dist(points[u], points[v]), u, v))
                
        heapq.heapify(h)
        
        while h:
            d, u, v = heapq.heappop(h)
            u, v = find(u), find(v)
            if u != v:
                res += d
                if rank[u] > rank[v]:
                    parent[u] += parent[v]
                    parent[v] = u
                else:
                    parent[v] += parent[u]
                    parent[u] = v
                    if rank[u] == rank[v]: rank[v] += 1
                
                if parent[u] == -n or parent[v] == -n: break
                    
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def manhattan(p1, p2):
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        
        n = len(points)
        seen = set()
        res = 0
        pq = [(0, 0, 0)]
        while len(seen) < n:
            w, u, v = heapq.heappop(pq)
            if u in seen and v in seen:
                continue
            res += w
            seen.add(u)
            seen.add(v)
            for i in range(n):
                if i != v and i not in seen:
                    heapq.heappush(pq, (manhattan(points[v], points[i]), v, i))
        return res

def getDistance(i, j, points):
    x1, y1, x2, y2 = points[i][0], points[i][1], points[j][0], points[j][1]
    return abs(y1 - y2) + abs(x1 - x2)
    


class Solution:
    
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        n = len(points)
        
        
        
        res = 0
        nextPoint = 0
        vis = set([0])
        count = 1
        disMap = {}
        
        while count < n:
            minPoint, minLength = 0, sys.maxsize
            for i in range(n):
                
                if i in vis:
                    continue
                
                l = getDistance(nextPoint, i, points)
                
                if i not in disMap or l < disMap[i]:
                    disMap[i] = l
                 
                if disMap[i] < minLength:
                    minLength = disMap[i]
                    minPoint = i
            
            
            
            res += minLength
            vis.add(minPoint)
            count += 1
            nextPoint = minPoint
            
            
            
                
        
        return res
            
                
                
                
            
            


from collections import defaultdict
import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        s, heap, c, ans = set(), list(), 0, 0
        parent = [-1]*len(points)
        
        if len(points) == 1 or not points:
            return 0
        
        def give_dist(x, y):
            return abs(x[0] - y[0]) + abs(x[1] - y[1])
        
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                heap.append([give_dist(points[i], points[j]), i, j])
        
        heapq.heapify(heap)
        
        def find(x):
            while parent[x] != -1:
                x = parent[x]
            return x
        
        def union(x, y):
            px, py = find(x), find(y)
            parent[px] = py
        
        while c < len(points) - 1:
            d, x, y = heapq.heappop(heap)
            if find(x) != find(y):
                ans += d
                union(x, y)
                c += 1
        return ans
        
                


\"\"\"
This is a minimum spanning tree problem, which can be solved by kruskal's algo or Prim's algo.
We need to pre-compute all the possible edges' weights
\"\"\"
import heapq
from typing import Tuple
class Solution:
    def __init__(self):
      self.roots = {}
      self.ranks = {}
      
    def find(self, point: Tuple[int, int]) -> Tuple[int, int]:
      self.roots.setdefault(point, point)
      self.ranks.setdefault(point, 1)
      if point != self.roots[point]:
        self.roots[point] = self.find(self.roots[point])
      return self.roots[point]
    
    def union(self, point1: Tuple[int, int], point2: Tuple[int, int], root1: Tuple[int, int], root2: Tuple[int, int]):
      if self.ranks[root1] > self.ranks[root2]:
        self.roots[root2] = root1
      elif self.ranks[root1] < self.ranks[root2]:
        self.roots[root1] = root2
      else:
        self.roots[root1] = root2
        self.ranks[root2] += 1
      
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
      \"\"\"
      Kruskal's algo: always select the lightest edge, and use a union find to detect cycles. If there are cycles ignore that edge.
      Time:
      For minimum spanning tree, V vertices have E=V-1 edges.
        * Compute all edge weights and sort: E^2 + ElogE
        * union find: amortized O(1), need to do this for all edges, so O(V). (Yes union-find with path compession and rank by union, has amortized time O(1))
        Over all E^2 + ElogE + V
      \"\"\"
      min_cost = 0
      edge_count = 0
      all_weights = []
      for i in range(len(points)):
        for j in range(i + 1, len(points)):
          xi, yi, xj, yj = (*points[i], *points[j])
          dist = abs(xi - xj) + abs(yi - yj)
          heapq.heappush(all_weights, (dist, xi, yi, xj, yj))
      
      # print(\"all_weights: \", all_weights)
      
      while len(all_weights) > 0:
        weight, xi, yi, xj, yj = heapq.heappop(all_weights)
        rooti, rootj = self.find((xi, yi)), self.find((xj, yj))
        if rooti != rootj:
          self.union((xi, yi), (xj, yj), rooti, rootj)
          # print(\"selected: \", weight, xi, yi, xj, yj)
          min_cost += weight
          edge_count += 1
          
          if edge_count == len(points) - 1: break
      
      return min_cost

class Solution:
    def minCostConnectPoints(self, points):
        helper = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        points, res = [[p, helper(p, points[0])] for p in points], 0
        while points:
            minI = min(list(range(len(points))), key = lambda i: points[i][1])
            p1, cost = points.pop(minI)
            res += cost
            for i, (p2, _) in enumerate(points):
                points[i][1] = min(points[i][1], helper(p1, p2))
        return res
    
    
    
    
    
    
    
    
    
    
    
    
    
    
class Solution:
    def minCostConnectPoints(self, points):
        helper = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        N, total_cost = len(points), 0
        points = [[p, helper(p, points[0])] for p in points]
        while points:
            minI = min(list(range(len(points))), key = lambda i: points[i][1])
            p2, cost = points.pop(minI)
            total_cost += cost
            for i, (p1, cost) in enumerate(points):
                points[i][1] = min(cost, helper(p1, p2))
        return total_cost
                
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        dis = [math.inf] * n
        visited = [False] * n
        ans = 0
        dis[0] = 0
        for i in range(0, n):
            d, j = min((d, j) for j, d in enumerate(dis))
            dis[j] = math.inf
            visited[j] = True
            ans += d
            for k in range(0, n):
                if j == k or visited[k]:
                    continue
                dis[k] = min(dis[k], abs(points[j][0] - points[k][0]) + abs(points[j][1] - points[k][1]))
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def get_dist(p,q):
            return abs(p[0]-q[0])+abs(p[1]-q[1])
        
        n=len(points)
        seen=set()
        dist=[math.inf]*n
        res=0
        cur=0
        for i in range(n-1):
            seen.add(cur)
            for j in range(n):
                if j in seen:
                    continue
                d=get_dist(points[cur],points[j])
                dist[j]=min(dist[j],d)
            
            delta,cur=min((d,j) for j,d in enumerate(dist))
            res+=delta
            dist[cur]=math.inf
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def get_dist(p,q):
            return abs(p[0]-q[0])+abs(p[1]-q[1])
        
        n=len(points)
        seen=set()
        dist=[math.inf]*n
        res=0
        cur=0
        for _ in range(n-1):
            seen.add(cur)
            for j in range(n):
                if j in seen:
                    continue
                d=get_dist(points[cur],points[j])
                dist[j]=min(dist[j],d)
            
            delta,cur=min((d,j) for j,d in enumerate(dist))
            res+=delta
            dist[cur]=math.inf
        return res

import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        total_cost = 0
        # any initial point can be chosen
        x1, y1 = points.pop() 
        # then make a heap sorted by distance to that point
        
        cost_heap = []
        for x2, y2 in points:
            heapq.heappush(cost_heap, [abs(x1-x2) + abs(y1-y2), x2, y2])
        
        # pop off the points with the lowest distance
        # then see if any of the remaining points are closer to that new point than
        # the previous points had been, and update the heap
        while cost_heap:
            cost, x1, y1 = heapq.heappop(cost_heap)
            total_cost += cost
            for i, [cost, x2, y2] in enumerate(cost_heap):
                cost_heap[i][0] = min(cost, abs(x1-x2) + abs(y1-y2))
            heapq.heapify(cost_heap)
            
        return total_cost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if len(points) == 1: return 0
        res = 0
        curr = 0 # select a random point as the starting point
        dis = [math.inf] * n
        explored = set()
        
        for i in range(n - 1):
            x0, y0 = points[curr]
            explored.add(curr)
            for j, (x, y) in enumerate(points):
                if j in explored: continue
                dis[j] = min(dis[j], abs(x - x0) + abs(y - y0))
                
            delta, curr = min((d, j) for j, d in enumerate(dis)) 
            dis[curr] = math.inf
            res += delta
            
        return res


import heapq

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) == 1:
            return 0
        # mst?
        np = len(points)
        rest = set(range(np))
        cur_val = 0
        rest.remove(cur_val)
        
        def get_costs(rest, node):
            return [(abs(points[node][0] - points[tmp][0]) + abs(points[node][1] - points[tmp][1]), node, tmp) for tmp in rest if tmp != node]
        
        q = get_costs(rest, cur_val)
        heapq.heapify(q)
        
        cost = 0
        
        while len(rest) > 0:
            dist, node1, node2 = heapq.heappop(q)
            if node2 in rest:
                cost += dist
                rest.remove(node2)
                for rsti in get_costs(rest, node2):
                    heapq.heappush(q, rsti)
                    
        return cost


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        dist = {}
        n = len(points)
        queue = []
        for i in range(n):
            x = points[i]
            for j in range(i + 1, n):
                y = points[j]
                heapq.heappush(queue, (abs(x[0] - y[0]) + abs(x[1] - y[1]), i, j))
                
        parents = list(range(n))
        rank = [1] * n
        def find(x):
            if parents[x] != x:
                parents[x] = find(parents[x])
            return parents[x]
        
        def union(x, y):
            px, py = find(x), find(y)
            if px == py:
                return False
            if rank[px] < rank[py]:
                px, py = py, px
            parents[py] = px
            rank[px] += rank[px] == rank[py]
            return True
                
        result = 0
        for _ in range(n - 1):
            while True:
                dist, i, j = heapq.heappop(queue)
                if union(i, j):
                    result += dist
                    break
        return result
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        num_points = len(points)
        mst = {0}
        mra = 0
        hep = []
        def dist(a,b):
            return abs(a[0] - b[0]) + abs(a[1]- b[1])
        
        def update_heap(added):
            for i,(x,y) in enumerate(points):
                if i not in mst:
                    heapq.heappush(hep, (dist(points[added], points[i]), added, i))
        
        sol = 0
        while len(mst) < num_points:
            update_heap(mra)
            
            while hep:
                d, x, y = heapq.heappop(hep)
                
                if y not in mst:
                    mst.add(y)
                    mra = y
                    sol += d
                    break
        
        return sol
                
                
        


class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:
        edges, n, cnt, ans = [], len(p), 1, 0

        def manhattan(x, y):
            return abs(p[x][0]-p[y][0]) + abs(p[x][1]-p[y][1])

        edges = [(manhattan(i, j), (i, j)) 
                 for i in range(n) for j in range(i+1, n)]
        heapq.heapify(edges)

        def union(x, y):
            uf[find(x)] = find(y)

        def find(x):
            if x != uf[x]:
                uf[x] = find(uf[x])
            return uf[x]

        uf = list(range(n))
        while cnt < n:
            d, (u, v) = heapq.heappop(edges)
            if find(u) != find(v):
                ans += d
                cnt += 1
                union(u, v)
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # 先算每一对点的距离
        # 最小生成树, union find
        edges = []
        n = len(points)
        if n == 1:
            return 0
        for i in range(n - 1):
            for j in range(i+1, n):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((i, j, dist))
        edges.sort(key = lambda x : x[2])
        parent = [i for i in range(n)]
        cnt = 0
        ans = 0
        for e in edges:
            x = e[0]
            y = e[1]
            px = self.find(x, parent)
            py = self.find(y, parent)
            if px != py:
                parent[px] = py
                cnt += 1
                ans += e[2]
            if cnt == n - 1:
                break
        return ans
        
    def find(self, x, parent):
        while parent[x] != x:
            parent[x] = parent[parent[x]]
            x = parent[x]
        return x

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if len(points) == 1: return 0
        res = 0
        curr = 0 # select a random point as the starting point
        dis = [math.inf] * n
        explored = set()
        
        for _ in range(n - 1):
            x0, y0 = points[curr]
            explored.add(curr)
            dis[curr] = math.inf
            for j, (x, y) in enumerate(points):
                if j in explored: continue
                dis[j] = min(dis[j], abs(x - x0) + abs(y - y0))
                
            delta, curr = min((d, j) for j, d in enumerate(dis)) 
            res += delta
            
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        '''
        Prim's algorithm
        Start from some initial point, we build a tree. We track connected points in 'seen'.
        For current point, we add all its edges to a min-heap. Each time, we pickup smallest
        edge which connects to a point not in 'seen'. Repeat until all points are in 'seen'.

        Time: O(V^2 + E*logE)
        Space: O(E)
        '''
        n = len(points)
        seen = set()
        heap = [[0, 0]]
        cost = 0
        for _ in range(n):
            while heap and heap[0][1] in seen:
                heapq.heappop(heap)
            dist, i = heapq.heappop(heap)
            cost += dist
            seen.add(i)
            for j in range(n):
                if j in seen: continue
                dist2j = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                heapq.heappush(heap, [dist2j, j])

        return cost

import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        ans=0
        visit=set()
        x0,y0=points[0]
        N=len(points)
        unvisit=set([i for i in range(1,N)])
        dis=N*[float('inf')]
        cur=0
        while unvisit:
            x0,y0=points[cur]
            for nei in unvisit:
                x1,y1=points[nei]
                dis[nei]=min(dis[nei],abs(x1-x0)+abs(y1-y0))
            cur=min(unvisit,key=lambda x: dis[x])
            ans+=dis[cur]
            unvisit.remove(cur)
        return ans
        
        
        
        
        \"\"\"
        xlist=[]
        ylist=[]
        for x,y in points:
            xlist.append(x)
            ylist.append(y)
        def partition(A,l,r):
            left,right=l,l
            pivot=A[r-1]
            for right in range(l,r):
                if A[right]<=pivot:
                    A[right],A[left]=A[left],A[right]
                    left+=1
            return left
        def medium(A):
            random.shuffle(A)
            N=len(A)
            left,right=0,N
            M=(N+1)//2
            z=-1
            while z!=M:
                z=partition(A,left,right)
                if z==M:
                    return A[z-1]
                elif z>M:
                    right=z-1
                else:
                    left=z
                partition(A,left,right)
        xm=medium(xlist)
        ym=medium(ylist)
        ans=0
        for x,y in points:
            ans+=abs(x-xm)
            ans+=abs(y-ym)
        return ans
        \"\"\"       
            
                

import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def distance(x, y):
            dx = abs(x[0] - y[0])
            dy = abs(x[1] - y[1])
            return dx+dy
        
        n = len(points)
        if n == 1:
            return 0
        if n == 2:
            return distance(points[0], points[1])
        
        # # Method 1: Prim's Alg with Heap
        # d = {i:[] for i in range(n)}
        # for i in range(n):
        #     for j in range(i+1, n):
        #         dist = distance(points[i], points[j])
        #         d[i].append((dist, j))
        #         d[j].append((dist, i))
        # cost = 0
        # connected = 1
        # check = [True] + [False]*(n-1)
        # heap = d[0]
        # heapq.heapify(heap)
        # while connected < n:
        #     (dist, p) = heapq.heappop(heap)
        #     if not check[p]:
        #         cost += dist
        #         connected += 1
        #         check[p] = 1
        #         for pair in d[p]:
        #             heapq.heappush(heap, pair)
        # return cost
        
        # Method 2: Kruskal's Alg with Disjoint Set
        
        
        
        # Nethod 3: Greedy
        cost = 0
        curr = 0 # select a random point as the starting point
        dist = [float('inf')] * n
        explored = set()
        explored.add(0)
        while len(explored) < n:
            x = points[curr]
            for j, y in enumerate(points):
                if j in explored: 
                    continue
                else:
                    dist[j] = min(dist[j], distance(x,y))
            min_d, curr = min((d, j) for j, d in enumerate(dist)) 
            explored.add(curr)
            dist[curr] = float('inf')
            cost += min_d
        return cost


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        total = 0
        edges = []
        N = len(points)
        parent = [x for x in range(N)]
        rank = [1 for x in range(N)]
        
        def ufind(x):
            if parent[x] == x:
                return parent[x]
            return ufind(parent[x])
            
        def uunion(x, y):
            ux = ufind(x)
            uy = ufind(y)
            if rank[ux] > rank[uy]:
                parent[uy] = ux
                rank[ux] += rank[uy]
            else:
                parent[ux] = uy
                rank[uy] += rank[ux]
            
        def dist(xi, yi, xj, yj):
            return abs(xi-xj) + abs(yi-yj)
        
        for i in range(N):
            xi, yi = points[i]
            for j in range(i+1, N):
                xj, yj = points[j]
                edges.append((dist(xi, yi, xj, yj), i, j))
                
        heapq.heapify(edges)
        n_added = 0
        while n_added < N-1:
            edge, i, j = heapq.heappop(edges)
            if ufind(i) != ufind(j):
                uunion(i, j)
                total += edge
                n_added += 1
        
        return total

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        if len(points) ==1:
            return 0
        heap = []      
        visited = set()        
        res = 0
        
        cur = 0
        visited.add(0)
        
        while len(visited)!=len(points):
            
            for i in range(len(points)):
                if cur==i or i in visited:
                    continue
                heapq.heappush(heap, (abs(points[i][0]-points[cur][0])+abs(points[i][1]-points[cur][1]), i))
                
            while True:
                val, nxt = heapq.heappop(heap)
               
                if nxt not in visited:
                    
                    visited.add(nxt)
                    res+=val
                    cur = nxt
                    break
        
        return res
            
        


class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:
        
        def manhattan(x, y):
            return abs(x[0]-y[0]) + abs(x[1]-y[1])
        
        cur, N, ans = 0, len(p), 0
        dis = [float('inf')] * N
        seen = set()
        
        for _ in range(N-1):
            seen.add(cur)
            for j in range(N):
                if j in seen: continue
                dis[j] = min(dis[j], manhattan(p[cur], p[j]))

            d, cur = min((w, k) for k, w in enumerate(dis))
            dis[cur] = float('inf')
            ans += d
            
        return ans
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        X = [[None] * n for _ in range(n)]
        for i in range(n):
            for j in range(i + 1, n):
                X[i][j] = X[j][i] = abs(points[i][0] - points[j][0]) + \\
                                    abs(points[i][1] - points[j][1])
        
        V = [0] + [float(\"inf\")] * (n - 1)
        S = [True] * n
        
        for _ in range(n - 1):
            i, v = -1, float(\"inf\")
            for j in range(n):
                if S[j] and V[j] < v:
                    i, v = j, V[j]
            
            S[i] = False
            for j in range(n):
                if S[j] and X[i][j] < V[j]:
                    V[j] = X[i][j]    
        
        return sum(V)

import math
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if len(points) == 1: return 0
        res = 0
        curr = 0 # select a random point as the starting point
        dis = [math.inf] * n
        explored = set()
        
        for i in range(n - 1):
            x0, y0 = points[curr]
            explored.add(curr)
            for j, (x, y) in enumerate(points):
                if j in explored: continue
                dis[j] = min(dis[j], abs(x - x0) + abs(y - y0))
                
            delta, curr = min((d, j) for j, d in enumerate(dis)) 
            dis[curr] = math.inf
            res += delta
            
        return res


class Solution:
    def minCostConnectPoints(self, A: List[List[int]]) -> int:
        # prim O(N^2)
        inf = float('inf')
        n = len(A)
        cost_sum = 0
        nearest_points = [inf]
        for i in range(1, n):
            nearest_points.append(abs(A[i][0]-A[0][0]) + abs(A[i][1]-A[0][1]))
        for i in range(n-1):
            mn_cost = inf
            for j in range(n):
                if nearest_points[j] < mn_cost:
                    mn_cost = nearest_points[j]
                    mn_cost_index = j
            cost_sum += mn_cost
            nearest_points[mn_cost_index] = inf
            for j in range(n):
                if nearest_points[j] != inf:
                    nearest_points[j] = min(nearest_points[j], abs(A[mn_cost_index][0]-A[j][0])+abs(A[mn_cost_index][1]-A[j][1]))
        return cost_sum


class Solution:
    def minCostConnectPoints(self, points) -> int:
        pq = []
        N = len(points)
        def dist(p1, p2):
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        
        p = list(range(N))
        s = [1] * N
        
        def find(u):
            while u != p[u]:
                p[u] = p[p[u]]
                u = p[u]
            return p[u]
        
        for i in range(N):
            for j in range(i + 1, N):
                heappush(pq, [dist(points[i], points[j]), i, j])
        
        edges = 0
        res = 0
        while edges < N - 1:
            d, u, v = heappop(pq)
            pu, pv = find(u), find(v)
            if pu == pv:
                continue
            edges += 1
            res += d
            if s[pv] > s[pu]:
                pu, pv = pv, pu
            p[pv] = pu
            s[pu] += s[pv]
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if len(points) == 1: 
            return 0
        ans = curr = 0
        d = [float(\"inf\")] * n
        v = set()
        for _ in range(n-1):
            x0, y0 = points[curr]
            v.add(curr)
            for j, (x, y) in enumerate(points):
                if j not in v:
                    d[j] = min(d[j], abs(x-x0) + abs(y-y0)) 
            delta, curr = min((v, j) for j, v in enumerate(d)) 
            d[curr] = float(\"inf\")
            ans += delta
        return ans

import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        total_cost = 0
        # any initial point can be chosen
        x1, y1 = points.pop() 
        # then make a heap sorted by distance to that point
        
        cost_heap = []
        heapq.heapify(cost_heap)
        for x2, y2 in points:
            heapq.heappush(cost_heap, [abs(x1-x2) + abs(y1-y2), x2, y2])
        
        # pop off the points with the lowest distance
        # then see if any of the remaining points are closer to that new point than
        # the previous points had been, and update the heap
        while cost_heap:
            cost, x1, y1 = heapq.heappop(cost_heap)
            total_cost += cost
            for i, [cost, x2, y2] in enumerate(cost_heap):
                cost_heap[i][0] = min(cost, abs(x1-x2) + abs(y1-y2))
            heapq.heapify(cost_heap)
            
        return total_cost

#Prim's algorithm
from heapq import *
class Solution:
    def minCostConnectPoints(self, points):
        n = len(points)
        dist = lambda p0, p1: abs(p1[0] - p0[0]) + abs(p1[1] - p0[1])
        q = [(0, 0)]
        visited = set()
        nodes = set(range(len(points)))
        res = 0
        while q:
            d, u = heappop(q)
            if u in visited:
                continue
            visited.add(u)
            res = res + d
            if len(visited) == n:
                return res
            for v in nodes:
                if v not in visited:
                    w = dist(points[u], points[v])
                    heappush(q, (w, v))

import heapq

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        manhattan = lambda p1, p2 : abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        pq = []
        p1 = points[0]
        seen_idxs = {0,}
        for idx in range(len(points)):
            if idx not in seen_idxs:
                p2 = points[idx]
                heapq.heappush(pq, (manhattan(p1, p2), idx))
            else:
                continue
                
        total_dist = 0
        while len(seen_idxs) != len(points):
            while pq[0][-1] in seen_idxs:
                heapq.heappop(pq)
            dist, min_idx = heapq.heappop(pq)
            
            total_dist += dist
            seen_idxs.add(min_idx)
            p1 = points[min_idx]
            
            for idx in range(len(points)):
                if idx not in seen_idxs:
                    p2 = points[idx]
                    heapq.heappush(pq, (manhattan(p1, p2), idx))
                    
        return total_dist
        
        


import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def distance(x, y):
            dx = abs(x[0] - y[0])
            dy = abs(x[1] - y[1])
            return dx+dy
        
        n = len(points)
        if n == 1:
            return 0
        if n == 2:
            return distance(points[0], points[1])
        
        # # Method 1: Prim's Alg with Heap
        # d = {i:[] for i in range(n)}
        # for i in range(n):
        #     for j in range(i+1, n):
        #         dist = distance(points[i], points[j])
        #         d[i].append((dist, j))
        #         d[j].append((dist, i))
        # cost = 0
        # connected = 1
        # check = [True] + [False]*(n-1)
        # heap = d[0]
        # heapq.heapify(heap)
        # while connected < n:
        #     (dist, p) = heapq.heappop(heap)
        #     if not check[p]:
        #         cost += dist
        #         connected += 1
        #         check[p] = 1
        #         for pair in d[p]:
        #             heapq.heappush(heap, pair)
        # return cost
        
        # Method 2: Kruskal's Alg with Disjoint Set
        
        
        
        # Nethod 3: Greedy
        cost = 0
        curr = 0 # select a random point as the starting point
        dist = [float('inf')] * n
        explored = set()
        explored.add(0)
        cnt = 1
        while cnt < n:
            x = points[curr]
            for j, y in enumerate(points):
                if j in explored: 
                    continue
                else:
                    dist[j] = min(dist[j], distance(x,y))
            min_d, curr = min((d, j) for j, d in enumerate(dist)) 
            explored.add(curr)
            cnt += 1
            dist[curr] = float('inf')
            cost += min_d
        return cost


import heapq

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def dist(p1, p2):
            return abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        
        res = 0
        n = len(points)
        seen = set()
        h = [(0, 0, 0)]
        
        while len(seen) < n:
            d, u, v = heapq.heappop(h)
            if v in seen: continue
            seen.add(v)
            res += d
            for w in range(n):
                if w in seen or w == v: continue
                heapq.heappush(h, (dist(points[v], points[w]), v, w))
                    
        return res

class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:
        
        def manhattan(x, y):
            return abs(x[0]-y[0]) + abs(x[1]-y[1])
        
        cur, N, ans = 0, len(p), 0
        dis = [float('inf')] * N
        seen = [False] * N
        
        for _ in range(N-1):
            seen[cur] = True
            for j in range(N):
                if seen[j]: continue
                dis[j] = min(dis[j], manhattan(p[cur], p[j]))

            d, cur = min((w, k) for k, w in enumerate(dis))
            dis[cur] = float('inf')
            ans += d
            
        return ans
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if len(points) == 1: 
            return 0
        res = 0
        curr = 0 # select a random point as the starting point
        dis = [math.inf] * n
        explored = set()
        
        for i in range(n - 1):
            x0, y0 = points[curr]
            explored.add(curr)
            for j, (x, y) in enumerate(points):
                if j in explored: 
                    continue
                dis[j] = min(dis[j], abs(x - x0) + abs(y - y0))
                
            delta, curr = min((d, j) for j, d in enumerate(dis)) 
            dis[curr] = math.inf
            res += delta
            
        return res

# # Kruskal
# # O(n ^ 2 log n)
# class UnionFindSet:
#     def __init__(self, n):
#         self.parents = [i for i in range(n + 1)]
#         self.ranks = [0 for i in range(n + 1)]
        
#     def find(self, u):
#         if u != self.parents[u]:
#             self.parents[u] = self.find(self.parents[u])            
#         return self.parents[u]
    
#     def union(self, u, v):
#         pu = self.find(u)
#         pv = self.find(v)
#         if pu == pv: return False
        
#         if self.ranks[pu] < self.ranks[pv]:
#             self.parents[pu] = pv
#         elif self.ranks[pu] > self.ranks[pv]:
#             self.parents[pv] = pu
#         else:
#             self.parents[pu] = pv
#             self.ranks[pv] += 1
            
#         return True


# class Solution:
#     def minCostConnectPoints(self, points: List[List[int]]) -> int:
#         n = len(points)
#         edges = []
#         for i in range(n):
#             for j in range(i + 1, n):
#                 edges.append([abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]), i, j])
#         edges.sort()
#         ans = 0
#         count = 0
#         uf = UnionFindSet(n)
#         for e in edges:
#             if not uf.union(e[1], e[2]): continue
#             ans += e[0]
#             count += 1
#             if count == n - 1: return ans
            
#         return ans
        

# Prim's
# my time: O(n ^ 2)
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def dist(p1, p2):
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        n = len(points)
        ds = [float('inf') for _ in range(n)]
        for i in range(1, n):
            ds[i] = dist(points[0], points[i])
        
        ans = 0
        for i in range(1, n):
            v = ds.index(min(ds))
            ans += ds[v]
            ds[v] = float('inf')
            for i in range(n):
                if ds[i] == float('inf'): continue
                ds[i] = min(ds[i], dist(points[i], points[v]))
                
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        heap=[]
        union_find=dict()
        for i in range(len(points)):
            union_find[i]=i
            for j in range(i+1,len(points)):
                heapq.heappush(heap,(abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1]),i,j))
        
        def find_set(node,ufo):
            if ufo[node]==node:
                return node
            else:
                return find_set(ufo[node],ufo)
        
        cost=0
        n=0
        while heap:
            currEdge=heapq.heappop(heap)
            left_root=find_set(currEdge[1],union_find)
            right_root=find_set(currEdge[2],union_find)
            if left_root!=right_root:
                cost+=currEdge[0]
                n+=1
                if n==(len(points)-1):
                    break
                union_find[left_root]=right_root
        
        return cost
            


# # Kruskal
# # O(n ^ 2)
# class UnionFindSet:
#     def __init__(self, n):
#         self.parents = [i for i in range(n + 1)]
#         self.ranks = [0 for i in range(n + 1)]
        
#     def find(self, u):
#         if u != self.parents[u]:
#             self.parents[u] = self.find(self.parents[u])            
#         return self.parents[u]
    
#     def union(self, u, v):
#         pu = self.find(u)
#         pv = self.find(v)
#         if pu == pv: return False
        
#         if self.ranks[pu] < self.ranks[pv]:
#             self.parents[pu] = pv
#         elif self.ranks[pu] > self.ranks[pv]:
#             self.parents[pv] = pu
#         else:
#             self.parents[pu] = pv
#             self.ranks[pv] += 1
            
#         return True


# class Solution:
#     def minCostConnectPoints(self, points: List[List[int]]) -> int:
#         n = len(points)
#         edges = []
#         for i in range(n):
#             for j in range(i + 1, n):
#                 edges.append([abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]), i, j])
#         edges.sort()
#         ans = 0
#         count = 0
#         uf = UnionFindSet(n)
#         for e in edges:
#             if not uf.union(e[1], e[2]): continue
#             ans += e[0]
#             count += 1
#             if count == n - 1: return ans
            
#         return ans
        
        
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def dist(p1, p2):
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        n = len(points)
        ds = [float('inf') for _ in range(n)]
        for i in range(1, n):
            ds[i] = dist(points[0], points[i])
        
        ans = 0
        for i in range(1, n):
            v = ds.index(min(ds))
            ans += ds[v]
            ds[v] = float('inf')
            for i in range(n):
                if ds[i] == float('inf'): continue
                ds[i] = min(ds[i], dist(points[i], points[v]))
                
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        res = 0
        n = len(points)
        mst = [False]*n
        dist = [None]*n       
        i = 0
        dist[i] = 0
        mst[i] = True
        for _ in range(n - 1):
            min_dist = None
            next_i = None
            for j in range(n):
                if not mst[j]:
                    cur_dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                    if dist[j] is None:
                        dist[j] = cur_dist
                    elif dist[j] > cur_dist:
                        dist[j] = cur_dist
                    if min_dist is None or min_dist > dist[j]:
                        min_dist = dist[j]
                        next_i = j
            i = next_i
            res += dist[i]
            mst[i] = True
        return res


import heapq
class UnionFind:
    def __init__(self, n):
        self.parent = list(range(n+1))
        self.rank = [0]*(n+1)
    
    def find(self, x):
        if x!=self.parent[x]:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def union(self, x, y):
        px = self.find(x)
        py = self.find(y)
        if px==py:
            return False
        if self.rank[px]>self.rank[py]:
            self.parent[py] = px
        elif self.rank[px]<self.rank[py]:
            self.parent[px] = py
        else:
            self.parent[px] = py
            self.rank[px] += 1
        return True
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        l = len(points)
        if l == 1:
            return 0
        u = UnionFind(l)
        li = []
        c = 0
        ans = 0
        for i in range(l):
            for j in range(i+1,l):
                v = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                li.append((v,i,j))
        heapq.heapify(li)
        #li.sort(key = lambda x:x[2])
        while li:
            p = heapq.heappop(li)
            if u.find(p[1]) != u.find(p[2]):
                u.union(p[1],p[2])
                c = c + 1
                ans = ans + p[0]
            if c == l - 1:
                return ans
                


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # turns out sorted + union find is the best
        # but makes sense to write union find using nonlocal as they are less
        # likely to TLE

        n = len(points)
        edges = []
        for i in range(n-1):
            for j in range(i+1,n):
                d = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((d, i, j))
                
        cost = 0
        found = 0
        parents = list(range(n))
        
        def find(a):
            while a != parents[a]:
                a, parents[a] = parents[a], parents[parents[a]]
            return a
        
        def union(a, b):
            parents[find(a)] = find(b)
        
        for c, a, b in sorted(edges):
            if find(a) != find(b):
                union(a,b)
                found += 1
                cost += c
                
            if found == n-1:
                break
        
        return cost

class DSU:
    def __init__(self, length):
        self.storage = [x for x in range(length)]
        self.rank = [0] * length
    
    def find(self, val):
        return self.find(self.storage[val]) if val != self.storage[val] else val
    
    def union(self, val1, val2):
        place_1 = self.find(val1)
        place_2 = self.find(val2)
        if self.rank[place_1] > self.rank[place_2]:
            self.storage[place_2] = self.storage[place_1]
        elif self.rank[place_2] > self.rank[place_1]:
            self.storage[place_1] = self.storage[place_2]
        else:
            self.rank[place_1] += 1
            self.storage[place_2] = self.storage[place_1]


class Solution:
    def distance(self, p1, p2):
        return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])

    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        possible_pairs = [] # (from, to, distance)
        n = len(points)
        for i in range(n):
            for j in range(i+1, n):
                possible_pairs.append((i, j, self.distance(points[i], points[j])))

        possible_pairs.sort(key=lambda x: x[2])

        result = 0
        index = 0
        count = 0
        dsu = DSU(n)
        while index < len(possible_pairs) and count != n - 1:
            f, to, d = possible_pairs[index]
            
            x = dsu.find(f)
            y = dsu.find(to)
            
            if x != y:
                count += 1
                dsu.union(x, y)
                result += d

            index += 1
        
        return result


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        adj = [[inf for _ in range(n)] for _ in range(n)]
        for i in range(n):
            for j in range(i+1, n):
                adj[i][j] = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                adj[j][i] = adj[i][j]
        selected = [False for _ in range(n)]
        min_edges = [[inf, -1] for _ in range(n)]
        min_edges[0][0] = 0
        total = 0
        for i in range(n):
            v = -1
            for j in range(n):
                if not selected[j] and (v == -1 or min_edges[j][0] < min_edges[v][0]):
                    v = j
            selected[v] = True
            total += min_edges[v][0]
            for to in range(n):
                if adj[v][to] < min_edges[to][0]:
                    min_edges[to][0] = adj[v][to]
        return total

class Solution:
    def minCostConnectPoints(self, points: list(list())) -> int:
        n = len(points)
        if len(points) == 1: return 0
        res = 0
        curr = 0  # select a random point as the starting point
        dis = [float('inf')] * n
        explored = set()

        for i in range(n - 1):
            x0, y0 = points[curr]
            explored.add(curr)
            for j, (x, y) in enumerate(points):
                if j in explored: continue
                dis[j] = min(dis[j], abs(x - x0) + abs(y - y0))

            delta, curr = min((d, j) for j, d in enumerate(dis))
            dis[curr] = float('inf')
            res += delta

        return int(res)

import heapq

class DisjointSet:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [1 for _ in range(n)]
    
    # make a and b part of the same component
    # union by rank optimization
    def union(self, a, b):
        pa = self.find(a)
        pb = self.find(b)
        if pa == pb: return
        if self.rank[pa] > self.rank[pb]:
            self.parent[pb] = pa
            self.rank[pa] += self.rank[pb]
        else:
            self.parent[pa] = pb
            self.rank[pb] += self.rank[pa]
    
    # find the representative of the 
    # path compression optimization
    def find(self, a):
        if self.parent[a] == a:
            return a
        
        self.parent[a] = self.find(self.parent[a])
        return self.parent[a]

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def distance(u, v):
            dx = abs(u[0] - v[0])
            dy = abs(u[1] - v[1])
            return dx+dy
        
        n = len(points)
        if n == 1:
            return 0
        if n == 2:
            return distance(points[0], points[1])
        
        # # Method 1: Prim's Alg with Heap
        # d = {i:[] for i in range(n)}
        # for i in range(n):
        #     for j in range(i+1, n):
        #         dist = distance(points[i], points[j])
        #         d[i].append((dist, j))
        #         d[j].append((dist, i))
        # cost = 0
        # connected = 1
        # check = [True] + [False]*(n-1)
        # heap = d[0]
        # heapq.heapify(heap)
        # while connected < n:
        #     (dist, p) = heapq.heappop(heap)
        #     if not check[p]:
        #         cost += dist
        #         connected += 1
        #         check[p] = 1
        #         for pair in d[p]:
        #             heapq.heappush(heap, pair)
        # return cost
        
        # # Nethod 2: Another Implementation of Prim's Alg
        cost = 0
        curr = 0 # select a random point as the starting point
        dist = [float('inf')] * n
        explored = set()
        explored.add(0)
        cnt = 1
        while cnt < n:
            u = points[curr]
            for j, v in enumerate(points):
                if j in explored: 
                    continue
                else:
                    dist[j] = min(dist[j], distance(u,v))
            min_d, curr = min((d, j) for j, d in enumerate(dist)) 
            explored.add(curr)
            cnt += 1
            dist[curr] = float('inf')
            cost += min_d
        return cost
        
        # Method 3: Kruskal's Alg with Disjoint Set
        
        
        



class Solution:
    def find(self, parents, i):
        if parents[i] == -1:
            return i
        return self.find(parents, parents[i])
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n <= 1:
            return 0
        pairs = []
        for i in range(n):
            for j in range(i+1, n):
                pairs.append((i, j))
        
        def distance(i, j):
            p1, p2 = points[i], points[j]
            return abs(p1[0]-p2[0])+abs(p1[1]-p2[1])
        pairs = sorted(pairs, key=lambda pair: distance(pair[0], pair[1]))
        
        total = 0
        parents = [-1]*n
        countE = 0
        for pair in pairs:
            if countE >= n-1:
                break
            i, j = pair
            pi = self.find(parents, i)
            pj = self.find(parents, j)
            if pi == pj:
                continue
            
            parents[pi] = pj
            total += distance(i, j)
            countE += 1
        return total
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def main(arr):
            if len(arr) < 1:
                return 0
            node = 0
            answer = 0
            n = len(arr)
            visit = set()
            global_dist = [float('inf')] * n
            while n > 1 :
                cur_x, cur_y = arr[node]
                visit.add(node)
                
                for j in range(len(arr)):
                    if j in visit: continue
                    x,y = arr[j]
                    global_dist[j] = min(global_dist[j], abs(x-cur_x)+abs(y-cur_y))
                
                next_node = -1
                next_dist = float('inf')
                for idx,dist in enumerate(global_dist):
                    if dist < next_dist:
                        next_dist = dist
                        next_node = idx
                node = next_node        
                answer += next_dist
                
                global_dist[next_node] = float('inf')

                n -= 1

            return answer
        return main(points)

import heapq

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        total_cost = 0
        # any initial point can be chosen
        x1, y1 = points[0]

        # initially sort points by their distance to initial point
        cost_heap = []
        heapq.heapify(cost_heap)
        for x2, y2 in points[1:]:
            heapq.heappush(cost_heap, [abs(x1-x2) + abs(y1-y2), x2, y2])
        
        # then pop points and update costs since new point may be closer
        while cost_heap:
            cost, x1, y1 = heapq.heappop(cost_heap)
            total_cost += cost
            for i, [cost, x2, y2] in enumerate(cost_heap):
                cost_heap[i][0] = min(cost, abs(x1-x2) + abs(y1-y2))
            cost_heap.sort()
            
        return total_cost


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n_points = len(points)
        
        if n_points == 1: return 0
        
        res  = 0
        curr = 0 # select a random point as the starting point
        dist  = [math.inf] * n_points
        explored = set()
        
        for i in range(n_points - 1):
            x0, y0 = points[curr]
            explored.add(curr)
            for j, (x, y) in enumerate(points):
                if j in explored: 
                    continue
                
                dist[j] = min(dist[j], abs(x - x0) + abs(y - y0))
                
            delta, curr = min((d, j) for j, d in enumerate(dist)) 
            dist[curr]   = math.inf
            res += delta
            
        return res


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        graph = [[0 for _ in range(len(points))].copy() for _ in range(len(points))]
        
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                graph[i][j] = abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                graph[j][i] = graph[i][j]
        
        costs = 0
        visited = set()
        keys = [sys.maxsize]*len(points)
        parent = [0]*len(points)
        keys[0] = 0
        
        def minkey():
            ind = -1
            m = sys.maxsize
            for i in range(len(points)):
                if i not in visited and keys[i] < m:
                    m = keys[i]
                    ind = i
            return ind
        
        for _ in range(len(points)):
            x = minkey()
            visited.add(x)
            for i in range(len(points)):
                if graph[x][i] > 0 and i not in visited and keys[i] > graph[x][i]:
                    keys[i] = graph[x][i]
                    parent[i] = x
                    
        for i in range(len(points)):
            costs += graph[i][parent[i]]
            
        return costs
        
        
        
        
        


import heapq
from collections import defaultdict

class DSU():
    def __init__(self, par):
        self.par = par
        self.rank = defaultdict(int)

    def find(self, x):
        if x != self.par[x]:
            self.par[x] = self.find(self.par[x])
        return self.par[x]
    
    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        if xr == yr:
            return False
        elif self.rank[xr] > self.rank[yr]:
            self.par[yr] = xr
        elif self.rank[xr] < self.rank[yr]:
            self.par[xr] = yr
        else:
            self.par[xr] = yr
            self.rank[yr] += 1
        return True
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def dist(x,y):
            return abs(x[0]-y[0]) + abs(x[1]-y[1])
        
        if len(points) == 1:
            return 0
        edges = []
        heapq.heapify(edges)
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                heapq.heappush(edges, (dist(points[i], points[j]), points[i], points[j]))
                
        par = {(x,y): (x,y) for (x,y) in points}        
        dsu = DSU(par)
        
        total_len = 0
        count = 0
        while count < len(points) - 1:
            d, p1, p2 = heapq.heappop(edges)
            if dsu.union(tuple(p1), tuple(p2)):
                total_len += d
                count += 1
        
        return total_len

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        n = len(points)
        connected, dis = set(), [float(\"inf\")] * n
        
        res = 0
        cur = nxt = 0
        d = dis[0]
        
        for _ in range(n-1):
            
            connected.add(cur)
            xx, yy = points[cur]
            
            for j, (x, y) in enumerate(points):
                if j in connected: continue
                    
                dis[j] = min(dis[j], abs(x - xx) + abs(y - yy))
                
                if dis[j] < d:
                    nxt, d = j, dis[j]
            
            res += d
            cur = nxt
            d = float(\"inf\")
            
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) == 1:
            return 0
        n  = len(points)
        par = [i for i in range(n)]
        sze = [1] * n
        def dist(pi: List[int], pj: List[int]) -> int:
            x, y = pi
            a, b = pj        
            return abs(x - a) + abs(y - b)
        
        def find(i: int) -> int:
            if par[i] == i:
                return i
            return find(par[i])
        
        def union(i: int, j: int) -> int:
            par[i] = j
            sze[j] += sze[i]
            return sze[j]
            
        pq = []    
        
        for i in range(n):
            pi = points[i]
            for j in range(i + 1, n):
                pj = points[j]
                heapq.heappush(pq, (dist(pi, pj), i, j))
        ok = set()
        total = 0
        usize = 0
        while usize < len(points):
            cost, i, j = heapq.heappop(pq)        
            ri, rj = find(i), find(j)
            if ri != rj:
                usize = union(ri, rj)                
                ok.add(i)
                ok.add(j)
                total += cost   
                #print(total, i, j, usize)
        return total
                


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        if len(points) == 1:
            return 0
        
        costs = []
        
        for i in range(len(points)):
            for k in range(i+1, len(points)):
                x,y = points[i]
                xx, yy = points[k]
                costs.append((abs(x-xx)+abs(y-yy),i,k))
        
        costs.sort()
        
        dd = {x:x for x in range(len(points))}
        
        #print(costs)
        
        def merge(x,y,c):
            x,y = find(x), find(y)
            if x != y:
                dd[x] = y
                self.ans += c
                self.groups -= 1
        
        def find(x):
            if dd[x] != x:
                dd[x] = find(dd[x])
            return dd[x]
        
        self.groups = len(points)
        
        self.ans = 0
        
        for c,x,y in costs:
            merge(x,y,c)
            if self.groups == 1:
                return self.ans
                    


class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:
        def manhattan(x, y):
            return abs(x[0]-y[0]) + abs(x[1]-y[1])

        ans, n = 0, len(p)
        seen = set()
        vertices = [(0, (0, 0))]

        while len(seen) < n:
            # print(vertices, seen)
            w, (u, v) = heapq.heappop(vertices)            
            if u in seen and v in seen: continue
            ans += w
            seen.add(v)
            for j in range(n):
                if j not in seen and j!=v:
                    heapq.heappush(vertices, (manhattan(p[j], p[v]), (v, j)))

        return ans

class UnionFind:
    def __init__(self, n):
        self.parent = list(range(n))
        self.size = [1]*n
    
    def find(self, i):
        if self.parent[i] != i:
            self.parent[i] = self.find(self.parent[i])
        return self.parent[i]
    
    def union(self, i, j):
        pi = self.find(i)
        pj = self.find(j)
        if pi != pj:
            self.parent[max(pi, pj)] = min(pi, pj)
            self.size[min(pi, pj)] += self.size[max(pi, pj)]
            self.size[max(pi, pj)] = 0

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        distances = []
        for idx0 in range(n):
            i0, j0 = points[idx0]
            for idx1 in range(idx0+1, n):
                i1, j1 = points[idx1]
                dis = abs(i0-i1)+abs(j0-j1)
                distances.append([dis, idx0, idx1])
        # print(distances)
        heapq.heapify(distances)
        # print(distances)
        
        res = 0
        uf = UnionFind(n)
        while uf.size[0] < n:
            dis, idx0, idx1 = heapq.heappop(distances)
            if uf.find(idx0) != uf.find(idx1):
                # print(dis, idx0, idx1)
                res += dis
                uf.union(idx0, idx1)
        return res
                


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        costs = [[0 for _ in range(n)]for _ in range(n)]
        
        for i in range(n):
            for j in range(i+1, n):
                costs[i][j] = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                costs[j][i] = costs[i][j]
        
        parent = [-1 for _ in range(n)]
        keyval = [-1 for _ in range(n)]
        mst = [False for _ in range(n)]
        keyval[0] = 0
        
        for i in range(n):
            mini = -1
            u = -1
            
            for j in range(n):
                if mst[j]:
                    continue
                if keyval[j] == -1:
                    continue
                if mini == -1:
                    mini = keyval[j]
                    u = j
                elif mini != -1 and mini > keyval[j]:
                    mini = keyval[j]
                    u = j
            mst[u] = True
            for j in range(n):
                if j != u and not mst[j]:
                    if keyval[j] == -1 or keyval[j] > costs[u][j]:
                        keyval[j] = costs[u][j]
                        parent[j] = u
                        
        r = 0
        for i in range(1, n):
            r += costs[parent[i]][i]
        return r


import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        total_cost = 0
        # any initial point can be chosen
        x1, y1 = points.pop() 
        # then make a heap sorted by distance to that point
        
        cost_heap = []
        for x2, y2 in points:
            heapq.heappush(cost_heap, [abs(x1-x2) + abs(y1-y2), x2, y2])
        
        # pop off the points with the lowest distance
        # then see if any of the remaining points are closer to that new point than
        # the previous points had been, and update the heap
        while cost_heap:
            cost, x1, y1 = heapq.heappop(cost_heap)
            total_cost += cost
            for i, [cost, x2, y2] in enumerate(cost_heap):
                cost_heap[i][0] = min(cost, abs(x1-x2) + abs(y1-y2))
                
            # heapify runs in n time, and sort in n log n, however since it
            # should be mostly presorted, in practice it's probably very close
            # since timsort takes advantage of these \"runs\"
            
            heapq.heapify(cost_heap)
            
        return total_cost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if len(points) == 1: return 0
        res = 0
        curr = 0 # select a random point as the starting point
        dis = [math.inf] * n
        explored = set()
        
        for i in range(n - 1):
            x0, y0 = points[curr]
            explored.add(curr)
            for j, (x, y) in enumerate(points):
                if j in explored: continue
                dis[j] = min(dis[j], abs(x - x0) + abs(y - y0))
                
            delta, curr = min((d, j) for j, d in enumerate(dis)) 
            dis[curr] = math.inf
            res += delta
            
        return res


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        graph = [[0 for _ in range(len(points))].copy() for _ in range(len(points))]
        
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                graph[i][j] = abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                graph[j][i] = graph[i][j]
        
        costs = 0
        keys = [sys.maxsize]*len(points)
        parent = [0]*len(points)
        visited = parent.copy()
        keys[0] = 0
        
        def minkey():
            ind = -1
            m = sys.maxsize
            for i in range(len(points)):
                if visited[i] == 0 and keys[i] < m:
                    m = keys[i]
                    ind = i
            return ind
        
        for _ in range(len(points)):
            x = minkey()
            visited[x] = 1
            for i in range(len(points)):
                if graph[x][i] > 0 and visited[i] == 0 and keys[i] > graph[x][i]:
                    keys[i] = graph[x][i]
                    parent[i] = x
                    
        for i in range(len(points)):
            costs += graph[i][parent[i]]
            
        return costs
        
        
        
        
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if len(points) == 1: return 0
        res = 0
        curr = 0 # select a random point as the starting point
        dis = [math.inf] * n
        explored = set()
        
        for i in range(n - 1):
            x0, y0 = points[curr]
            explored.add(curr)
            for j, (x, y) in enumerate(points):
                if j in explored: continue
                dis[j] = min(dis[j], abs(x - x0) + abs(y - y0))
                
            delta, curr = min((d, j) for j, d in enumerate(dis)) 
            dis[curr] = math.inf
            res += delta
            
        return res
        
        



class DSU:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [0 for _ in range(n)]
        self.size = n
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    def union(self, x, y):
        xp, yp = self.find(x), self.find(y)
        if xp == yp:
            return False
        if self.rank[xp] < self.rank[yp]:
            self.parent[xp] = yp
        elif self.rank[xp] > self.rank[yp]:
            self.parent[yp] = xp
        else:
            self.parent[xp] = yp
            self.rank[yp] += 1
        self.size -= 1
        return True
    def getSize(self):
        return self.size
    
class Solution:
    import heapq
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        heap, n = [], len(points)
        for i in range(n):
            for j in range(i + 1, n):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                heapq.heappush(heap, (dist, (i, j)))
        dsu = DSU(n + 1)
        res, i, j = 0, 0, 0
        while heap:
            dist, (i, j) = heapq.heappop(heap)
            if dsu.union(i, j):
                res += dist
                if dsu.getSize() == 2:
                    return res
        return 0
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def minKey(keys, mstSet):
            min_value = float('+Inf') 
            for v in range(len(points)):
                if keys[v] < min_value and not mstSet[v]:
                    min_value = keys[v]
                    min_index = v
            return (min_index, min_value)
        
        def get_distance(u, v):
            return (abs(points[u][0] - points[v][0]) +
                abs(points[u][1] - points[v][1]))
        
        size, total = len(points), 0
        keys = [float('+Inf')] * size
        keys[0] = 0
        mstSet = [False] * size
        for i in range(size):
            (u, min_value) = minKey(keys, mstSet)
            total += min_value
            mstSet[u] = True
            for v in range(size):
                distance = get_distance(u, v)
                if (keys[v] > distance > 0 and mstSet[v] == False):
                    keys[v] = distance
        return total


class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:
        
        def manhattan(x, y):
            return abs(x[0]-y[0]) + abs(x[1]-y[1])
        
        ans, n = 0, len(p)
        seen = set()
        vertices = [(0, (0, 0))]
        
        while len(seen) < n:
            # print(vertices, seen)
            w, (u, v) = heapq.heappop(vertices)            
            if v in seen: continue
            ans += w
            seen.add(v)
            for j in range(n):
                if j not in seen and j!=v:
                    heapq.heappush(vertices, (manhattan(p[j], p[v]), (v, j)))
        return ans

class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:
        
        cur, N, ans = 0, len(p), 0
        dis = [float('inf')] * N
        seen = [False] * N
        
        for _ in range(N-1):
            x, y = p[cur]
            seen[cur] = True
            for j, (nx, ny) in enumerate(p):
                if seen[j]: continue
                dis[j] = min(dis[j], abs(nx-x)+abs(ny-y))

            d, cur = min((w, k) for k, w in enumerate(dis))
            dis[cur] = float('inf')
            ans += d
            
        return ans
            


class DSU:
    def __init__(self,n):
        self.parent = [i for i in range(n)]
        self.rank = [1 for i in range(n)]
        self.count = n
    
    def find(self,x):
        if x!=self.parent[x]:
            self.parent[x]=self.find(self.parent[x])
        return self.parent[x]
    
    def union(self,x,y):
        px = self.find(x)
        py = self.find(y)
        if px==py:
            return False
        self.count-=1
        if self.rank[x]>self.rank[y]:
            self.parent[py]=px
            self.rank[px]+=self.rank[py]
        else:
            self.parent[px]=py
            self.rank[py]+=self.rank[px]
        return True
                
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        edges = []
        for i in range(n):
            for j in range(i+1, n):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((dist, i, j))
        # print(edges)
        edges.sort()
        res = 0
        ds = DSU(n)
        for cost, u, v in edges:
            if ds.count==1:
                break
            if ds.union(u,v):
                res += cost
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def find(symbol):
            if(group_map.get(symbol) is None):
                group_map[symbol] = symbol
                return group_map[symbol]
            root = symbol
            while(root != group_map[root]):
                root = group_map[root]
            
            while(symbol != root):
                parent = group_map[symbol]
                group_map[symbol] = root
                symbol = parent
            
            return root
        
        def union(symbol1, symbol2):
            root1 = find(symbol1)
            root2 = find(symbol2)
            
            if(root1 == root2):
                return
            
            if(group_size.get(root1) is None):
                group_map[root1] = root1
                group_size[root1] = 1
            
            if(group_size.get(root2) is None):
                group_map[root2] = root2
                group_size[root2] = 1
            
            if(group_size[root1] < group_size[root2]):
                group_size[root2] += group_size[root1]
                group_map[root1] = root2
            else:
                group_size[root1] += group_size[root2]
                group_map[root2] = root1
                
        all_edges = []
        for i in range(0, len(points)):
            for j in range(i + 1, len(points)):
                all_edges.append((i, j, (abs(points[j][0] - points[i][0]) + abs(points[j][1] - points[i][1]))))
        
        all_edges.sort(key=lambda x: x[2])
        
        vertices = [i for i in range(0, len(points))]
        
        group_map = {}
        group_size = {}

        edge_count = 0
        edge_index = 0
        
        total_weight = 0
        
        while(edge_count < len(points) - 1):
            (node_1, node_2, weight) = all_edges[edge_index]
            edge_index += 1
            parent_1 = find(node_1)
            parent_2 = find(node_2)
            
            if(parent_1 != parent_2):
                edge_count += 1
                total_weight += weight
                union(parent_1, parent_2)
            
        return total_weight


from heapq import *
class Solution:
    def minCostConnectPoints(self, points):
        N = len(points)
        parent = [i for i in range(N)]
        def find(v):
            while parent[v] != parent[parent[v]]:
                parent[v] = parent[parent[v]]
            return parent[v]
        dist = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        heap, total_cost = [], 0
        for u in range(N-1):
            for v in range(u+1, N):
                heappush(heap, [dist(points[u], points[v]), u, v])
        while heap:
            cost, u, v = heappop(heap)
            pu, pv = find(u), find(v)
            if pu != pv:
                parent[pu] = pv
                N -= 1
                total_cost += cost
                if N == 0:
                    break
        return total_cost

    
    
    
    
    
    
    
    
from heapq import *
class Solution:
    def minCostConnectPoints(self, points):
        dist = lambda p1, p2: abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        N = len(points)
        parent = [i for i in range(N)]
        def find(v):
            while parent[v] != parent[parent[v]]:
                parent[v] = parent[parent[v]]
            return parent[v]
        heap = []
        for i in range(N-1):
            for j in range(i+1, N):
                heappush(heap, (dist(points[i], points[j]), i, j))
        res = 0
        while heap:
            d, u, v = heappop(heap)
            pu, pv = find(u), find(v)
            if pu != pv:
                parent[pu] = pv
                res += d
                N -= 1
                if N == 0:
                    break
        return res
            


class Solution:
    def minCostConnectPoints(self, points):
        manhattan = lambda a, b, x, y: abs(a-x)+abs(b-y)
        points = sorted(points, key=lambda x: abs(x[0])+abs(x[1]))
        connected = [points[0]]
        cost = 0
        points = list([[x[0], x[1], manhattan(connected[0][0], connected[0][1], x[0], x[1])] for x in points])
        while len(connected) <= len(points):
            minidx = None
            mindist = float('inf')
            for i in range(len(points)):
                x, y, dist = points[i]
                if dist < mindist:
                    mindist = dist
                    minidx = i
            mx, my, mdist = points.pop(minidx)
            cost += mdist
            for i in range(len(points)):
                x, y, dist = points[i]
                newdist = manhattan(x, y, mx, my)
                if newdist < dist:
                    points[i][2] = newdist
        return cost


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def manhattan(x, y):
            return abs(x[0]-y[0]) + abs(x[1]-y[1])
        
        ans, n = 0, len(points)
        seen = set()
        vertices = [(0, (0, 0))]
        
        while len(seen) < n:
            w, (u, v) = heapq.heappop(vertices)
            if v in seen: continue
            ans += w
            seen.add(v)
            for j in range(n):
                if j not in seen:
                    heapq.heappush(vertices, (manhattan(points[j], points[v]), (v, j)))
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def manhattan(x,y):
            return abs(x[0]-y[0])+abs(x[1]-y[1])
        
        ans, n = 0, len(points)
        seen = set()
        vertices = [(0,(0,0))]
        
        while len(seen) < n:
            w, (u,v) = heapq.heappop(vertices)
            if v in seen:
                continue
            ans += w
            seen.add(v)
            for j in range(n):
                if j not in seen and j != v:
                    heapq.heappush(vertices, (manhattan(points[j], points[v]), (v,j)))
        
        return ans
        
        
        
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:

        def minnode(vis): 
            mini = 999999999999
            x,y=0,0
        

            # Loop through all the values of 
            # the nodes which are not yet 
            # included in MST and find the 
            # minimum valued one. 
            # k=lambda u,v :u*1+v
            for u,v in points:
                if (vis[(u,v)] == False and dis[(u,v)] < mini): 
                    mini = dis[(u,v)]
                    x,y=u,v
                
            return (mini,x,y)
        
        def cal_cities_dis(x,y):
            dis={}
            vis={}
            for u,v in points:
                vis[(u,v)]=False
                dis[(u,v)]=abs(u-x)+abs(y-v)
            return vis,dis
        
        # Find the rest n-1 nodes of MST. 
        def dist(x,y,u,v):
            
            return abs(u-x)+abs(y-v)
        res=0
        n=len(points)
        
        vis,dis=cal_cities_dis(points[0][0],points[0][1])
        
        # print(vis,dis)
        for i in range(n ): 

            # First find out the minimum node 
            # among the nodes which are not yet 
            # included in MST. 
            c,u,v = minnode( vis) 
            res+=c
            # print(c,u,v)

            # Now the uth node is included in MST. 
            vis[(u,v)]=True

            # Update the values of neighbor 
            # nodes of u which are not yet 
            # included in MST. 
            for x,y in points:
                if ( vis[(x,y)] == False and dist(u,v,x,y)< dis[(x,y)]): 
                    
                    dis[(x,y)] = dist(u,v,x,y)
                
        return res


\t
\t


# This code is contributed by PranchalK 


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def manhattan(x, y):
            return abs(x[0]-y[0]) + abs(x[1]-y[1])
        
        ans, n = 0, len(points)
        seen = set()
        vertices = [(0, (0, 0))]
        
        while len(seen) < n:
            # print(vertices, seen)
            w, (u, v) = heapq.heappop(vertices)            
            if v in seen: continue
            ans += w
            seen.add(v)
            for j in range(n):
                if j not in seen and j!=v:
                    heapq.heappush(vertices, (manhattan(points[j], points[v]), (v, j)))
                    
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        import heapq
        if len(points) == 1:
            return 0
        heap = []
        group = {i:i for i in range(len(points))}
        for i in range(len(points)-1):
            for j in range(i+1,len(points)):
                heap.append([abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1]),i,j])
        edgeset = []
        heapq.heapify(heap)
        while len(set(group.values())) > 1:
            weight,s,e = heapq.heappop(heap)
            if group[s] != group[e]:
                v1 = group[s]
                v2 = group[e]
                for key,v in list(group.items()):
                    if v == v2:
                        group[key] = v1
                edgeset.append(weight)
        return sum(edgeset)
                


def manhattan(x, y):
    return abs(x[0] - y[0]) + abs(x[1]-y[1])

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # minimum spanning tree (subgraph that contains all vertices and is a tree)
        # Two disjoint subsets of vertices
        # must be connected to make Spanning Tree
        # this connection must be minimum
        mstSet = set() # all vertices in mst
        ans, n = 0, len(points)
        queue = [(0, (0, 0))]
        while len(mstSet) < n:
            # print(vertices, mstSet)
            weight, (u, v) = heapq.heappop(queue)
            if v in mstSet: continue
            ans += weight
            mstSet.add(v)
            for j in range(n):
                if j not in mstSet and j != v:
                    heapq.heappush(queue, (manhattan(points[j], points[v]), (v, j)))
        return ans

class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:

        def manhattan(x, y):
            return abs(x[0]-y[0]) + abs(x[1]-y[1])

        ans, n = 0, len(p)
        seen = set()
        vertices = [(0, (0, 0))] # (distance, (last_vertice, cur_vertice))

        while len(seen) < n:
            # print(vertices, seen)
            d, (u, v) = heapq.heappop(vertices)            
            if u in seen and v in seen: continue
            ans += d
            seen.add(v)
            for j in range(n):
                if j not in seen and j!=v:
                    heapq.heappush(vertices, (manhattan(p[j], p[v]), (v, j)))

        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        manhattan = lambda a, b, x, y: abs(a-x)+abs(b-y)
        points = sorted(points, key=lambda x: abs(x[0])+abs(x[1]))
        connected = [points[0]]
        cost = 0
        points = list([[x[0], x[1], manhattan(connected[0][0], connected[0][1], x[0], x[1])] for x in points])
        # print(points)
        while len(connected) <= len(points):
            minidx = None
            mindist = float('inf')
            for i in range(len(points)):
                x, y, dist = points[i]
                if dist < mindist:
                    mindist = dist
                    minidx = i
            mx, my, mdist = points.pop(minidx)
            cost += mdist
            for i in range(len(points)):
                x, y, dist = points[i]
                newdist = manhattan(x, y, mx, my)
                if newdist < dist:
                    points[i][2] = newdist
            # print(points, mindist, \"=\", mx,my)
        return cost


import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        total_cost = 0
        # any initial point can be chosen
        x1, y1 = points.pop() 
        # then make a heap sorted by distance to that point
        
        cost_heap = []
        heapq.heapify(cost_heap)
        for x2, y2 in points:
            heapq.heappush(cost_heap, [abs(x1-x2) + abs(y1-y2), x2, y2])
        
        while cost_heap:
            cost, x1, y1 = heapq.heappop(cost_heap)
            total_cost += cost
            for i, [cost, x2, y2] in enumerate(cost_heap):
                cost_heap[i][0] = min(cost, abs(x1-x2) + abs(y1-y2))
            cost_heap.sort()
            
        return total_cost

class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:

        def manhattan(x, y):
            return abs(x[0]-y[0]) + abs(x[1]-y[1])

        ans, n = 0, len(p)
        seen = set()
        vertices = [(0, (0, 0))]

        while len(seen) < n:
            # print(vertices, seen)
            w, (u, v) = heapq.heappop(vertices)            
            if u in seen and v in seen: continue
            ans += w
            seen.add(v)
            for j in range(n):
                if j not in seen and j!=v:
                    heapq.heappush(vertices, (manhattan(p[j], p[v]), (v, j)))

        return ans

class Solution(object):
    def minCostConnectPoints(self, points):
        \"\"\"
        :type points: List[List[int]]
        :rtype: int
        \"\"\"
        n = len(points)
        colors = list(range(n))
        sets = [[i] for i in range(n)]
        
        edges = []
        for i in range(n):
            for j in range(i):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((i, j, dist))
                
        edges.sort(key=lambda x: x[2])
        
        cost = 0
        for (x, y, d) in edges:
            if colors[x] == colors[y]:
                continue

            cost += d
            if len(sets[colors[x]]) < len(sets[colors[y]]):
                x, y = y, x

            #add y to x
            color_x = colors[x]
            color_y = colors[y]

            for node in sets[color_y]:
                colors[node] = color_x

            sets[color_x].extend(sets[color_y])

        return cost
        

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        n = len(points)
        if len(points) == 1: return 0
        res = 0
        curr = 0 # select a random point as the starting point
        dis = [math.inf] * n
        visited = set()
        
        for i in range(n - 1):
            x0, y0 = points[curr]
            visited.add(curr)
            for j, (x, y) in enumerate(points):
                if j in visited: 
                    continue
                dis[j] = min(dis[j], abs(x - x0) + abs(y - y0))
                
            delta, curr = float('inf'),float('inf')
            for j, d in enumerate(dis):
                delta, curr = min((delta, curr),(d, j)) 
            
            dis[curr] = math.inf
            res += delta
            
        return res



class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        ss = [(0,0)]
        n = len(points)
        inc = set()
        ans = 0
        while n:
            node = heapq.heappop(ss)
            if node[1] not in inc:
                ans+=node[0]
                p1 = points[node[1]]
                for i in range(len(points)):
                    if i!=node[1] and i not in inc:
                        p2 = points[i]
                        dist = abs(p1[0]-p2[0])+abs(p1[1]-p2[1])
                        heapq.heappush(ss,(dist,i))
                inc.add(node[1])
                n-=1
        return ans

class Node:
    def __init__(self,data,rank,node):        
        self.data = data
        self.rank = rank
        self.node = node            
        self.parent = self

class UnionFind(object):
    def __init__(self,n):
        self._parent = [0]*n
        self._size = [1]*n
        self.count = n
        for i in range(n):
            self._parent[i] = i
            
    def union(self, p, q):
        rootp = self.find(p)
        rootq = self.find(q)
        if rootp == rootq:
            return False
        self.count -= 1
        if self._size[rootp] > self._size[rootq]:
            self._size[rootp] += self._size[rootq]
            self._parent[rootq] = self._parent[q] = rootp
        else:
            self._size[rootq] += self._size[rootp]
            self._parent[rootp] = self._parent[p] = rootq
        return True
    
    def find(self, n):
        while self._parent[n] != n:
            self._parent[n] = self._parent[self._parent[n]]
            n = self._parent[n]
        return n
    
    def connected(self, p, q):
        return self.find(p) == self.find(q)
            

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def findManhattanDistance(p1,p2):            
            return abs(p1[0]-p2[0]) + abs(p1[1] - p2[1])
        
        edges = []        
        N = len(points)  
        for i in range(N):
            for j in range(i+1,N):
                edges.append([i,j,findManhattanDistance(points[i],points[j])])        
        edges.sort(key=lambda x:x[2])        
              
        hashMap = {}        
        for i in range(N):              
            hashMap[i] = Node(i,0,None)       
            
        uf = UnionFind(N)
        edge_count, costs = 0,0
        for u,v,w in edges:            
            if(uf.union(u,v)):        
                costs += w
                edge_count +=1
            if(edge_count == N - 1):
                break
        return costs

class UnionFind(object):
    def __init__(self,n):
        self._parent = [0]*n
        self._size = [1]*n
        self.count = n
        for i in range(n):
            self._parent[i] = i
            
    def union(self, p, q):
        rootp = self.find(p)
        rootq = self.find(q)
        if rootp == rootq:
            return False
        self.count -= 1
        if self._size[rootp] > self._size[rootq]:
            self._size[rootp] += self._size[rootq]
            self._parent[rootq] = self._parent[q] = rootp
        else:
            self._size[rootq] += self._size[rootp]
            self._parent[rootp] = self._parent[p] = rootq
        return True
    
    def find(self, n):
        while self._parent[n] != n:
            self._parent[n] = self._parent[self._parent[n]]
            n = self._parent[n]
        return n
    
    #def connected(self, p, q):
    #    return self.find(p) == self.find(q)
            

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def findManhattanDistance(p1,p2):            
            return abs(p1[0]-p2[0]) + abs(p1[1] - p2[1])
        
        edges = []        
        N = len(points)  
        for i in range(N):
            for j in range(i+1,N):
                edges.append([i,j,findManhattanDistance(points[i],points[j])])        
        edges.sort(key=lambda x:x[2])      
            
        uf = UnionFind(N)
        edge_count, costs = 0,0
        for u,v,w in edges:            
            if(uf.union(u,v)):        
                costs += w
                edge_count +=1
            if(edge_count == N - 1):
                break
        return costs

class Node:
    def __init__(self,data,node):        
        self.data = data
        self.node = node            
        self.parent = self

class UnionFind(object):
    def __init__(self,n):
        self._parent = [0]*n
        self._size = [1]*n
        self.count = n
        for i in range(n):
            self._parent[i] = i
            
    def union(self, p, q):
        rootp = self.find(p)
        rootq = self.find(q)
        if rootp == rootq:
            return False
        self.count -= 1
        if self._size[rootp] > self._size[rootq]:
            self._size[rootp] += self._size[rootq]
            self._parent[rootq] = self._parent[q] = rootp
        else:
            self._size[rootq] += self._size[rootp]
            self._parent[rootp] = self._parent[p] = rootq
        return True
    
    def find(self, n):
        while self._parent[n] != n:
            self._parent[n] = self._parent[self._parent[n]]
            n = self._parent[n]
        return n
    
    def connected(self, p, q):
        return self.find(p) == self.find(q)
            

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def findManhattanDistance(p1,p2):            
            return abs(p1[0]-p2[0]) + abs(p1[1] - p2[1])
        
        edges = []        
        N = len(points)  
        for i in range(N):
            for j in range(i+1,N):
                edges.append([i,j,findManhattanDistance(points[i],points[j])])        
        edges.sort(key=lambda x:x[2])      
            
        uf = UnionFind(N)
        edge_count, costs = 0,0
        for u,v,w in edges:            
            if(uf.union(u,v)):        
                costs += w
                edge_count +=1
            if(edge_count == N - 1):
                break
        return costs

class UnionFind(object):
    def __init__(self,n):
        self._parent = [0]*n
        self._size = [1]*n
        self.count = n
        for i in range(n):
            self._parent[i] = i
            
    def union(self, p, q):
        rootp = self.find(p)
        rootq = self.find(q)
        if rootp == rootq:
            return False
        self.count -= 1
        if self._size[rootp] > self._size[rootq]:
            self._size[rootp] += self._size[rootq]
            self._parent[rootq] = self._parent[q] = rootp
        else:
            self._size[rootq] += self._size[rootp]
            self._parent[rootp] = self._parent[p] = rootq
        return True
    
    def find(self, n):
        while self._parent[n] != n:
            self._parent[n] = self._parent[self._parent[n]]
            n = self._parent[n]
        return n
    
    #def connected(self, p, q):
    #    return self.find(p) == self.find(q)
            

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def findManhattanDistance(p1,p2):            
            return abs(p1[0]-p2[0]) + abs(p1[1] - p2[1])
        if not points: return 0
        edges = []        
        N = len(points)  
        for i in range(N):
            for j in range(i+1,N):
                edges.append([i,j,findManhattanDistance(points[i],points[j])])        
        edges.sort(key=lambda x:x[2])      
            
        uf = UnionFind(N)
        edge_count, costs = 0,0
        for u,v,w in edges:            
            if(uf.union(u,v)):        
                costs += w
                edge_count +=1
                if(edge_count == N - 1):
                    break
        return costs

class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:
        
        ans, N, heap = 0, len(p), [(0, (0, 0))]
        seen = set()
        
        while len(seen) < N:
            w, (u, v) = heapq.heappop(heap)
            if u in seen and v in seen: continue
            seen.add(v)
            ans += w
            for j, (nx, ny) in enumerate(p):
                if j not in seen and j!=v:
                    heapq.heappush(heap, (abs(nx-p[v][0])+abs(ny-p[v][1]), (v, j)))
        return ans

class UnionFind(object):
    def __init__(self,n):
        self._parent = [0]*n
        self._size = [1]*n
        self.count = n
        for i in range(n):
            self._parent[i] = i
            
    def union(self, p, q):
        rootp = self.find(p)
        rootq = self.find(q)
        if rootp == rootq:
            return False
        self.count -= 1
        if self._size[rootp] > self._size[rootq]:
            self._size[rootp] += self._size[rootq]
            self._parent[rootq] = self._parent[q] = rootp
        else:
            self._size[rootq] += self._size[rootp]
            self._parent[rootp] = self._parent[p] = rootq
        return True
    
    def find(self, n):
        while self._parent[n] != n:
            self._parent[n] = self._parent[self._parent[n]]
            n = self._parent[n]
        return n
    
    def connected(self, p, q):
        return self.find(p) == self.find(q)
            

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def findManhattanDistance(p1,p2):            
            return abs(p1[0]-p2[0]) + abs(p1[1] - p2[1])        
        edges = []        
        N = len(points)  
        if N < 2: return 0
        for i in range(N):
            for j in range(i+1,N):
                edges.append([i,j,findManhattanDistance(points[i],points[j])])        
        edges.sort(key=lambda x:x[2])      
            
        uf = UnionFind(N)
        edge_count, costs = 0,0
        for u,v,w in edges:            
            if(uf.union(u,v)):        
                costs += w
                edge_count +=1
                if(edge_count == N - 1):
                    break
        return costs

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        result = 0
        m = 0
        q = [(0, 0, 0)]
        visited = [0] * n
        dis = [10 ** 9] * n
        dis[0] = 0
        while m < n:
            w, j, i = heapq.heappop(q)
            # print(j, i, w)
            if visited[i]:
                continue
            visited[i] = 1
            for j in range(n):
                if j == i or visited[j]:
                    continue
                ww = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                if ww < dis[j]:
                    dis[j] = ww
                    heapq.heappush(q, (ww, i, j))
            m += 1
            result += w
        return result

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        dist = [[-1 for _ in points] for _ in points]
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                d = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                dist[i][j] = d
                dist[j][i] = d
        if not points or len(points) <= 1:
            return 0
        connected = [False for _ in points]
        min_cost_pq = []
        connected[0] = True
        connected_count = 1
        res = 0
        for j in range(1, len(points)):
            heapq.heappush(min_cost_pq, (dist[0][j], j))
        while connected_count < len(points):
            d, i = heapq.heappop(min_cost_pq)
            if connected[i]:
                continue
            res += d
            connected[i] = True
            connected_count += 1
            for j in range(len(points)):
                if not connected[j]:
                    heapq.heappush(min_cost_pq, (dist[i][j], j))
        return res


class UnionFind(object):
    def __init__(self,n):
        self._parent = [0]*n
        self._size = [1]*n
        self.count = n
        for i in range(n):
            self._parent[i] = i
            
    def union(self, p, q):
        rootp = self.find(p)
        rootq = self.find(q)
        if rootp == rootq:
            return False
        self.count -= 1
        if self._size[rootp] > self._size[rootq]:
            self._size[rootp] += self._size[rootq]
            self._parent[rootq] = self._parent[q] = rootp
        else:
            self._size[rootq] += self._size[rootp]
            self._parent[rootp] = self._parent[p] = rootq
        return True
    
    def find(self, n):
        while self._parent[n] != n:
            self._parent[n] = self._parent[self._parent[n]]
            n = self._parent[n]
        return n
    
    #def connected(self, p, q):
    #    return self.find(p) == self.find(q)
            

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def findManhattanDistance(p1,p2):            
            return abs(p1[0]-p2[0]) + abs(p1[1] - p2[1])
        
        edges = []        
        N = len(points)  
        for i in range(N):
            for j in range(i+1,N):
                edges.append([i,j,findManhattanDistance(points[i],points[j])])        
        edges.sort(key=lambda x:x[2])      
            
        uf = UnionFind(N)
        edge_count, costs = 0,0
        for u,v,w in edges:            
            if(uf.union(u,v)):        
                costs += w
                edge_count +=1
                if(edge_count == N - 1):
                    break
        return costs

import numpy as np
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        
        numNode=len(points)
        if numNode==1:
            return 0
        
        
        totalCost=0
        current=0
        distance=[math.inf]*numNode
        explored=set()
        
        for i in range(numNode-1):
            x0,y0 = points[current]
            explored.add(current)
            
            for j , (x,y) in enumerate(points):
                if j in explored:
                    continue
                distance[j]=min(distance[j],abs(x0-x)+abs(y0-y))
        
            cost , current = min((c, index) for index, c in enumerate(distance))
            distance[current]=math.inf
            totalCost+=cost
        
        return totalCost



class UnionFind(object):
    def __init__(self,n):
        self._parent = [0]*n
        self._size = [1]*n
        self.count = n
        for i in range(n):
            self._parent[i] = i
            
    def union(self, p, q):
        rootp = self.find(p)
        rootq = self.find(q)
        if rootp == rootq:
            return False
        self.count -= 1
        if self._size[rootp] > self._size[rootq]:
            self._size[rootp] += self._size[rootq]
            self._parent[rootq] = self._parent[q] = rootp
        else:
            self._size[rootq] += self._size[rootp]
            self._parent[rootp] = self._parent[p] = rootq
        return True
    
    def find(self, n):
        while self._parent[n] != n:
            self._parent[n] = self._parent[self._parent[n]]
            n = self._parent[n]
        return n
    
    #def connected(self, p, q):
    #    return self.find(p) == self.find(q)
            

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def findManhattanDistance(p1,p2):            
            return abs(p1[0]-p2[0]) + abs(p1[1] - p2[1])
        
        edges = []        
        N = len(points)  
        if N < 2: return 0
        for i in range(N):
            for j in range(i+1,N):
                edges.append([i,j,findManhattanDistance(points[i],points[j])])        
        edges.sort(key=lambda x:x[2])      
            
        uf = UnionFind(N)
        edge_count, costs = 0,0
        for u,v,w in edges:            
            if(uf.union(u,v)):        
                costs += w
                edge_count +=1
                if(edge_count == N - 1):
                    break
        return costs

import heapq

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        #solution with Prim's algorithm
        #start from a random node idx 0, use heap to store distance between two nodes and the nodes, calculate distances for node's haven't visited, put in heap. Next node we'll process is the one with shortest distance from previous, continue until all nodes are visited
        def manhattan(p1, p2):
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        
        res, n = 0, len(points)
        verticles = [(0, (0, 0))]
        visited = set()
        
        while len(visited) < n:
            d, (pre, cur) = heapq.heappop(verticles)
            if cur in visited:  continue
            res += d
            visited.add(cur)
            for nxt in range(n):
                if nxt not in visited and nxt != cur:
                    heapq.heappush(verticles, (manhattan(points[cur], points[nxt]), (cur, nxt)))
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def getCost(a, b):
            return abs(a[0] - b[0]) + abs(a[1] - b[1])
        
        res, N = 0, len(points)
        seen = set()
        vertices = [(0, (0, 0))]
        
        while len(seen) < N:
            w, (u, v) = heapq.heappop(vertices)
            if v in seen: continue
            res += w
            seen.add(v)
            for j in range(N):
                if j not in seen and j != v:
                    heapq.heappush(vertices, (getCost(points[v], points[j]), (v, j)))
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:

        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        
        ans, n = 0, len(points)
        seen = set()
        vertices = [(0, (0, 0))] # [(dist, ( , index)]
        # first zero is distance, middle zero is dummy value, last zero is next vertice. 
        # so ai point (0, 0) the heap will add the edges[0], and ans += 0.

        while len(seen) < n:
            w, (u, v) = heapq.heappop(vertices)            
            if v in seen: continue
            ans += w
            seen.add(v)
            for j in range(n):
                if j not in seen and j!=v:
                    heapq.heappush(vertices, (manhattan(points[j], points[v]), (v, j)))    
        return ans
    \"\"\"
            # select random start point
        # find the node that 1) search all possible route costs least 2) not generate a loop 3) among the ones that are not selected 
        if len(points) <= 1: return 0
        visited = [(points[0][0], points[0][1])]
        mustgo = points[1:]
        cost = 0
        while mustgo:
            route = dict()
            for p in visited:
                for m in mustgo:
                    if (m[0], m[1]) in route.keys():
                        route[(m[0], m[1])] = min(abs(p[0] - m[0]) + abs(p[1] - m[1]), route[(m[0], m[1])])
                    else:
                        route[(m[0], m[1])] = abs(p[0] - m[0]) + abs(p[1] - m[1])
            for k, v in route.items():
                if v == min(route.values()):
                    cost += v                    
                    visited.append(k)
                    mustgo.remove([k[0],k[1]])
        print((visited))
        return cost
    \"\"\"

class Solution:
            
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def func(x,y):
            return abs(x[0]-y[0])+abs(x[1]-y[1])
        
        ans=0
        n=len(points)
        print(n)
        s=set()
        ver=[(0,(0,0))]
        while len(s)<n:
            res,(v1,v2)=heapq.heappop(ver)
            if v1 in s and v2 in s:
                continue
                
            
            ans+=res
            s.add(v2)

            for i in range(n):
                if i not in s and i!=v2:
                    sol=func(points[i],points[v2])
                    heapq.heappush(ver,(sol,(v2,i)))
        return ans
        
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        visited = [False] * len(points)
        count = 0
        distance = [[0]*len(points) for p in points]
        for i in range(len(points)):
            for j in range(len(points)):
                distance[i][j] = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                #distance[j][i] = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])

        cost = 0
        visited[0] = True
        n = len(points)
        close = [1<<29]*n
        for i in range(1,n):
            close[i] = distance[0][i]
            
        for k in range(n-1):
            minCost = 1<<29
            v = None
            for i in range(n):
                if not visited[i] and minCost>close[i]:
                    v = i
                    minCost = close[i]
                    
            cost += minCost
            visited[v] = True
            for i in range(n):
                if not visited[i]:
                    close[i] = min(close[i],distance[v][i])
        return cost
        # return res           
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        result = 0
        m = 0
        q = [(0, 0)]
        visited = [0] * n
        dis = [10 ** 9] * n
        dis[0] = 0
        while m < n:
            w, i = heapq.heappop(q)
            # print(j, i, w)
            if visited[i]:
                continue
            visited[i] = 1
            for j in range(n):
                if j == i or visited[j]:
                    continue
                ww = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                if ww < dis[j]:
                    dis[j] = ww
                    heapq.heappush(q, (ww, j))
            m += 1
            result += w
        return result

# class Solution:
#     def minCostConnectPoints(self, points: List[List[int]]) -> int:
#         manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
#         n, c = len(points), collections.defaultdict(list)
#         for i in range(n):
#             for j in range(i+1, n):
#                 d = manhattan(points[i], points[j])
#                 c[i].append((d, j))
#                 c[j].append((d, i))
#         cnt, ans, visited, heap = 1, 0, [0] * n, c[0]
#         visited[0] = 1
#         heapq.heapify(heap)
#         while heap:
#             d, j = heapq.heappop(heap)
#             if not visited[j]:
#                 visited[j], cnt, ans = 1, cnt+1, ans+d
#                 for record in c[j]: heapq.heappush(heap, record)
#             if cnt >= n: break        
#         return ans

class DisjointSet:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [1 for _ in range(n)]
    
    # make a and b part of the same component
    # union by rank optimization
    def union(self, a, b):
        pa = self.find(a)
        pb = self.find(b)
        if pa == pb: return
        if self.rank[pa] > self.rank[pb]:
            self.parent[pb] = pa
            self.rank[pa] += self.rank[pb]
        else:
            self.parent[pa] = pb
            self.rank[pb] += self.rank[pa]
    
    # find the representative of the 
    # path compression optimization
    def find(self, a):
        if self.parent[a] == a:
            return a
        
        self.parent[a] = self.find(self.parent[a])
        return self.parent[a]
    

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        n = len(points)
        edges = []
        for i in range(n):
            for j in range(i+1, n):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((dist, i, j))
        
        # sort based on cost (i.e. distance)
        edges.sort()
        
        # using Kruskal's algorithm to find the cost of Minimum Spanning Tree
        res = 0
        ds = DisjointSet(n)
        cnt = 0
        for cost, u, v in edges:
            if ds.find(u) != ds.find(v):
                ds.union(u, v)
                res += cost
                cnt += 1
            if cnt == len(points) -1:
                break
        return res

class Node:
    def __init__(self,data,rank,node):        
        self.data = data
        self.rank = rank
        self.node = node
        
class UnionFind(object):
    def __init__(self,n):
        self._parent = [0]*n
        self._size = [1]*n
        self.count = n
        for i in range(n):
            self._parent[i] = i
            
    def union(self, p, q):
        rootp = self.find(p)
        rootq = self.find(q)
        if rootp == rootq:
            return
        self.count -= 1
        if self._size[rootp] > self._size[rootq]:
            self._size[rootp] += self._size[rootq]
            self._parent[rootq] = self._parent[q] = rootp
        else:
            self._size[rootq] += self._size[rootp]
            self._parent[rootp] = self._parent[p] = rootq
    
    def find(self, n):
        while self._parent[n] != n:
            self._parent[n] = self._parent[self._parent[n]]
            n = self._parent[n]
        return n
    
    def connected(self, p, q):
        return self.find(p) == self.find(q)
            

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def findManhattanDistance(p1,p2):            
            return abs(p1[0]-p2[0]) + abs(p1[1] - p2[1])
        
        edges = []        
        for i,p1 in enumerate(points):
            for j in range(i+1,len(points)):                
                edges.append([i,j,findManhattanDistance(p1,points[j])])                
        
        edges = sorted(edges,key=lambda x:x[2])        
        N = len(points)        
        hashMap = {}        
        for i in range(N):            
            node = Node(i,0,None)
            node.parent = node            
            hashMap[node.data] = node
        
        
        def Union(data1,data2):
            
            node1 = hashMap[data1]
            node2 = hashMap[data2]
            
            p1 = findSet(node1)
            p2 = findSet(node2)
            
            if(p1 == p2):
                return False            
        
            if(p1.rank >= p2.rank):
                p1.rank = p1.rank + 1 if(p1.rank == p2.rank) else p1.rank                
                p2.parent = p1                
            else:
                p1.parent = p2            
            return True        
        
        
        def findSet(node):
            while (node.parent != node):
                node.parent = node.parent.parent
                node = node.parent            
            return node.parent
        

        edge_count = 0
        costs = 0
        
        for u,v,w in edges:
            
            if(Union(u,v)):
                costs += w
                edge_count +=1
                
                
            if(edge_count == N - 1):
                break
                    
        
        return costs

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        import heapq
        
        connect = list(range(N))
        def find(x):
            if connect[x]!=x:
                connect[x] = find(connect[x])
            return connect[x]
        
        def union(x, y):
            if find(x)!=find(y):
                connect[find(x)] = find(y)
        
        
        q = []
        for i in range(N):
            for j in range(i):
                w = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                q.append((w, i, j))
        q.sort()
        
        res = 0
        cnt = 0
        for w, i, j in q:
            if cnt == N-1:
                break
            if find(i) == find(j):
                continue
            else:
                res += w
                union(i, j)
                cnt += 1
        
        return res
                
        
        


class Node:
    def __init__(self,data,rank,node):        
        self.data = data
        self.rank = rank
        self.node = node            

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def findManhattanDistance(p1,p2):            
            return abs(p1[0]-p2[0]) + abs(p1[1] - p2[1])
        
        edges = []        
        for i,p1 in enumerate(points):
            for j in range(i+1,len(points)):                
                edges.append([i,j,findManhattanDistance(p1,points[j])])                
        
        edges = sorted(edges,key=lambda x:x[2])        
        N = len(points)        
        hashMap = {}        
        for i in range(N):            
            node = Node(i,0,None)
            node.parent = node            
            hashMap[node.data] = node
        
        
        def Union(data1,data2):            
            node1 = hashMap[data1]
            node2 = hashMap[data2]
            
            p1 = findSet(node1)
            p2 = findSet(node2)
            
            if(p1 == p2):
                return False            
        
            if(p1.rank >= p2.rank):
                p1.rank = p1.rank + 1 if(p1.rank == p2.rank) else p1.rank                
                p2.parent = p1                
            else:
                p1.parent = p2            
            return True        
        
        
        def findSet(node):
            while (node.parent != node):
                node.parent = node.parent.parent
                node = node.parent            
            return node.parent        
        
        edge_count = 0
        costs = 0        
        for u,v,w in edges:            
            if(Union(u,v)):        
                costs += w
                edge_count +=1
            if(edge_count == N - 1):
                break
        return costs

class Node:
    def __init__(self,data,rank,node):        
        self.data = data
        self.rank = rank
        self.node = node            

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def findManhattanDistance(p1,p2):            
            return abs(p1[0]-p2[0]) + abs(p1[1] - p2[1])
        
        edges = []        
        for i,p1 in enumerate(points):
            for j in range(i+1,len(points)):                
                edges.append([i,j,findManhattanDistance(p1,points[j])])                
        
        edges = sorted(edges,key=lambda x:x[2])        
        N = len(points)        
        hashMap = {}        
        for i in range(N):            
            node = Node(i,0,None)
            node.parent = node            
            hashMap[node.data] = node
        
        
        def Union(data1,data2):            
            node1 = hashMap[data1]
            node2 = hashMap[data2]
            
            p1 = findSet(node1)
            p2 = findSet(node2)
            
            if(p1 == p2):
                return False            
        
            if(p1.rank > p2.rank):
                p1.rank = p1.rank + p2.rank
                p2.parent = p1                
            else:
                p2.rank = p2.rank + p1.rank
                p1.parent = p2            
            return True        
        
        
        def findSet(node):
            while (node.parent != node):
                node.parent = node.parent.parent
                node = node.parent            
            return node.parent        
        
        edge_count = 0
        costs = 0        
        for u,v,w in edges:            
            if(Union(u,v)):        
                costs += w
                edge_count +=1
            if(edge_count == N - 1):
                break
        return costs

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        ans = 0
        current_point_index = 0
        visited_point_indeces = set()
        distance_list = [float('inf')] * len(points)
        
        for i in range(len(points) - 1):
            visited_point_indeces.add(current_point_index)
            
            for j in range(len(points)):
                if j in visited_point_indeces: continue
                    
                x, y = points[current_point_index]
                x0, y0 = points[j]
                
                distance_list[j] = min(distance_list[j], abs(y0 - y) + abs(x0 - x))
                
            distance_list[current_point_index] = float('inf')
            delta, current_point_index = min([distance, index] for index, distance in enumerate(distance_list))
            ans += delta
            
        return ans


class Node:
    def __init__(self,data,rank,node):        
        self.data = data
        self.rank = rank
        self.node = node            
        self.parent = self

class UnionFind(object):
    def __init__(self,n):
        self._parent = [0]*n
        self._size = [1]*n
        self.count = n
        for i in range(n):
            self._parent[i] = i
            
    def union(self, p, q):
        rootp = self.find(p)
        rootq = self.find(q)
        if rootp == rootq:
            return False
        self.count -= 1
        if self._size[rootp] > self._size[rootq]:
            self._size[rootp] += self._size[rootq]
            self._parent[rootq] = self._parent[q] = rootp
        else:
            self._size[rootq] += self._size[rootp]
            self._parent[rootp] = self._parent[p] = rootq
        return True
    
    def find(self, n):
        while self._parent[n] != n:
            self._parent[n] = self._parent[self._parent[n]]
            n = self._parent[n]
        return n
    
    def connected(self, p, q):
        return self.find(p) == self.find(q)
            

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def findManhattanDistance(p1,p2):            
            return abs(p1[0]-p2[0]) + abs(p1[1] - p2[1])
        
        edges = []        
        N = len(points)  
        for i,p1 in enumerate(points):
            for j in range(i+1,N):                
                edges.append([i,j,findManhattanDistance(p1,points[j])])                
        
        edges = sorted(edges,key=lambda x:x[2])        
              
        hashMap = {}        
        for i in range(N):            
            node = Node(i,0,None)                     
            hashMap[node.data] = node       
            
        uf = UnionFind(N)
        edge_count = 0
        costs = 0        
        for u,v,w in edges:            
            if(uf.union(u,v)):        
                costs += w
                edge_count +=1
            if(edge_count == N - 1):
                break
        return costs

class Node:
    
    
    def __init__(self,data,rank,node):
        
        self.data = data
        self.rank = rank
        self.node = node
        

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def findManhattanDistance(p1,p2):
            
            
            return abs(p1[0]-p2[0]) + abs(p1[1] - p2[1])

        
        
        
        
        
        edges = []
        
        
        
        for i,p1 in enumerate(points):
            for j in range(i+1,len(points)):
                
                edges.append([i,j,findManhattanDistance(p1,points[j])])
                
        
        edges = sorted(edges,key=lambda x:x[2])
        
        N = len(points)
        
        hashMap = {}
        
        for i in range(N):
            
            node = Node(i,0,None)
            node.parent = node
            
            hashMap[node.data] = node
        
        
        
        
        def Union(data1,data2):
            
            node1 = hashMap[data1]
            node2 = hashMap[data2]
            
            p1 = findSet(node1)
            p2 = findSet(node2)
            
            if(p1 == p2):
                return False
            
        
            if(p1.rank >= p2.rank):
                p1.rank = p1.rank + 1 if(p1.rank == p2.rank) else p1.rank
                
                p2.parent = p1
                
            else:
                p1.parent = p2
                
            
            return True
        
        
        
        def findSet(node):
            
            if(node.parent == node):
                return node
            
            node.parent = findSet(node.parent)
            
            return node.parent
        

        edge_count = 0
        costs = 0
        
        for u,v,w in edges:
            
            if(Union(u,v)):
                costs += w
                edge_count +=1
                
                
            if(edge_count == N - 1):
                break
                    
        
        return costs
                


class Node:
    
    
    def __init__(self,data,rank,node):
        
        self.data = data
        self.rank = rank
        self.node = node
        

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def findManhattanDistance(p1,p2):            
            return abs(p1[0]-p2[0]) + abs(p1[1] - p2[1])
        
        edges = []
        
        for i,p1 in enumerate(points):
            for j in range(i+1,len(points)):
                
                edges.append([i,j,findManhattanDistance(p1,points[j])])
                
        
        edges = sorted(edges,key=lambda x:x[2])
        
        N = len(points)
        
        hashMap = {}
        
        for i in range(N):
            
            node = Node(i,0,None)
            node.parent = node
            
            hashMap[node.data] = node
        
        
        
        
        def Union(data1,data2):
            
            node1 = hashMap[data1]
            node2 = hashMap[data2]
            
            p1 = findSet(node1)
            p2 = findSet(node2)
            
            if(p1 == p2):
                return False
            
        
            if(p1.rank >= p2.rank):
                p1.rank = p1.rank + 1 if(p1.rank == p2.rank) else p1.rank
                
                p2.parent = p1
                
            else:
                p1.parent = p2
                
            
            return True
        
        
        
        def findSet(node):
            
            if(node.parent == node):
                return node
            
            node.parent = findSet(node.parent)
            
            return node.parent
        

        edge_count = 0
        costs = 0
        
        for u,v,w in edges:
            
            if(Union(u,v)):
                costs += w
                edge_count +=1
                
                
            if(edge_count == N - 1):
                break
                    
        
        return costs

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def dis(p1, p2):
            x1, y1 = p1
            x2, y2 = p2
            return abs(x1-x2) + abs(y1-y2)
        
        size = len(points)
        cost = 0
        
        idx = list(range(size))
        
        def find(x):
            if x != idx[x]:
                idx[x] = find(idx[x])
            return idx[x]
        
        def union(x, y):
            xx, yy = find(x), find(y)
            if xx == yy:
                return False
            idx[xx] = yy
            return True
        
        edges = []
        for i in range(size):
            for j in range(i+1, size):
                distance = dis(points[i], points[j])
                edges.append((distance, i, j))
                
        edges.sort()        
        for dis, x, y in edges:        
            if union(x, y):
                cost += dis
                size -= 1
                if size == 1:
                    return cost
        return cost        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        result = 0
        m = 0
        q = [(0, 0)]
        visited = [10 ** 9] * n
        while m < n:
            w, i = heapq.heappop(q)
            # print(j, i, w)
            if visited[i] < 0:
                continue
            visited[i] = -1
            for j in range(n):
                if j == i or visited[j] < 0:
                    continue
                ww = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                if ww < visited[j]:
                    visited[j] = ww
                    heapq.heappush(q, (ww, j))
            m += 1
            result += w
        return result

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if not points:
            return 0
        n = len(points)
        g = [[0]*n for _ in range(n)]
        for i in range(n):
            for j in range(n):
                x,y = points[i]
                xx,yy = points[j]
                g[i][j] = g[j][i] = abs(x-xx) + abs(y-yy)
        dist = [float('inf')] * n
        dist[0] = 0
        s = set(range(n))
        heap = [(0,0)]  # PQ for (distance,node)
        while heap:
            d,u = heapq.heappop(heap)
            if u not in s:
                continue
            s.remove(u)
            for v in range(n):
                if v in s and g[u][v] < dist[v]:
                    dist[v] = g[u][v]
                    heapq.heappush(heap,(dist[v],v))
        # print(dist)
        return sum(dist)
            
                    
            


import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        fathers = list(range(n))
        queue = []
        for i, p1 in enumerate(points):
            for j in range(i+1, n):
                p2 = points[j]
                d = self.distance(p1, p2)
                heapq.heappush(queue, (d, i*n+j, i, j))
        
        def find(fathers, v):
            if fathers[v]!=v:
                fathers[v]=find(fathers, fathers[v])
            return fathers[v]
        
        def union(fathers, a, b):
            rootA = find(fathers, a)
            rootB = find(fathers, b)
            if rootA!=rootB:
                fathers[rootB]=rootA
        
        cnt = 0
        edges = 0
        while queue and edges<n-1:
            d, _, i, j = heapq.heappop(queue)
            rootI = find(fathers, i)
            rootJ = find(fathers, j)
            if rootI != rootJ:
                cnt+=d
                edges+=1
                union(fathers, rootI, rootJ)
        return cnt
    
    def distance(self, p1, p2):
        return abs(p1[0]-p2[0])+abs(p1[1]-p2[1])

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def find(parent, i):
            if parent[i] == i:
                return i
            return find(parent, parent[i])
        
        def apply_union(parent, rank, x, y):
            xroot = find(parent, x)
            yroot = find(parent, y)
            if rank[xroot] < rank[yroot]:
                parent[xroot] = yroot
            elif rank[xroot] > rank[yroot]:
                parent[yroot] = xroot
            else:
                parent[yroot] = xroot
                rank[xroot] += 1
        
        ans = 0
        V = len(points)
        graph = []
        for i in range(V):
            for j in range(i):
                v = abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                graph.append([i,j,v])
                
        i, e = 0, 0
        graph = sorted(graph, key=lambda item: item[2])
        parent = []
        rank = []
        for node in range(V):
            parent.append(node)
            rank.append(0)
        while e < V - 1:
            u, v, w = graph[i]
            i = i + 1
            x = find(parent, u)
            y = find(parent, v)
            if x != y:
                e = e + 1
                ans+=w
                apply_union(parent, rank, x, y)
        return ans

class Node:
    def __init__(self,data,rank,node):        
        self.data = data
        self.rank = rank
        self.node = node            
        self.parent = self

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def findManhattanDistance(p1,p2):            
            return abs(p1[0]-p2[0]) + abs(p1[1] - p2[1])
        
        edges = []        
        for i,p1 in enumerate(points):
            for j in range(i+1,len(points)):                
                edges.append([i,j,findManhattanDistance(p1,points[j])])                
        
        edges = sorted(edges,key=lambda x:x[2])        
        N = len(points)        
        hashMap = {}        
        for i in range(N):            
            node = Node(i,0,None)
            #node.parent = node            
            hashMap[node.data] = node
        
        
        def Union(data1,data2):            
            node1 = hashMap[data1]
            node2 = hashMap[data2]
            
            p1 = findSet(node1)
            p2 = findSet(node2)
            
            if(p1 == p2):
                return False            
        
            if(p1.rank > p2.rank):
                p1.rank = p1.rank + p2.rank
                p2.parent = p1                
            else:
                p2.rank = p2.rank + p1.rank
                p1.parent = p2            
            return True        
        
        
        def findSet(node):
            while (node.parent != node):
                node.parent = node.parent.parent
                node = node.parent            
            return node.parent        
        
        edge_count = 0
        costs = 0        
        for u,v,w in edges:            
            if(Union(u,v)):        
                costs += w
                edge_count +=1
            if(edge_count == N - 1):
                break
        return costs

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        res = 0
        connected = 1
        visited = set()
        pq = list()
        i = 0
        while (connected < n):
            visited.add(i)
            for j in range(n):
                if j not in visited:
                    heappush(pq, (abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]), j))
            d, i = heappop(pq)
            while (i in visited):
                d, i = heappop(pq)
            res += d
            connected += 1
        return res;

class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:
        edges, n, cnt, ans = [], len(p), 1, 0
        
        def manhattan(x, y):
            return abs(p[x][0]-p[y][0]) + abs(p[x][1]-p[y][1])
        
        edges = [(manhattan(i, j), (i, j)) 
                 for i in range(n) for j in range(i+1, n)]
        heapq.heapify(edges)
        
        def union(x, y):
            uf[find(x)] = find(y)
        
        def find(x):
            if x != uf[x]:
                uf[x] = find(uf[x])
            return uf[x]
        
        uf = list(range(n))
        while cnt < n:
            d, (u, v) = heapq.heappop(edges)
            if find(u)!=find(v):
                ans += d
                cnt += 1
                union(u, v)
        return ans    


import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def cost(a, b):
            return abs(a[0] - b[0]) + abs(a[1] -b[1])
        points = list(map(lambda x: (x[0], x[1]), points))
        minDist = {p:float(\"inf\") for p in points}
        
        
        point = points[0]
        connected = set()
        connected.add(point)
        # q = []
        totalCost = 0
        for p in points:
            if p != point:
                minDist[p] = cost(point, p)
        for i in range(1, len(points)):
            minPoint = None
            minCost = float(\"inf\") 
            for p in points:
                if p not in connected and minDist[p] < minCost:
                    minPoint = p
                    minCost = minDist[p]
            connected.add(minPoint)
            totalCost += minCost
            # update min list
            for p in points:
                if p != minPoint:
                    minDist[p] = min(minDist[p], cost(minPoint, p))
        return totalCost
        # heapq.heappush(q, (cost(point, p), p))
                
                
                
        # connected = set()
        # connected.add(point)
        # totalCost = 0
        # while len(q) > 0:
        #     edgeCost, point = heapq.heappop(q)
        #     if point in connected:
        #         continue
        #     connected.add(point)
        #     totalCost += edgeCost
        #     if len(connected) == len(points):
        #         return totalCost
        #     for p in points:
        #         if p != point:
        #             heapq.heappush(q, (cost(point, p), p))
        # return totalCost

class Unifind:
    def __init__(self,n):
        self.arr = list(range(n))
        self.rank = [0]*n
    def union(self,a,b):
        a = self.find(a)
        b = self.find(b)
        
        if self.rank[a]<self.rank[b]:
            a,b = b,a
        
        if self.rank[a]==self.rank[b]:
            self.rank[a]+=1
        
        self.arr[b] = a
        
    def find(self,a):
        if self.arr[a]!=a:
            self.arr[a] = self.find(self.arr[a])
        return self.arr[a]
        
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        manhatan = lambda i,j : -(abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1]))
        edges = sorted((manhatan(i,j),i,j) for i in range(len(points)) for j in range(i+1,len(points)))
        #print(edges)
        uf = Unifind(len(points))
        count = 0
        cost = 0
        while count < len(points)-1:
            c,i,j = edges.pop()
            #if edge adds a cycle(both ends are already in)
            if uf.find(i)!=uf.find(j):
                cost-=c
                count+=1
                uf.union(i,j)
                
        #print(uf.arr)
        return cost
                
                


class Solution:
    def calculateCost(self, i, j, points):
        return abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
    
    def find(self, x, roots):
        if roots[x] != x:
            roots[x] = self.find(roots[x], roots)
        return roots[x]

    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if not points or len(points) < 2:
            return 0
        
        n = len(points)
        
        edges = []
        for i in range(n):
            for j in range(i + 1, n):
                weight = self.calculateCost(i, j, points)
                edges.append((weight, i, j))
        edges.sort()
        
        roots = [i for i in range(n)]
        
        res = 0
        components = n
        for edge in edges:
            weight, x, y = edge
            root_x = self.find(x, roots)
            root_y = self.find(y, roots)
            if root_x != root_y:
                components -= 1
                res += weight
                
                if components == 1:
                    break
                
                roots[root_x] = root_y
        
        return res


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        result = 0
        for i in range(1, len(points)):
            for j in range(i):
                edges.append((j, i, abs(points[j][1] - points[i][1]) + abs(points[j][0] - points[i][0])));
        edges =  sorted(edges, key = lambda k : k[2])
        treeId = []
        for i in range(len(points)):
            treeId.append(i)

        for u,v,w in edges:
            if treeId[u] != treeId[v]:
                result += w
                oldId = treeId[u]
                newId = treeId[v]
                for k in range(len(points)):
                    if treeId[k] == oldId:
                        treeId[k] = newId
        return result


class Unifindm:
    def __init__(self,n):
        self.arr = list(range(n))
        self.rank = [0]*n
    def union(self,a,b):
        a = self.find(a)
        b = self.find(b)
        
        if self.rank[a]<self.rank[b]:
            a,b = b,a
        
        if self.rank[a]==self.rank[b]:
            self.rank[a]+=1
        
        self.arr[b] = a
        
    def find(self,a):
        if self.arr[a]!=a:
            self.arr[a] = self.find(self.arr[a])
        return self.arr[a]

class Unifind:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [1 for _ in range(n)]
    
    # make a and b part of the same component
    # union by rank optimization
    def union(self, a, b):
        pa = self.find(a)
        pb = self.find(b)
        if pa == pb: return
        if self.rank[pa] > self.rank[pb]:
            self.parent[pb] = pa
            self.rank[pa] += self.rank[pb]
        else:
            self.parent[pa] = pb
            self.rank[pb] += self.rank[pa]
    
    # find the representative of the 
    # path compression optimization
    def find(self, a):
        if self.parent[a] == a:
            return a
        
        self.parent[a] = self.find(self.parent[a])
        return self.parent[a]
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        manhatan = lambda i,j : -(abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1]))
        edges = sorted((manhatan(i,j),i,j) for i in range(len(points)) for j in range(i+1,len(points)))
        #print(edges)
        uf = Unifind(len(points))
        count = 0
        cost = 0
        while count < len(points)-1:
            c,i,j = edges.pop()
            #if edge adds a cycle(both ends are already in)
            if uf.find(i)!=uf.find(j):
                cost-=c
                count+=1
                uf.union(i,j)
                
        #print(uf.arr)
        return cost
                
                


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n=len(points)
        l=[[0 for i in range(n)] for j in range(n)]
        for i in range(n-1):
            for j in range(i+1,n):
                res=abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                l[i][j]=res
                l[j][i]=res
        def minKey():
            m=sys.maxsize
            minind = 0
            for i in range(n):
                if key[i]<m and vis[i]==0:
                    m=key[i]
                    minind=i
            return minind
        vis=[0]*n
        key=[sys.maxsize]*n
        key[0]=0
        for i in range(n-1):
            u=minKey()
            vis[u]=1
            for v in range(n):
                if l[u][v] and vis[v]==0 and l[u][v]<key[v]:
                    key[v]=l[u][v]
        return sum(key)

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def find_parent(parent,x):
            if parent[x] == -1:
                return x
            return find_parent(parent,parent[x])
        
        def union(parent,x,y):
            x_s = find_parent(parent,x)
            y_s = find_parent(parent,y)
            parent[x_s] = y_s
        
        def kruskals(edges):
            parent = [-1]*len(points)
            min_weight = 0
            i = 0
            j = 0
            while j < len(points) - 1:
                start,end,weight = edges[i]
                x = find_parent(parent,start)
                y = find_parent(parent,end)
                i+=1
                if x!=y:
                    j+=1
                    union(parent,x,y)
                    min_weight += weight
            return min_weight

        edges = []
        for i in range(len(points)):
            for j in range(i+1,len(points)):
                dis = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append([i,j,dis])
        edges.sort(key = lambda x: x[2])
        return kruskals(edges)


class Unifind:
    def __init__(self,n):
        self.arr = list(range(n))
        
    def union(self,a,b):
        self.arr[self.find(a)] = self.find(b)
        
    def find(self,a):
        if self.arr[a]!=a:
            self.arr[a] = self.find(self.arr[a])
        return self.arr[a]
        
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        manhatan = lambda i,j : -(abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1]))
        edges = sorted((manhatan(i,j),i,j) for i in range(len(points)) for j in range(i+1,len(points)))
        #print(edges)
        uf = Unifind(len(points))
        count = 0
        cost = 0
        while count < len(points)-1:
            c,i,j = edges.pop()
            #if edge adds a cycle(both ends are already in)
            if uf.find(i)!=uf.find(j):
                cost-=c
                count+=1
                uf.union(i,j)
                
        #print(uf.arr)
        return cost
                
                


class DisjointSet():
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [1]*n 

    def find(self, x):
        if self.parent[x] == x: return x 
        return self.find(self.parent[x])

    def union(self, x, y):
        px = self.find(x)
        py = self.find(y)
        if self.rank[px] > self.rank[py]:
            self.parent[py] = px 
            self.rank[px] += self.rank[py] 
        else: 
            self.parent[px] = py 
            self.rank[py] += self.rank[px]
    

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        def ManhattanDistance(p1,p2):
            x1,y1 = p1; 
            x2,y2 = p2;
            return abs(x2-x1)+abs(y2-y1)

        edges = [(ManhattanDistance(points[i], points[j]),i,j) for i in range(n) for j in range(i+1, n)]
        edges.sort()

        graph = DisjointSet(n)
        ans = 0
        
        i = 0
        for cost, u, v in edges:
            if graph.find(u) != graph.find(v): 
                graph.union(u,v)
                ans += cost 
                i += 1
            if i == n-1: break
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        
        distances = []
        for i in range(n - 1):
            for j in range(i + 1, n):
                distances.append([i, j, self.dist(points[i], points[j])])
        
        distances.sort(key=lambda x: x[2])
        
        parent = []
        for i in range(n):
            parent.append(i)
            
        e = 0
        i = 0
        result = 0
        while e < n-1:
            u, v, w =  distances[i] 
            i = i + 1
            x = self.find(parent, u) 
            y = self.find(parent ,v) 
  
            # If including this edge does't cause cycle,  
                        # include it in result and increment the index 
                        # of result for next edge 
            if x != y: 
                e = e + 1     
                result += w
                self.union(parent, x, y) 
        
        return result
            
    def dist(self, p1, p2):
        return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
    
    def find(self, parent, i): 
        if parent[i] == i: 
            return i 
        return self.find(parent, parent[i]) 
  
    def union(self, parent, x, y): 
        xroot = self.find(parent, x) 
        yroot = self.find(parent, y) 
  
        if xroot != yroot: 
            parent[yroot] = xroot 

import heapq

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        if len(points) == 1:
            return 0
        
        def manhattan(x1, x2):
            return abs(x1[0] - x2[0]) + abs(x1[1] - x2[1])
        
        total_cost = 0
        first_chosen = points.pop()
        cost_heap = []
        
        for point in points:
            heapq.heappush(cost_heap, [manhattan(point, first_chosen), point])

        while cost_heap:
            cost, new_point = heapq.heappop(cost_heap)
            total_cost += cost
            for i, [cost, point] in enumerate(cost_heap):
                cost_heap[i][0] = min(cost, manhattan(point, new_point))
            cost_heap.sort()
            
        return total_cost


from heapq import nlargest

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        res = 0
        visited = [False] * n
        dist = [float(\"inf\")] * n
        curr = 0
        for i in range(n-1):
            x1,y1 = points[curr]
            visited[curr] = True
            for j in range(n):
                if not visited[j]:
                    x2,y2 = points[j]
                    dist[j] = min(dist[j], abs(x2-x1) + abs(y2-y1))
                    
            cost, curr = float(\"inf\"), -1
            for i in range(len(dist)):
                if dist[i] < cost:
                    curr = i
                    cost = dist[i]
            dist[curr] = float(\"inf\")
            res += cost
            
        return res
                    
        
            

from queue import PriorityQueue

class Solution:
    def findParent(self, parents, i):
        if parents[i] is None:
            return i
        else:
            return self.findParent(parents, parents[i])
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) == 0:
            return 0
        
        edges = []
        req_edges = len(points)-1
        dist = 0
        parents = [None] * len(points)
        ranks = [0] * len(points)
        
        for i, p1 in enumerate(points):
            for j, p2 in enumerate(points):
                if i < j:
                    edges.append([i, j, (abs(p1[0]-p2[0]) + abs(p1[1]-p2[1]))])
        edges = sorted(edges, key=lambda x: x[2])
        
        for edge in edges:
            parent_i = self.findParent(parents, edge[0])
            parent_j = self.findParent(parents, edge[1])
            if parent_i == parent_j:
                continue
            if ranks[parent_i] < ranks[parent_j]:
                parents[parent_i] = parent_j
            elif ranks[parent_i] > ranks[parent_j]:
                parents[parent_j] = parent_i
            else:
                parents[parent_i] = parent_j
                ranks[parent_j] += 1
            dist += edge[2]

            req_edges -= 1
            if req_edges == 0:
                break
            
        return dist


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        self.rank = [1 for _ in range(n)]
        self.parent = [i for i in range(n)]
        distance = []
        for i in range(n-1):
            for j in range(i+1,n):
                dis = abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                distance.append((dis,i,j))
        distance.sort(key = lambda x:x[0])
        ans = 0
        count = 0
        for dis,u,v in distance:
            if self.find(u) == self.find(v):
                continue
            ans += dis
            self.union(u,v)
            count += 1
            if count == n-1:
                break
        return ans
    def union(self,a,b):
        parenta = self.find(a)
        parentb = self.find(b)
        if parenta == parentb:
            return 
        if self.rank[parenta] > self.rank[parentb]:
            self.parent[parentb] = parenta
            self.rank[parenta] += self.rank[parentb]
        else:
            self.parent[parenta] = parentb
            self.rank[parentb] += self.rank[parenta]
        return
    def find(self,a):
        if self.parent[a] == a:
            return a
        else:
            self.parent[a] = self.find(self.parent[a])
            return self.parent[a]


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def md(p1, p2):
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        q = [md(points[0], p) for p in points]
        #print(q)
        res = 0
        n = len(points)
        for _ in range(n - 1):
            d, j = min((d, j) for j, d in enumerate(q) if d > 0)
            print((d, j))
            res += d
            q = [min(q[i], md(points[i], points[j])) for i in range(n)]
        return res


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n=len(points)
        def dist(i,j):  #求两个点之间的距离
            return abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
        
        ds=[float('inf')]*n   #一点到其他所有点的距离
        
        for i in range(1,n):   #此时0到其他所有点的距离
            ds[i]=dist(0,i)
        
        res=0
        for i in range(1,n):
            cost=min(ds)
            res+=cost
            j=ds.index(cost)
            ds[j]=float('inf')
            for k in range(n):
                if ds[k]==float('inf'):
                    continue
                ds[k]=min(ds[k],dist(j,k))
        return res

import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        n = len(points)
        
        
        ques = []
        final = (1 << n) - 1
        for i in range(n):
            for j in range(i+1, n):
                heapq.heappush(ques, (abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]), i, j))
        
        p = [i for i in range(n)]
        k = [1 for i in range(n)]
        components = n
        res = 0
        
        def findp(x):
            while x != p[x]:
                x = p[x]
            return x
        
        def union(x, y):
            if k[x] > k[y]:
                k[x] += k[y]
                p[y] = x
            else:
                k[y] += k[x]
                p[x] = y
                
        while components != 1:
            
            dist, one, two = heapq.heappop(ques)
            pone = findp(one)
            ptwo = findp(two)
            # print(dist, one, two)
            # print(p)
            if pone != ptwo:
                union(pone, ptwo)
                components -= 1
                res += dist
        return res
                
            
 

            
        
            
        



from collections import defaultdict
import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        graph = defaultdict(list)
        start = points[0]
\t\t
         
        #Storing the data in parent Directory
        dist = {}
        N = len(points)
\t\t# Using heap to find min wt
        heap = [(0, tuple(start))]
        while heap:
            ddist, node = heapq.heappop(heap)
            if node in dist:
                continue
            dist[node] = ddist
            for neighbor in points:
                if tuple(neighbor) not in dist:
                    d = abs(node[0]-neighbor[0]) + abs(node[1]-neighbor[1])
                    heapq.heappush (heap, (d, tuple(neighbor)))
            if len(dist) == N:
                break
        return sum(dist.values()) if len(dist) == N else -1

    
class Solution1:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        uf = {}

        # create union find for the initial edges given 
        def find(edge):
            uf.setdefault(edge, edge)
            if uf[edge] != edge:
                uf[edge] = find(uf[edge])
            return uf[edge]

        def union(edge1, edge2):
            uf[find(edge1)] = find(edge2)

       

        # sort the new edges by cost
        # if an edge is not part of the minimum spanning tree, then include it, else continue
        cost_ret = 0
        poss_mst = []
        for p1 in points:
            for p2 in points:
                dist = abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
                poss_mst.append([tuple(p1),tuple(p2),dist])
                
        for c1, c2, cost in sorted(poss_mst, key=lambda x : x[2]):
            if find(c1) != find(c2):
                union(c1, c2)
                cost_ret += cost

        return cost_ret
        

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n == 1:
            return 0
        dMat = [[-1 for j in range(n)] for i in range(n)]
        
        def d(p1, p2):
            a, b = p1
            c, d = p2
            return abs(a-c) + abs(b-d)
        
        for i, p1 in enumerate(points):
            for j, p2 in enumerate(points):
                dMat[i][j] = d(p1, p2)
        
        key = [float('inf')] * n
        parent = [None] * n
        key[0] = 0
        mstSet = [False] * n

        parent[0] = -1

        def minKey():
            # Initilaize min value
            min = float('inf')
            for v in range(n):
                if key[v] < min and mstSet[v] == False:
                    min = key[v]
                    min_index = v
            return min_index

        for cout in range(n):
            u = minKey()
            mstSet[u] = True
            for v in range(n):
                if dMat[u][v] > 0 and mstSet[v] == False and key[v] > dMat[u][v]:
                    key[v] = dMat[u][v]
                    parent[v] = u

        res = 0
        for v in range(n):
            if parent[v] != -1:
                u = parent[v]
                res += dMat[u][v]
        
        return res


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        edges = collections.defaultdict(dict)
        n = len(points)
        for i in range(n):
            for j in range(i):
                x1, y1 = points[i]
                x2, y2 = points[j]
                d = abs(x1-x2) + abs(y1-y2)
                edges[i][j] = d
                edges[j][i] = d
                
                
        ans = 0
        visited = set([0])
        cand = []
        for j in edges[0]:
            heapq.heappush(cand, [edges[0][j], j])
        ans = 0
        while len(visited) < n:
            d, j = heapq.heappop(cand)
            if j not in visited:
                ans += d
                visited.add(j)
                for i in edges[j]:
                    if i not in visited:
                        heapq.heappush(cand, [edges[j][i], i])
        return ans
            


from heapq import *
class Solution:
    def minCostConnectPoints(self, points):
        N = len(points)
        parent = [i for i in range(N)]
        def find(v):
            while parent[v] != parent[parent[v]]:
                parent[v] = parent[parent[v]]
            return parent[v]
        dist = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        heap, total_cost = [], 0
        for u in range(N-1):
            for v in range(u+1, N):
                heappush(heap, [dist(points[u], points[v]), u, v])
        while heap:
            cost, u, v = heappop(heap)
            pu, pv = find(u), find(v)
            if pu != pv:
                parent[pu] = pv
                N -= 1
                total_cost += cost
                if N == 0:
                    break
        return total_cost

    
    
    
    
    
    
    
    
from heapq import *
class Solution:
    def minCostConnectPoints(self, points):
        dist = lambda p1, p2: abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        N = len(points)
        parent = [i for i in range(N)]
        def find(v):
            while parent[v] != parent[parent[v]]:
                parent[v] = parent[parent[v]]
            return parent[v]
        heap = []
        for i in range(N-1):
            for j in range(i+1, N):
                heappush(heap, (dist(points[i], points[j]), i, j))
        res = 0
        while heap:
            d, u, v = heappop(heap)
            pu, pv = find(u), find(v)
            if pu != pv:
                parent[pu] = pv
                res += d
                N -= 1
                if N == 0:
                    break
        return res
            


    
    
class Solution:
    def minCostConnectPoints(self, points):
        distance = lambda p1, p2: abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        points.sort(key = lambda p: abs(p[0]) + abs(p[1]))
        total_cost = 0
        points = [[p, distance(p, points[0])] for p in points]
        while points:
            minIdx, mindist = None, float('inf')
            for i, (p, dist) in enumerate(points):
                if dist < mindist:
                    minIdx, mindist = i, dist
            px, cost = points.pop(minIdx)
            total_cost += cost
            for i, (p, dist) in enumerate(points):
                newdist = distance(p, px)
                if newdist < dist:
                    points[i][1] = newdist
        return total_cost        

class Solution:

    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def manhattan(p1, p2):
            if p1 == p2:
                return 10**10
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        
        def makeGraph(points):
            graph = []
            for p1 in range(len(points)):
                for p2 in range(p1):
                    graph.append( (p2, p1, manhattan(points[p1], points[p2])) )
            return graph
        
        def find(subsets, p1):
            if subsets[p1][0] != p1:
                subsets[p1][0] = find(subsets, subsets[p1][0])
            return subsets[p1][0]
        
        def union(subsets, p1, p2):
            p1root = find(subsets, p1)
            p2root = find(subsets, p2)
            
            if subsets[p1root][1] > subsets[p2root][1]:
                subsets[p2root][0] = p1root
            elif subsets[p2root][1] > subsets[p1root][1]:
                subsets[p1root][0] = p2root
            else:
                subsets[p1root][1] += 1
                subsets[p2root][0] = p1root
        
        graph = makeGraph(points)
        
        edges = sorted(graph, key=lambda x: x[2])
        subsets = [[x, 0] for x in range(len(points))]
        
        e = 0 #counts how many edges have been added
        i = 0 #tracks location in edges array
        total_cost = 0
        
        while e < len(points) - 1:
            
            p1, p2, cost = edges[i]
            
            if find(subsets, p1) != find(subsets, p2):               
                union(subsets, p1, p2)
                total_cost += cost
                e += 1
            else:
                pass
                #discard the edge
            
            i += 1
        return total_cost

class DisjointSet:
    def __init__(self, n):
        self.rank = {i:i for i in range(n)}
        self.size = n
        self.parent = {i:i for i in range(n)}
        
    def find(self, i):
        if self.parent[i] != i:
            self.parent[i] = self.find(self.parent[i])
        return self.parent[i]
    
    def union(self, i, j):
        root_i, root_j = self.find(i), self.find(j)
        if root_i == root_j:
            return False
        
        if self.rank[root_i] > self.rank[root_j]:
            self.parent[root_j] = root_i
        elif self.rank[root_i] < self.rank[root_j]:
            self.parent[root_i] = root_j
        else:
            self.parent[root_j] = root_i
            self.rank[root_i] += 1
        self.size -= 1
        return True
        

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        ds = DisjointSet(n)
        
        d = []
        for i in range(n):
            for j in range(i, n):
                d_ij = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                heapq.heappush(d, [d_ij, i, j])
        
        min_cost = 0
        while ds.size > 1:
            d_ij, i, j = heapq.heappop(d)
            if ds.union(i, j):
                min_cost += d_ij
        return min_cost


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        # lets give each edge a weight
        # an edge will be some point A to another point B
        # we will store the distances in a minheap
        # then we will perform union find to connect all points
        # using prim's algorithm - we choose the minimum from the current point we are at building out the MST
        if len(points) <= 1: return 0
        N = len(points)
        distances = [float('inf')] * N
        seen = set()
        ans = 0
        curr = 0
        for i in range(N-1):
            x1,y1 = points[curr]
            seen.add(curr)
            for j in range(N):
                x2,y2 = points[j]
                if j in seen: continue
                distances[j] = min(abs(x1-x2)+abs(y1-y2),distances[j])
            delta,curr = min((d,j) for j,d in enumerate(distances))
            distances[curr] = float('inf')
            ans+= delta
        return ans
            


import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        edges = [[] for i in range(n)]
        for i in range(n - 1):
            for j in range(i + 1, n):
                md = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges[i].append((md, j))
                edges[j].append((md, i))
        i = 0
        visited = set()
        visited.add(i)
        li = edges[i]
        heapq.heapify(li)
        result = 0
        while li:
            d, j = heapq.heappop(li)
            if j not in visited:
                visited.add(j)
                result += d
                if len(visited) == n:
                    return result
                for edge in edges[j]:
                    if edge[1] not in visited:
                        heapq.heappush(li, edge)
        return result

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def manhattan(p1,p2):
            return abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        
        q = []
        for i in range(1,len(points)):
            heapq.heappush(q, (manhattan(points[0],points[i]),0,i))
        
        network = set([0])
        res = 0
        while q and (len(network) < len(points)):
            
            d, prev, node = heapq.heappop(q)
            
            if node in network:
                continue
            
            network.add(node)
            res += d
            
            for neigh in range(len(points)):
                if neigh not in network:
                    heapq.heappush(q, (manhattan(points[neigh], points[node]), node, neigh))
        
        return res

from heapq import heappop, heappush, heapify
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if len(points) == 1: return 0
        res = 0
        curr = 0 # select a random point as the starting point
        dis = [math.inf] * n
        explored = set()
        
        for i in range(n - 1):
            x0, y0 = points[curr]
            explored.add(curr)
            for j, (x, y) in enumerate(points):
                if j in explored: continue
                dis[j] = min(dis[j], abs(x - x0) + abs(y - y0))
                
            delta, curr = min((d, j) for j, d in enumerate(dis)) 
            dis[curr] = math.inf
            res += delta
            
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        #   最小生成树
        N = len(points)
        
        if N <= 1:
            return 0
        
        edges = []
        for i in range(N):
            p1 = points[i]
            for j in range(i+1, N):
                p2 = points[j]
                cost = abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
                edges.append((cost, i, j))
        
        edges.sort()    #   按照距离升序排列
        # print(edges)
        
        A = set()
        B = set(range(N))

        #   增加起点
        A.add(0)
        B.discard(0)    
            
        rtv = 0
        while len(B) > 0:
            for idx,e in enumerate(edges):
                c,a,b = e
                if a in A and b in B:
                    B.discard(b)
                    A.add(b)
                    # print(\"{} {} {}\".format(a,b,c))
                    rtv += c
                    edges.pop(idx)
                    break
                elif b in A and a in B:
                    B.discard(a)
                    A.add(a)
                    # print(\"{} {} {}\".format(a,b,c))
                    rtv += c
                    edges.pop(idx)
                    break
        return rtv
        


import numpy as np
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # pre-processing, adjacency matrix for cost of edges;
        if len(points) > 1:
            edge_cost = []
            for i in range(len(points)):
                for j in range(i+1, len(points)):
                    edge_cost.append((i, j, abs(points[j][0] - points[i][0]) + abs(points[j][1] - points[i][1])))

            # now try to find the smallest edge to add, find more points to add. 

            edge_cost.sort(key=lambda x: x[2])

            # print(edge_cost)

            connected_component = set()

            min_cost = 0

            i = 0
            
    #         # when some element is not connectected
            while len(connected_component) < len(points):
                i = 0
                while not ((edge_cost[i][0] in connected_component) ^ (edge_cost[i][1] in connected_component)) and len(connected_component)!= 0:
                    i += 1
                if i < len(edge_cost):
                    current = edge_cost[i]
                    min_cost += current[2]
                    connected_component.add(current[0])
                    connected_component.add(current[1])
                    edge_cost.pop(i)
                    # print(\"connected component: %s\" % connected_component)
                else:
                    print(\"Should never be here!\")
            return min_cost
        else:
            return 0

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n == 1:
            return 0
        res = 0
        curr = 0
        dis = [float('inf')] * n
        explored = set()

        for i in range(n - 1):
            point_x, point_y = points[curr]
            explored.add(curr)
            for j, (x, y) in enumerate(points):
                if j in explored:
                    continue
                dis[j] = min(dis[j], abs(x - point_x) + abs(y - point_y))

            delta, curr = min((d, j) for j, d in enumerate(dis))
            dis[curr] = float('inf')
            res += delta

        return res


from heapq import nlargest

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        res = 0
        visited = [False] * n
        dist = [float(\"inf\")] * n
        curr = 0
        for i in range(n-1):
            x1,y1 = points[curr]
            visited[curr] = True
            for j in range(n):
                if not visited[j]:
                    x2,y2 = points[j]
                    dist[j] = min(dist[j], abs(x2-x1) + abs(y2-y1))
                    
            cost, curr = float(\"inf\"), -1
            for i in range(len(dist)):
                if not visited[i] and dist[i] < cost:
                    curr = i
                    cost = dist[i]
            res += cost
            
        return res
                    
        
            

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) == 1:
            return 0
        pq = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                temp = abs(points[j][1]-points[i][1]) + abs(points[j][0]-points[i][0])
                heapq.heappush(pq, (temp, (i, j)))
        
        root = list(range(len(points)))
        
        def find(x):
            if x != root[x]:
                root[x] = find(root[x])
            return root[x]
            
        def union(x, y):
            rx, ry = find(x), find(y)
            if rx == ry:
                return False
            root[rx] = root[ry]
            return True
        
        res = 0
        conn = 0
        while conn < len(points)-1:
            cost, xy = heapq.heappop(pq)
            x, y = xy
            
            if union(x, y):
                res += cost
                conn += 1
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        a = points
        n = len(a)
        def d(i, j): return abs(a[i][0]-a[j][0]) + abs(a[i][1]-a[j][1])
        q = []
        dst = [float('inf')]*n
        vis = [False] * n
        def consider(du, u):
            if vis[u] or du >= dst[u]: return
            dst[u] = du
            heappush(q, (du, u))
        consider(0, 0)
        while q:
            du, u = heappop(q)
            if vis[u]: continue
            vis[u] = True
            for v in range(n): consider(d(u, v), v)
        return sum(dst)

from heapq import heappush, heappop
class DSU:
    def __init__(self, N):
        self.par = list(range(N))
        self.sz = [1] * N

    def find(self, x):
        if self.par[x] != x:
            self.par[x] = self.find(self.par[x])
        return self.par[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        if xr == yr:
            return False
        if self.sz[xr] < self.sz[yr]:
            xr, yr = yr, xr
        self.par[yr] = xr
        self.sz[xr] += self.sz[yr]
        self.sz[yr] = self.sz[xr]
        return True

    def size(self, x):
        return self.sz[self.find(x)]
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        if len(points) == 1:
            return 0
        
        def weight(i,j):
            return abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
        
        edges = []
        ans = 0
        
        for i in range(len(points)):
            for j in range(i+1,len(points)):
                heappush(edges,(weight(i,j),i,j))
        
        uf = DSU(len(points)+1)
        
        while edges:
            e = heappop(edges)
            if uf.union(e[1],e[2]):
                ans += e[0]
                if uf.size(e[1]) == len(points):
                    return ans
                
        # return ans


import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def cost(a, b):
            return abs(a[0] - b[0]) + abs(a[1] -b[1])
        points = list(map(lambda x: (x[0], x[1]), points))
        point = points[0]
        q = []
        for p in points:
            if p != point:
                heapq.heappush(q, (cost(point, p), p))
        connected = set()
        connected.add(point)
        totalCost = 0
        while len(q) > 0:
            edgeCost, point = heapq.heappop(q)
            if point in connected:
                continue
            connected.add(point)
            totalCost += edgeCost
            if len(connected) == len(points):
                return totalCost
            for p in points:
                if p != point:
                    heapq.heappush(q, (cost(point, p), p))
        return totalCost

class Solution:
    def minCostConnectPoints(self, points):
        distance = lambda p1, p2: abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        points.sort(key = lambda p: p[0] + p[1])
        total_cost = 0
        points = [[p, distance(p, points[0])] for p in points]
        while points:
            minIdx, mindist = None, float('inf')
            for i, (p1, dist) in enumerate(points):
                if dist < mindist:
                    minIdx, mindist = i, dist
            p1, cost = points.pop(minIdx)
            total_cost += cost
            for i, (p2, dist) in enumerate(points):
                points[i][1] = min(points[i][1], distance(p1, p2))
        return total_cost
    
from heapq import *
class Solution:
    def minCostConnectPoints(self, points):
        N = len(points)
        parent = [i for i in range(N)]
        def find(v):
            while parent[v] != parent[parent[v]]:
                parent[v] = parent[parent[v]]
            return parent[v]
        dist = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        connections = [[u, v, dist(points[u], points[v])] for u in range(N-1) for v in range(u+1, N)]
        connections.sort(key = lambda x:x[2])
        total_cost, remain = 0, N-1
        for u, v, cost in connections:
            pu, pv = find(u), find(v)
            if pu != pv:
                parent[pu] = pv
                total_cost += cost
                remain -= 1
                if remain == 0:
                    break
        return total_cost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        es = []
        n = len(points)
        for i, p in enumerate(points):
            x, y = p
            for j in range(i + 1, n):
                pb = points[j]
                x2, y2 = pb
                val = abs(x - x2) + abs(y - y2)
                es.append((val, i, j))
        es.sort()
        # print(es)
        self.father = {i:i for i in range(n)}
        ans = size = 0
        for cost, u, v in es:
            if self.find(u) != self.find(v):
                ans += cost
                self.union(u, v)
                size += 1
            if size == n - 1:
                break
        return ans
        
    def find(self, a):
        path = []
        nd = a
        fa = self.father
        while fa[nd] != nd:
            path.append(nd)
            nd = fa[nd]
        root = nd
        for nd in path:
            fa[nd] = root
        return root
    
    def union(self, a, b):
        fa = self.father
        ra = self.find(a)
        rb = self.find(b)
        if ra != rb:
            fa[ra] = rb


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        costs = []
        
        for i in range(len(points) - 1):
            for j in range(i + 1, len(points)):
                cost = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                costs.append((cost, i, j))
                
        costs.sort(key = lambda x: x[0])
        
        group_label = [i for i in range(len(points))]
        result = 0
        combined = 0
        
        
        def find_group(target: int, group_label: List[int]) -> int:
            path = []
            while not target == group_label[target]:
                path.append(target)
                target = group_label[target]
            for node in path:
                group_label[node] = target
            return target
        
        
        def union_group(target: int, source: int, group_label: List[int]) -> int:
            while not source == group_label[source]:
                next_source = group_label[source]
                group_label[source] = target
                source = next_source
            group_label[source] = target
            
        
        while combined < len(points) - 1:
            cost, target, source = costs.pop(0)
            target_group = find_group(target, group_label)
            source_group = find_group(source, group_label)
            if not target_group == source_group:
                union_group(target_group, source, group_label)
                result += cost
                combined += 1
                
        return result


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def dist(u,v):
            return abs(points[u][0]-points[v][0])+abs(points[u][1]-points[v][1])
        n = len(points)
        ret = 0
        visited = [False]*n
        visited[0] = True
        closest = [0]*n
        for i in range(1,n): closest[i] = dist(0,i)
        for _ in range(n-1):
            mini = float('inf')
            node = -1
            for i in range(n):
                if not visited[i] and closest[i] < mini:
                    mini = closest[i]
                    node = i
            ret += mini
            visited[node] = True
            for i in range(n):
                if not visited[i]: closest[i] = min(closest[i],dist(i,node))
        return ret

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n == 1:
            return 0
        
        dist_arr = []
        for i in range(n - 1):
            x1, y1 = points[i]
            for j in range(i + 1, n):
                x2, y2 = points[j]
                dist = abs(x1 - x2) + abs(y1 - y2)
                dist_arr.append((dist, i, j))
        heapq.heapify(dist_arr)
        
        
        root = [i for i in range(n)]
        
        def find(n):
            if root[n] != n:
                root[n] = find(root[n])
            return root[n]
        
        def union(x, y):
            s1 = find(x)
            s2 = find(y)
            if s1 != s2:
                root[s2] = root[s1]
                return 1
            return 0
                
        res = 0
        count = 0
        while count < n - 1:
            dist, x, y = heapq.heappop(dist_arr)
            if union(x, y) == 1:
                res += dist
                count += 1
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        l = len(points)
        if (l == 1):
            return 0        
        segs = []
        
        for idx1 in range(l):            
            for idx2 in range(idx1+1, l):
                dist = abs(points[idx1][0] - points[idx2][0]) + abs(points[idx1][1] - points[idx2][1])
                segs.append((idx1, idx2, dist))

        segs.sort(key = lambda x: x[2])

        parent = [x for x in range(l)]
        
        def getParent(idx:int) -> int:
            if parent[idx] == idx:
                return idx
            return getParent(parent[idx])
        
        self.f = 1
        def union(idx1:int, idx2:int, price:int) -> int:
            p1 = getParent(idx1)
            p2 = getParent(idx2)
            
            if (p1 == p2):
                return 0
            else:
                if (self.f == 0):
                    parent[p2] = p1
                else:
                    parent[p1] = p2
                self.f = 1 - self.f
                return price        
        
        ans = 0 
        
        lines = 0
        while(segs and lines < l - 1):
            s = segs.pop(0)
            off = union(s[0], s[1], s[2])
            ans += off
            if (off > 0):
                lines += 1
            
            
        return ans
            
            
                


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        if N == 1: return 0
        
        # Kruskal's algorithm
        
        # Sort the edges by cost
        edges = []
        for i in range(N):
            for j in range(i + 1, N):
                x1, y1 = points[i]
                x2, y2 = points[j]
                dist = abs(x1 - x2) + abs(y1 - y2)
                edges.append((dist, i, j))
        edges.sort()
        
        # Union find utility
        roots = [i for i in range(N)]
        def find(i):
            if roots[i] != i:
                roots[i] = find(roots[i])
            return roots[i]
    
        def join(i, j):
            ri, rj = find(i), find(j)
            roots[ri] = rj
            
        i = cnt = 0
        res = 0
        while cnt < N - 1:
            d, x, y = edges[i]
            i += 1
            rx, ry = find(x), find(y)
            if find(x) == find(y): # If already connected, cannot use this edge
                continue
            join(rx, ry)
            cnt += 1
            res += d
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n == 1:
            return 0
        res = 0
        curr = 0 
        dis = [float('inf')] * n
        explored = set()

        for i in range(n - 1):
            point_x, point_y = points[curr]
            explored.add(curr)
            for j, (x, y) in enumerate(points):
                if j in explored:
                    continue
                dis[j] = min(dis[j], abs(x - point_x) + abs(y - point_y))

            delta, curr = min((d, j) for j, d in enumerate(dis))
            dis[curr] = float('inf')
            res += delta

        return res


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        n, c = len(points), collections.defaultdict(list)
        for i in range(n):
            for j in range(i + 1, n):
                d = manhattan(points[i], points[j])
                c[i].append((d, j))
                c[j].append((d, i))
        cnt, ans, visited, heap = 1, 0, [0] * n, c[0]
        visited[0] = 1
        heapq.heapify(heap)
        while heap:
            d, j = heapq.heappop(heap)
            if not visited[j]:
                visited[j], cnt, ans = 1, cnt + 1, ans+d
                for record in c[j]: 
                    if not visited[record[1]]:
                        heapq.heappush(heap, record)
            if cnt >= n: break        
        return ans if cnt >= n else 0 
    
#         def manhattan(x, y):
#             return abs(x[0]-y[0]) + abs(x[1]-y[1])
        
#         ans, n = 0, len(p)
#         seen = set()
#         vertices = [(0, (0, 0))]
        
#         while len(seen) < n:
#             # print(vertices, seen)
#             w, (u, v) = heapq.heappop(vertices)            
#             if v in seen: continue
#             ans += w
#             seen.add(v)
#             for j in range(n):
#                 if j not in seen and j!=v:
#                     heapq.heappush(vertices, (manhattan(p[j], p[v]), (v, j)))


class Solution:
    def minCostConnectPoints(self, points) -> int:
        graph = defaultdict(list)
        for i in range(len(points)):
            x, y = points[i]
            for j in range(len(points)):
                x1, y1 = points[j]
                if i != j:
                    graph[i].append((abs(x-x1)+abs(y-y1), j))
        start = 0
        res = 0
        visited = {start}
        min_heap = []
        for cost, neighbor in graph[start]:
            heapq.heappush(min_heap, (cost, neighbor))
        while len(visited) < len(points):
            cost, next_node = heapq.heappop(min_heap)
            if next_node not in visited:
                visited.add(next_node)
                res += cost 
                for next_cost, next_neighbor in graph[next_node]:
                    if next_neighbor not in visited:
                        heapq.heappush(min_heap, (next_cost, next_neighbor))
        return res 

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def manhattan(p1,p2):
            return abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        
        q = []
        for i in range(1,len(points)):
            heapq.heappush(q, (manhattan(points[0],points[i]),0,i))
        
        network = set([0])
        res = 0
        while q and (len(network) < len(points)):
            
            d, i, j = heapq.heappop(q)
            
            if j in network:
                continue
            
            network.add(j)
            res += d
            
            for k in range(len(points)):
                if (k != j) and (k not in network):
                    heapq.heappush(q, (manhattan(points[k], points[j]), j, k))
        
        return res

class Solution:
    def minCostConnectPoints(self, points) -> int:
        graph = defaultdict(list)
        for i in range(len(points)):
            x, y = points[i]
            for j in range(len(points)):
                x1, y1 = points[j]
                if i != j:
                    graph[i].append((abs(x-x1)+abs(y-y1), j))
        start = 0
        res = 0
        visited = {start}
        min_heap = []
        for md, neighbor in graph[start]:
            heapq.heappush(min_heap, (md, neighbor))
        while len(visited) < len(points):
            md, next_node = heapq.heappop(min_heap)
            if next_node not in visited:
                visited.add(next_node)
                res += md 
                for nxt_md, next_neighbor in graph[next_node]:
                    if next_neighbor not in visited:
                        heapq.heappush(min_heap, (nxt_md, next_neighbor))
        return res 

class dsu:
    def __init__(self,n):
        self.parents = [i for i in range(n)]
        self.rank = [0 for i in range(n)]
    def find(self,u):
        if u != self.parents[u]:
            self.parents[u] = self.find(self.parents[u])
        return self.parents[u]
    def union(self,u,v):
        pu = self.parents[u]
        pv = self.parents[v]
        if pu != pv:
            if self.rank[pu] < self.rank[pv]:
                self.parents[pu] = pv
            elif self.rank[pu] > self.rank[pv]:
                self.parents[pv] = pu
            else:
                self.parents[pu] = pv
                self.rank[pv] += 1
        
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def get_dist(i,j):
            return abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
        h = []
        n = len(points)
        uf = dsu(n)
        for i in range(n):
            for j in range(i):
                heapq.heappush(h,(get_dist(i,j),i,j))
        # print(h)
        cost = 0
        count = 0
        while h:
            c,u,v = heapq.heappop(h)
            if uf.find(u) != uf.find(v):
                uf.union(u,v)
                cost += c
                count += 1
            if count >=  n-1:break
        return cost

class Solution:
    def minCostConnectPoints(self, a: List[List[int]]) -> int:                        
        ans, n, vis, pq, i = 0, len(a), set([0]), [], 0
        rem = set(range(1, n))
        while len(vis) < n:            
            for j in rem: heappush(pq, (abs(a[i][0]-a[j][0]) + abs(a[i][1] - a[j][1]), j))
            while pq[0][1] in vis: heappop(pq)
            val, i = heappop(pq)
            vis.add(i); rem.discard(i)
            ans += val            
        return ans                                            

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        ind = 0
        distance = [float('inf')]*n
        visited = [False] * n
        total_cost = 0
        for cnt in range(n):
            x0,y0 = points[ind][0],points[ind][1]
            for i in range(n):
                if visited[i]:
                    continue
                distance[i] = min(distance[i],abs(points[i][0]-x0) + abs(points[i][1]-y0))
            dis,ind = min((d,i) for i,d in enumerate(distance))
            visited[ind] = True
            total_cost += dis
            distance[ind] = float('inf')
        return total_cost


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def find(roots, x):
            if x != roots[x]:
                roots[x] = find(roots, roots[x])    # compress
            return roots[x]

        n = len(points)
        manhattan = lambda a, b: abs(a[0] - b[0]) + abs(a[1] - b[1])
        heap = []
        roots = list(range(n))
        size = [1 for i in range(n)]
        res = 0

        # 先把所有节点按照距离存放到 heap 中
        for i in range(n):
            for j in range(i + 1, n):
                d = manhattan(points[i], points[j])
                heap.append((d, (i, j)))

        # 堆化
        heapq.heapify(heap)

        while heap:
            d, (i, j) = heapq.heappop(heap)
            root1 = find(roots, i)
            root2 = find(roots, j)

            # if root1 != root2:
            #     res += d
            #     # union by rank
            #     if size[root1] < size[root2]:
            #         roots[root1] = root2
            #         size[root2] += size[root1]
            #         if size[root2] == n: break
            #     else:
            #         roots[root2] = root1
            #         size[root1] += size[root2]
            #         if size[root1] == n: break

            if root1 != root2:
                res += d
                # union by rank
                roots[root2] = root1
                size[root1] += size[root2]
                if size[root1] == n: break

        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def dist(a,b,c,d):
            return abs(a-c)+abs(b-d)
        res = 0
        if len(points) <= 1: return 0
        r = 0
        visited = set()
        k = defaultdict(lambda:999999999)
        k[tuple(points[0])] = 0 # source vertex
        for _ in range(len(points)):
            m = float('inf')
            cand = ()
            for point in k:
                if k[point] < m and point not in visited:
                    cand = point
                    m = k[point]
            visited.add(cand)
            
            for point in points:
                p = tuple(point)
                if p != cand and p not in visited and dist(cand[0], cand[1], p[0], p[1]) < k[p]:
                    k[p] = dist(cand[0], cand[1], p[0], p[1]) 
                    # res += k[p]
        print((k, sum(k.values())))
    
        return sum(k.values())


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        n, c = len(points), collections.defaultdict(list)
        for i in range(n):
            for j in range(i + 1, n):
                d = manhattan(points[i], points[j])
                c[i].append((d, j))
                c[j].append((d, i))
        cnt, ans, visited, heap = 1, 0, [0] * n, c[0]
        visited[0] = 1
        heapq.heapify(heap)
        while heap:
            d, j = heapq.heappop(heap)
            if not visited[j]:
                visited[j], cnt, ans = 1, cnt + 1, ans+d
                for record in c[j]: 
                    if not visited[record[1]]:
                        heapq.heappush(heap, record)
            if cnt >= n: break        
        return ans  
    
#         def manhattan(x, y):
#             return abs(x[0]-y[0]) + abs(x[1]-y[1])
        
#         ans, n = 0, len(p)
#         seen = set()
#         vertices = [(0, (0, 0))]
        
#         while len(seen) < n:
#             # print(vertices, seen)
#             w, (u, v) = heapq.heappop(vertices)            
#             if v in seen: continue
#             ans += w
#             seen.add(v)
#             for j in range(n):
#                 if j not in seen and j!=v:
#                     heapq.heappush(vertices, (manhattan(p[j], p[v]), (v, j)))


from collections import defaultdict
import heapq

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = defaultdict(list)
        for i in range(len(points)):
            for j in range(len(points)):
                if i != j:
                    parent_x, parent_y = points[i]
                    child_x, child_y = points[j]
                    distance = abs(child_x - parent_x) + abs(child_y - parent_y)
                    edges[i].append((distance, j))
        
        heap = [(0, 0, 0)]
        seen_points = set()
        total_distance = 0
        
        while len(seen_points) < len(points):
            distance, parent_point, child_point = heapq.heappop(heap)
            while child_point in seen_points:
                distance, parent_point, child_point = heapq.heappop(heap)
                
            seen_points.add(child_point)
            total_distance += distance
            
            for distance, child_child_point in edges[child_point]:
                if child_child_point not in seen_points:
                    heapq.heappush(heap, (distance, child_point, child_child_point))
        
        return total_distance
                    
                    
                    
                    
                    


class Solution:
    def minCostConnectPoints(self, a: List[List[int]]) -> int:                
        n = len(a)
        if n <= 1: return 0
        d = defaultdict(list)
        min_val = float('inf')
        min_i = min_j = None
        for i in range(n-1):            
            for j in range(i+1, n):                
                val = abs(a[i][0]-a[j][0]) + abs(a[i][1]-a[j][1])
                d[i].append((val, i, j))                         
                d[j].append((val, j, i))                         
                if min_val > val: 
                    min_val, min_i, min_j = val, i, j
                    
        for i in range(n): heapify(d[i])                
        q = [heappop(d[i]) for i in (min_i, min_j)]      
        heapify(q)        
        ans, cur = 0, set()
        while len(cur) < n:            
            val, i, j = heappop(q)
            if i not in cur or j not in cur:                 
                ans += val
                # print(ans, i, j, q)
            cur.add(i); cur.add(j)
            while d[i] and d[i][0][2] in cur: heappop(d[i])
            if d[i]: heappush(q, heappop(d[i]))
            while d[j] and d[j][0][2] in cur: heappop(d[j])
            if d[j]: heappush(q, heappop(d[j]))            
        return ans                

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:        
        vertices = len(points)
        self.V = vertices
        self.graph = [[0 for column in range(vertices)] for row in range(vertices)]
        for i in range(self.V):
            for j in range(self.V):
                if i == j:
                    self.graph[i][j] = 0
                else:
                    self.graph[i][j]= abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
        return self.primMST()

    def minKey(self, key, mstSet):
        min = math.inf
        for v in range(self.V):
            if key[v] < min and mstSet[v] == False:
                min = key[v]
                min_index = v
        return min_index
 
    def primMST(self):
        key = [math.inf] * self.V
        parent = [None] * self.V
        key[0] = 0
        mstSet = [False] * self.V
 
        parent[0] = -1
 
        for cout in range(self.V):
            u = self.minKey(key, mstSet)
            mstSet[u] = True
            for v in range(self.V):
                if self.graph[u][v] > 0 and mstSet[v] == False and key[v] > self.graph[u][v]:
                        key[v] = self.graph[u][v]
                        parent[v] = u       
        res = 0
        for i in range(1, self.V):
            res += self.graph[i][parent[i]]
        return res

class Solution:
    def minCostConnectPoints(self, a: List[List[int]]) -> int:                
        n = len(a)
        if n <= 1: return 0
        d = defaultdict(list)
        min_val, min_i = float('inf'), None        
        for i in range(n-1):            
            for j in range(i+1, n):                
                val = abs(a[i][0]-a[j][0]) + abs(a[i][1]-a[j][1])
                d[i].append((val, i, j)); d[j].append((val, j, i))                         
                if min_val > val: min_val, min_i = val, i
                    
        for i in range(n): heapify(d[i])                
        q = [heappop(d[min_i])]      
        heapify(q)        
        ans, cur = 0, set([min_i])
        while len(cur) < n:            
            val, i, j = heappop(q)
            if j not in cur: ans += val
            cur.add(j)
            while d[i] and d[i][0][2] in cur: heappop(d[i])
            if d[i]: heappush(q, heappop(d[i]))
            while d[j] and d[j][0][2] in cur: heappop(d[j])
            if d[j]: heappush(q, heappop(d[j]))            
        return ans                

class Solution:
    def minCostConnectPoints(self, points):
        distance = lambda p1, p2: abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        points.sort(key = lambda p: abs(p[0]) + abs(p[1]))
        total_cost = 0
        points = [[p, distance(p, points[0])] for p in points]
        while points:
            minIdx, mindist = None, float('inf')
            for i, (p1, dist) in enumerate(points):
                if dist < mindist:
                    minIdx, mindist = i, dist
            p1, cost = points.pop(minIdx)
            total_cost += cost
            for i, (p2, dist) in enumerate(points):
                newdist = distance(p1, p2)
                if newdist < dist:
                    points[i][1] = newdist
        return total_cost        

class Solution:
    def minCostConnectPoints(self, a: List[List[int]]) -> int:                        
        n, vis, ans, pq, i = len(a), set([0]), 0, [], 0
        rem = set(range(1, n))
        while len(vis) < n:            
            for j in rem: heappush(pq, (abs(a[i][0]-a[j][0]) + abs(a[i][1] - a[j][1]), j))
            while pq[0][1] in vis: heappop(pq)
            val, i = heappop(pq)
            vis.add(i); rem.discard(i)
            ans += val            
        return ans                                            

class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:
        
        ans, ct,n = 0,0, len(p)
        seen = set()
        vertices = [(0, (0, 0))]
        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        while ct<n:
            # print(vertices, seen)
            w, (u, v) = heapq.heappop(vertices)            
            if u in seen and v in seen: 
                continue
            ans += w
            seen.add(v)
            ct+=1
 
            for j in range(n):
                if j not in seen and j!=v:
                    heapq.heappush(vertices, (manhattan(p[j], p[v]), (v, j)))
                    
        return ans

import heapq
'''
1584. Min Cost to Connect All Points.  Medium

You are given an array points representing integer coordinates
of some points on a 2D-plane, where points[i] = [xi, yi].

The cost of connecting two points [xi, yi] and [xj, yj] is the manhattan distance
between them: |xi - xj| + |yi - yj|,
where |val| denotes the absolute value of val.

Return the minimum cost to make all points connected.
All points are connected if there is exactly one simple path
between any two points.

Example 1:
Input: points = [[0, 0], [2, 2], [3, 10], [5, 2], [7, 0]]
Output: 20
Explanation:

We can connect the points as shown above to get the minimum cost of 20.
Notice that there is a unique path between every pair of points.

Example 2:
Input: points = [[3, 12], [-2, 5], [-4, 1]]
Output: 18

Example 3:
Input: points = [[0, 0], [1, 1], [1, 0], [-1, 1]]
Output: 4

Example 4:
Input: points = [[-1000000, -1000000], [1000000, 1000000]]
Output: 4000000

Example 5:
Input: points = [[0, 0]]
Output: 0

Constraints:
1 <= points.length <= 1000
-106 <= xi, yi <= 106
All pairs (xi, yi) are distinct.

Accepted 1,742 / 5,429 submissions.
'''
def man_dist_4(x,y,u,v):
    return abs(x - u) + abs(y - v)

def man_dist_pt(ptA, ptB):
    return abs(ptA[0] - ptB[0]) + abs(ptA[1] - ptB[1])


class Solution:

    def minCostConnectPoints(self, p: List[List[int]]) -> int:

        def manhattan(x, y):
            return abs(x[0]-y[0]) + abs(x[1]-y[1])

        ans, n = 0, len(p)
        seen = set()
        vertices = [(0, (0, 0))]

        while len(seen) < n:
            # print(vertices, seen)
            w, (u, v) = heapq.heappop(vertices)
            if u in seen and v in seen: continue
            ans += w
            seen.add(v)
            for j in range(n):
                if j not in seen and j!=v:
                    heapq.heappush(vertices, (manhattan(p[j], p[v]), (v, j)))
        return ans

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

class SolutionTle:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) < 2:
            return 0
        points.sort()
        lost = {(x, y) for x, y in points}
        found = set()

        x, y = lost.pop()
        found.add((x, y))
        minc = float('inf')
        for u, v in lost:
            md = man_dist_4(x,y,u,v)
            if minc > md:
                minc = md
                minu = u
                minv = v
        cost = minc
        lost.remove((minu, minv))
        found.add((minu, minv))

        while lost:
            minc = float('inf')
            for x, y in found:
                for u, v in lost:
                    md = man_dist_4(x,y,u,v)
                    if (minc > md):
                        minc = md
                        minu = u
                        minv = v
            cost += minc
            lost.remove((minu, minv))
            found.add((minu, minv))

        return cost



class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if not points: return 0        
        
        n = len(points)
        dist = [[0] * n for _ in range(n)]
        for i in range(n):
            x1, y1 = points[i]
            for j in range(n):
                x2, y2 = points[j]
                dist[i][j] = abs(x1 - x2) + abs(y1 - y2)
                
        origin = 0
        q = []
        for j, d in enumerate(dist[0]):
            heapq.heappush(q, (d, j))
        
        ans = 0
        visited = set([0])
        while len(visited) < n:
            d, child = heapq.heappop(q)
            if child not in visited:
                ans += d
                visited.add(child)
                for j, n_d in enumerate(dist[child]):
                    if j not in visited:
                        heapq.heappush(q, (n_d, j))
        return ans
            
        
        
        
                


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        for i in range(len(points)-1):
            for j in range(i+1,len(points)):
                edges.append((i,j,abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])))
        
        edges.sort(key=lambda x: x[2])
        
        seen = dict()
        ct=0
        ans = 0
        
        for i in range(len(edges)):
            edge = edges[i]
                
            if edge[0] not in seen or edge[1] not in seen:
                if edge[0] not in seen and edge[1] not in seen:
                    seen[edge[0]] = ct
                    seen[edge[1]] = ct
                    ct+=1
                if edge[0] not in seen and edge[1] in seen:
                    seen[edge[0]] =seen[edge[1]]
                if edge[0] in seen and edge[1] not in seen:
                    seen[edge[1]] =seen[edge[0]]
                
                
                ans += edge[2]
                
            if edge[0] not in seen and edge[1] in seen:
                seen[edge[0]] = seen[edge[1]]
                
                ans+=edge[2]
            
            if edge[1] not in seen and edge[0] in seen:
                seen[edge[1]] = seen[edge[0]]
                
                ans+=edge[2]
                
            if edge[0] in seen and edge[1] in seen:
                if seen[edge[0]]!=seen[edge[1]]:
                    for key in seen:                        
                        if key!=edge[1] and seen[key]==seen[edge[1]]:
                            seen[key]=seen[edge[0]]
                    
                    seen[edge[1]] = seen[edge[0]]
                    
                    ans+=edge[2]
                    
        
        
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        
        n = len(points)
        dist = [[0] * n for _ in range(n)]
        res = 0
        
        for i in range(n):
            p = points[i]
            for j in range(n):
                nei = points[j]
                dist[i][j] = abs(p[0] - nei[0]) + abs(p[1] - nei[1])
        
        res = self.prim(n, dist, 0)
        return res
     
    def prim(self, n, dist, start):
        visited = set()
        res = 0
        nei = [[0, 0, 0]]
        heapq.heapify(nei)
        
        while len(visited) != n:
            weight, current, dummy = heapq.heappop(nei)
            if current in visited:
                continue
            res += weight
            visited.add(current)
            
            for i in range(n):
                if i not in visited:
                    heapq.heappush(nei, [dist[current][i], i, i])
        
        return res
            
            
        
        


from heapq import heappush, heappop
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def helper(i, j):
            return abs(points[j][0] - points[i][0]) + \\
                   abs(points[j][1] - points[i][1])
        
        g = defaultdict(lambda: {}); n = len(points)
        for i in range(n-1):
            for j in range(i+1, n):
                g[i][j] = g[j][i] = helper(i,j)

                
        visited = set(); res = 0; q = []; cnt=0
        heappush(q, (0, 0)) # u:0, cost:0
        while q:
            cost, u = heappop(q)
            if u in visited: continue
            res += cost
            cnt += 1
            for v, w in g[u].items():
                heappush(q, (w, v))
            visited.add(u)
            if cnt >= n: break
        return res
        
        
    
\"\"\"
[[0,0],[2,2],[3,10],[5,2],[7,0]]
[[3,12],[-2,5],[-4,1]]
[[0,0],[1,1],[1,0],[-1,1]]
[[-1000000,-1000000],[1000000,1000000]]
[[0,0]]
\"\"\"            

class Solution:
    def minCostConnectPoints(self, a: List[List[int]]) -> int:                
        n = len(a)
        if n <= 1: return 0
        d = defaultdict(list)
        min_val, min_i = float('inf'), None        
        for i in range(n-1):            
            for j in range(i+1, n):                
                val = abs(a[i][0]-a[j][0]) + abs(a[i][1]-a[j][1])
                d[i].append((val, i, j)); d[j].append((val, j, i))                         
                if min_val > val: 
                    min_val, min_i = val, i
                    
        for i in range(n): heapify(d[i])                
        q = [heappop(d[min_i])]      
        heapify(q)        
        ans, cur = 0, set()
        while len(cur) < n:            
            val, i, j = heappop(q)
            if i not in cur or j not in cur: ans += val
            cur.add(i); cur.add(j)
            while d[i] and d[i][0][2] in cur: heappop(d[i])
            if d[i]: heappush(q, heappop(d[i]))
            while d[j] and d[j][0][2] in cur: heappop(d[j])
            if d[j]: heappush(q, heappop(d[j]))            
        return ans                

class Node:
    def __init__(self,data,rank,node):        
        self.data = data
        self.rank = rank
        self.node = node            
        self.parent = self

class Solution:
    def minCostConnectPoints(self, a: List[List[int]]) -> int:
        n = len(a)
        if n <= 1: return 0
        d = defaultdict(list)
        min_val, min_i = float('inf'), None        
        for i in range(n-1):            
            for j in range(i+1, n):                
                val = abs(a[i][0]-a[j][0]) + abs(a[i][1]-a[j][1])
                d[i].append((val, i, j)); d[j].append((val, j, i))                         
                if min_val > val: min_val, min_i = val, i
                    
        for i in range(n): heapify(d[i])                
        q = [heappop(d[min_i])]      
        heapify(q)        
        ans, cur = 0, set([min_i])
        while len(cur) < n:            
            val, i, j = heappop(q)
            if j not in cur: ans += val
            cur.add(j)
            while d[i] and d[i][0][2] in cur: heappop(d[i])
            if d[i]: heappush(q, heappop(d[i]))
            while d[j] and d[j][0][2] in cur: heappop(d[j])
            if d[j]: heappush(q, heappop(d[j]))            
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        s = [0]
        res = 0
        d = {i: abs(points[i][0]-points[0][0]) + abs(points[i][1]-points[0][1]) for i in range(len(points))}
        current = 0
        while len(s) < len(points):
            min_ = float('inf')
            next_ = current
            for i in range(1,len(points)):
                if d[i] == 0:
                    continue
                else:
                    dis = abs(points[i][0]-points[next_][0]) + abs(points[i][1]-points[next_][1])
                    if dis <= d[i]:
                        d[i] = dis
                    if d[i] <= min_:
                        min_ = d[i]
                        current = i
            res += min_
            d[current] = 0
            s.append(current)
        return res
                                                                    
            
        
                    


from collections import defaultdict 
  
class Graph: 
    def __init__(self,vertices): 
        self.V= vertices
        self.graph = [] 

    def addEdge(self,u,v,w): 
        self.graph.append([u,v,w]) 
        
    def find(self, parent, i): 
        if parent[i] == i: 
            return i 
        return self.find(parent, parent[i]) 
    
    def union(self, parent, rank, x, y): 
        xroot = self.find(parent, x) 
        yroot = self.find(parent, y) 
        
        if rank[xroot] < rank[yroot]: 
            parent[xroot] = yroot 
        elif rank[xroot] > rank[yroot]: 
            parent[yroot] = xroot 
        else : 
            parent[yroot] = xroot 
            rank[xroot] += 1

    def KruskalMST(self): 
        
        result =[] 

        i = 0
        e = 0
        self.graph =  sorted(self.graph,key=lambda item: item[2]) 

        parent = [] ; rank = [] 

        for node in range(self.V): 
            parent.append(node) 
            rank.append(0) 

        while e < self.V -1 : 
            u,v,w =  self.graph[i] 
            i = i + 1
            x = self.find(parent, u) 
            y = self.find(parent ,v) 

            if x != y: 
                e = e + 1     
                result.append([u,v,w]) 
                self.union(parent, rank, x, y)             

        ans = 0
        for u,v,weight in result:
            ans += weight
        
        return ans


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def getCost(x1, x2, y1, y2):
            return abs(x2-x1) + abs(y2-y1)
        
        g = Graph(len(points))
        for i in range(len(points)-1):
            for j in range(i+1,len(points)):
                g.addEdge(i,j,getCost(points[i][0], points[j][0], points[i][1], points[j][1]))
        
        return g.KruskalMST()


class Solution:
    
    def dist(self, x1,y1,x2,y2):
        return abs(x1-x2) + abs(y1-y2)
    
    def dist_from_point_to_all(self, points, i, n):
        return [self.dist(*points[i],*points[j]) for j in range(n)]
        
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        # This is Prim algo and I need an array for the min_priority
        # to get the algo in time O(n**2), otherwise it will be too
        # slow with a factor of log(n)
        all_ = set(range(n))
        s = set([0])
        tot = 0
        dist = self.dist_from_point_to_all(points, 0, n)
        for _ in range(n-1):
            min_dist = 10**8
            for i in range(n):
                if i not in s and dist[i] < min_dist:
                    pos_best = i
                    min_dist = dist[i]
            tot += min_dist
            s.add(pos_best)
            dist_pos_best = self.dist_from_point_to_all(points, pos_best, n)
            dist = [min(dist[j], dist_pos_best[j]) for j in range(n)]
        return tot

class Solution:
    def minCostConnectPoints(self, a: List[List[int]]) -> int:                
        n = len(a)
        if n <= 1: return 0
        d = defaultdict(list)
        min_val, min_i = float('inf'), None        
        for i in range(n-1):            
            for j in range(i+1, n):                
                val = abs(a[i][0]-a[j][0]) + abs(a[i][1]-a[j][1])
                d[i].append((val, i, j)); d[j].append((val, j, i))                         
                if min_val > val: 
                    min_val, min_i = val, i
                    
        for i in range(n): heapify(d[i])                
        q = [heappop(d[min_i])]      
        heapify(q)        
        ans, cur = 0, set()
        while len(cur) < n:            
            val, i, j = heappop(q)
            if j not in cur: ans += val
            cur.add(i); cur.add(j)
            while d[i] and d[i][0][2] in cur: heappop(d[i])
            if d[i]: heappush(q, heappop(d[i]))
            while d[j] and d[j][0][2] in cur: heappop(d[j])
            if d[j]: heappush(q, heappop(d[j]))            
        return ans                

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        graph,n,temp,edge=collections.defaultdict(list),len(points),float(\"inf\"),[-1,-1]
        for i in range(n):
            for j in range(i+1,n):
                x,y,a,b=points[i][0],points[i][1],points[j][0],points[j][1]
                dist=abs(x-a)+abs(y-b)
                graph[i].append((dist,j))
                graph[j].append((dist,i))
                if dist<temp:
                    temp=dist
                    edge=[i,j]
        ans,vis,queue,vis_count=0,{0},graph[0],1
        heap=heapq.heapify(queue)
        while queue and vis_count<n:
            d,v=heapq.heappop(queue)
            if v in vis: continue
            ans+=d
            vis_count+=1
            vis.add(v)
            for connected in graph[v]:
                if connected[1] in vis: continue
                heapq.heappush(queue,connected)
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        L = len(points)
        parent = {i:i for i in range(L)}
        
        def find(p):
            if parent[p] == p:
                return p
            return find(parent[p])
        
        def union(p,q):
            if p != q:
                if p < q:
                    parent[q] = p
                else:
                    parent[p] = q
\t\t
        cost = 0
        con = {}
        count = 0            
        for i,p1 in enumerate(points):
            for j,p2 in enumerate(points):
                if i!=j and (j,i) not in con.keys():
                    d = self.dis(p1,p2)
                    con[(i,j)] = d
        k = sorted(con, key = lambda x :con[x])
        for e in k:
            x,y = e[0],e[1]
            x_set, y_set = find(x), find(y)
            if x_set!=y_set:
                union(x_set,y_set)
                count += 1
                cost += con[e]
            if count == L-1:
                break
        return cost
            
    def dis(self, p, x):
        d = abs(x[1]-p[1]) + abs(x[0]-p[0])
        return d

class Solution:
    def minCostConnectPoints(self, a: List[List[int]]) -> int:                
        n = len(a)
        if n <= 1: return 0
        d = defaultdict(list)
        min_val, min_i = float('inf'), None        
        for i in range(n-1):            
            for j in range(i+1, n):                
                val = abs(a[i][0]-a[j][0]) + abs(a[i][1]-a[j][1])
                d[i].append((val, i, j)); d[j].append((val, j, i))                         
                if min_val > val: 
                    min_val, min_i = val, i
                    
        for i in range(n): heapify(d[i])                
        q = [heappop(d[min_i])]      
        heapify(q)        
        ans, cur = 0, set([min_i])
        while len(cur) < n:            
            val, i, j = heappop(q)
            if j not in cur: ans += val
            cur.add(j)
            while d[i] and d[i][0][2] in cur: heappop(d[i])
            if d[i]: heappush(q, heappop(d[i]))
            while d[j] and d[j][0][2] in cur: heappop(d[j])
            if d[j]: heappush(q, heappop(d[j]))            
        return ans                

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n == 1:
            return 0
        dic = {}
        for i in range(n - 1):
            x1, y1 = points[i]
            for j in range(i + 1, n):
                x2, y2 = points[j]
                dist = abs(x1 - x2) + abs(y1 - y2)
                dic[(i, j)] = dist
        
        root = [i for i in range(n)]
        
        def find(n):
            if root[n] != n:
                root[n] = find(root[n])
            return root[n]
        
        def union(x, y):
            s1 = find(x)
            s2 = find(y)
            if s1 != s2:
                root[s2] = root[s1]
                return 1
            return 0
                
        dic_sorted = sorted(list(dic.items()), key=lambda x: x[1])
        res = 0
        count = 0
        for item in dic_sorted:
            x, y = item[0]
            dist = item[1]
            if union(x, y) == 1:
                res += dist
                count += 1
            if count == n - 1:
                return res
        #return res
            
                
                
        
                    
                
        
        
        
                
                
                
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def manhattan_distance(point_1, point_2):
            x1, y1 = point_1
            x2, y2 = point_2
            return abs(x2 - x1) + abs(y2 - y1)
        
        n = len(points)
        graph = collections.defaultdict(list)
        for i in range(n):
            for j in range(i + 1, n):
                dist = manhattan_distance(points[i], points[j])
                graph[i].append((dist, j))
                graph[j].append((dist, i))
            
        visited = set()
        visited.add(0)
        heap = [_ for _ in graph[0]]
        heapq.heapify(heap)
        cost = 0
        
        while heap and len(visited) != len(points):
            dist, neighbor = heapq.heappop(heap)
            if neighbor not in visited:
                visited.add(neighbor)
                cost += dist
                for new_dist, new_neighbor in graph[neighbor]:
                    if new_neighbor not in visited:
                        heapq.heappush(heap, (new_dist, new_neighbor))
                        
        return cost
    
    
    
    
    
    
    
    
    
    
    
    


from heapq import heappop, heappush

class DSU:
    def __init__(self, n):
        self.p = [i for i in range(n)]
        self.rank = [1] * n
        self.parts = n
    
    def find(self, a):
        if self.p[a] == a:
            return a
        
        self.p[a] = self.find(self.p[a])
        return self.p[a]
    
    def is_connected(self, a, b):
        return self.find(a) == self.find(b)
    
    def union(self, a, b):
        A = self.find(a)
        B = self.find(b)
        
        if self.rank[A] >= self.rank[B]:
            self.p[B] = A
            self.rank[A] += self.rank[B]
        else:
            self.p[A] = B
            self.rank[B] += self.rank[A]
        
        return

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        N = len(points)
        dsu = DSU(N)
        
        pq = []
        
        for i in range(N):
            x1, y1 = points[i]
            for j in range(i + 1, N):
                x2, y2 = points[j]
                heappush(pq, (abs(x1 - x2) + abs(y1 - y2), i, j))
        
        cost = 0
        while dsu.parts > 1:
            c, p1, p2 = heappop(pq)
            
            if dsu.is_connected(p1, p2) == True:
                continue
            
            dsu.union(p1, p2)
            dsu.parts -= 1
            cost += c
        
        return cost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def dist(p1, p2):
            x1,y1 = p1
            x2,y2 = p2
            return abs(x1-x2) + abs(y1-y2)
        
        n = len(points)
        d = [float('inf')] * n
        cur = 0
        ans = 0
        seen = set()
        
        for i in range(n-1):
            seen.add(cur)
            for j,p in enumerate(points):
                if j in seen: continue
                d[j] = min(d[j], dist(points[cur],points[j]))
            
            min_d, nxt = min((d,j) for j,d in enumerate(d))
            d[nxt] = float('inf')
            cur = nxt
            ans += min_d
        
        return ans
                                   
                


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def find(roots, x):
            if x != roots[x]:
                roots[x] = find(roots, roots[x])
            return roots[x]

        n = len(points)
        manhattan = lambda a, b: abs(a[0] - b[0]) + abs(a[1] - b[1])
        heap = []
        roots = list(range(n))
        size = [1 for i in range(n)]
        res = 0

        for i in range(n):
            for j in range(i + 1, n):
                d = manhattan(points[i], points[j])
                heap.append((d, (i, j)))

        heapq.heapify(heap)

        while heap:
            d, (i, j) = heapq.heappop(heap)
            root1 = find(roots, i)
            root2 = find(roots, j)

            if root1 != root2:
                res += d
                if size[root1] < size[root2]:
                    roots[root1] = root2
                    size[root2] += size[root1]
                    if size[root2] == n: break
                else:
                    roots[root2] = root1
                    size[root1] += size[root2]
                    if size[root1] == n: break

        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        L = len(points)
        res = 0
        con = {}
        father = {i:i for i in range(L)}
        def find(pidx):
            if father[pidx] == pidx:
                return pidx
            return find(father[pidx])
        def union(p,q):
            if p != q:
                if p < q:
                    father[q] = p
                else:
                    father[p] = q
        for i,p in enumerate(points):
            for j,p2 in enumerate(points):
                if i!=j and (j,i) not in list(con.keys()):
                    d = self.dis(p,p2)
                    con[(i,j)] = d
        k = sorted(con, key = lambda x :con[x])
        count = 0
        for e in k:
            x,y = e[0],e[1]
            fx, fy= find(x), find(y)
            if fx!=fy:
                union(fx,fy)
                count += 1
                res += con[e]
            if count == L-1:
                break
        return res
            
    def dis(self, p, x):
        d = abs(x[1]-p[1]) + abs(x[0]-p[0])
        return d


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def find(i):
            if parent[i] == i:
                return i
            return find(parent[i])
        def union(p1,p2):
            if size[p1] > size[p2]:
                p1,p2=p2,p1
            parent[p1] = p2
            size[p2] += size[p1]
            
        if len(points) <= 1:
            return 0
        dist = []
        for i in range(len(points)):
            for j in range(i+1,len(points)):
                d = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                dist.append((d,i,j))
        dist.sort()
        #print(dist)
        edge = 0
        res = 0
        parent = list(range(len(points)))
        size = [1]*len(points)
        for d,n1,n2 in dist:
            p1,p2 = find(n1),find(n2)
            if p1 == p2:
                continue
            res += d
            union(p1,p2)
            edge += 1
            if edge == len(points)-1:
                return res
                
        
    



class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        edges = []
        
        def distance(point1, points):
            return abs(point1[0]-point2[0]) + abs(point1[1]-point2[1])
        
        for i,point1 in enumerate(points):
            for j, point2 in enumerate(points[i+1:]):
                edges.append((i,j+i+1, distance(point1,point2)))

        edges = sorted(edges, key = lambda x: -x[2])
        
        union = list(range(n))
        rank = [1]*n
        
        def find(x):
            if union[x]!=x:
                union[x] = find(union[x])
            return union[x]
        
        def connect(x, y):
            xr, yr = find(x), find(y)
            if rank[xr] > rank[yr]:           
                union[yr] = xr
                rank[xr] += rank[yr]
            else:
                union[xr] = yr
                rank[yr] += rank[xr]
        
        result= 0
        times = 0
        while(edges and times < n-1):
            p1, p2, dis = edges.pop()    
            if find(p1)!=find(p2):
                connect(p1, p2)
                result += dis
                times +=1 
        print(rank)        
        return result


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) == 1: return 0
        n = len(points)
        heap = []
        dic = collections.defaultdict(list)
        #calculate all the distances and put them in a heap
        for i in range(n):
            for j in range(i + 1, n):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                dic[i].append((dist, j))
                dic[j].append((dist, i))
        #add edges connected to 0 to heap    
        res, count, visited, heap = 0, 0, [0] * n, dic[0]
        visited[0] = 1
        heapq.heapify(heap)
        while heap:
            dist, i = heapq.heappop(heap)
            if not visited[i]:
                res += dist
                count += 1
                visited[i] = 1
                if count == n - 1:
                    return res
                for record in dic[i]:
                    heapq.heappush(heap, record)
    


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        L = len(points)
        res = 0
        con = {}
        
        father = {i:i for i in range(L)}
        
        def find(pidx):
            if father[pidx] == pidx:
                return pidx
            return find(father[pidx])
        
        def union(p,q):
            if p != q:
                if p < q:
                    father[q] = p
                else:
                    father[p] = q
\t\t#Step 1
        for i,p in enumerate(points):
            for j,p2 in enumerate(points):
                if i!=j and (j,i) not in con.keys():
                    d = self.dis(p,p2)
                    con[(i,j)] = d
        k = sorted(con, key = lambda x :con[x])
\t\t#Step 2
        count = 0
        for e in k:
            x,y = e[0],e[1]
            fx, fy= find(x), find(y)
            if fx!=fy:
                union(fx,fy)
                count += 1
                res += con[e]
            if count == L-1:
                break
        return res
            
    def dis(self, p, x):
        d = abs(x[1]-p[1]) + abs(x[0]-p[0])
        return d

from collections import defaultdict
import heapq

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        dist = defaultdict(lambda: defaultdict(int))
        n = len(points)
        
        if n <= 1: return 0
        if n == 2:
            return abs(points[0][0] - points[1][0]) + abs(points[0][1] - points[1][1])
        
        for i in range(n - 1):
            for j in range(i + 1, n):
                dist[j][i] = dist[i][j] = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                
        seen = set()
        start = 0
        seen.add(start)
        heap = []
        
        for k, v in list(dist[start].items()):
            heapq.heappush(heap, (v, k))
            
        ans = 0
        while heap:
            if len(seen) == len(points):
                return ans
            
            d, node = heapq.heappop(heap)
            if node not in seen:
                seen.add(node)
                ans += d
                for k, v in list(dist[node].items()):
                    heapq.heappush(heap, (v, k))
        
        
            
                


from collections import Counter, defaultdict, OrderedDict, deque
from bisect import bisect_left, bisect_right
from functools import reduce, lru_cache
from typing import List
import itertools
import math
import heapq
import string
true = True
false = False
MIN, MAX, MOD = -0x3f3f3f3f, 0x3f3f3f3f, 1000000007


#
# @lc app=leetcode id=1584 lang=python3
#
# [1584] Min Cost to Connect All Points
#
# https://leetcode.com/problems/min-cost-to-connect-all-points/description/
#
# algorithms
# Medium (31.62%)
# Total Accepted:    1.7K
# Total Submissions: 5.4K
# Testcase Example:  '[[0,0],[2,2],[3,10],[5,2],[7,0]]'
#
# You are given an array points representing integer coordinates of some points
# on a 2D-plane, where points[i] = [xi, yi].
#
# The cost of connecting two points [xi, yi] and [xj, yj] is the manhattan
# distance between them: |xi - xj| + |yi - yj|, where |val| denotes the
# absolute value of val.
#
# Return the minimum cost to make all points connected. All points are
# connected if there is exactly one simple path between any two points.
#
#
# Example 1:
#
#
#
#
# Input: points = [[0,0],[2,2],[3,10],[5,2],[7,0]]
# Output: 20
# Explanation:
#
# We can connect the points as shown above to get the minimum cost of 20.
# Notice that there is a unique path between every pair of points.
#
#
# Example 2:
#
#
# Input: points = [[3,12],[-2,5],[-4,1]]
# Output: 18
#
#
# Example 3:
#
#
# Input: points = [[0,0],[1,1],[1,0],[-1,1]]
# Output: 4
#
#
# Example 4:
#
#
# Input: points = [[-1000000,-1000000],[1000000,1000000]]
# Output: 4000000
#
#
# Example 5:
#
#
# Input: points = [[0,0]]
# Output: 0
#
#
#
# Constraints:
#
#
# 1 <= points.length <= 1000
# -10^6 <= xi, yi <= 10^6
# All pairs (xi, yi) are distinct.
#
#
#
class Solution:
    def minCostConnectPoints(self, ps: List[List[int]]) -> int:
        n = len(ps)
        if n < 2: return 0
        keys, visited = [MAX] * n, [False] * n
        keys[0] = 0
        cost = 0
        for _ in range(n):
            idx, n_min = 0, MAX
            for j in range(n):
                if not visited[j] and keys[j] < n_min:
                    idx, n_min = j, keys[j]
            visited[idx] = True
            cost += n_min
            for j in range(n):
                if not visited[j]:
                    weight = abs(ps[idx][0] - ps[j][0]) + abs(ps[idx][1] -
                                                              ps[j][1])
                    if weight < keys[j]:
                        keys[j] = weight

        return cost


sol = Solution()

points = [[0, 0], [2, 2], [3, 10], [5, 2], [7, 0]]
# points = [[3, 12], [-2, 5], [-4, 1]]
# points = [[0, 0], [1, 1], [1, 0], [-1, 1]]
# points = [[-1000000, -1000000], [1000000, 1000000]]
# points = [[0, 0]]


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def dist(p1, p2):
            x1,y1 = p1
            x2,y2 = p2
            return abs(x1-x2) + abs(y1-y2)
        
        n = len(points)
        d = [float('inf')] * n
        cur = 0
        ans = 0
        seen = set()
        
        for i in range(n-1):
            seen.add(cur)
            for j,p in enumerate(points):
                if j in seen: continue
                d[j] = min(d[j], dist(points[cur],points[j]))
            
            min_d, nxt = min((d,j) for j,d in enumerate(d))
            d[nxt] = float('inf') #don't count distance with self
            cur = nxt
            ans += min_d
        
        return ans
                                   
                


class Solution:
    def minCostConnectPoints(self, points):
        N = len(points)
        dist = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        connections = [[u, v, dist(points[u], points[v])] for u in range(N-1) for v in range(u+1, N)]
        connections.sort(key = lambda x:x[2])
        parent, cnt, res = [i for i in range(N+1)], N-1, 0
        def find(v):
            while parent[v] != parent[parent[v]]:
                parent[v] = parent[parent[v]]
            return parent[v]
        for u, v, cost in connections:
            pu, pv = find(u), find(v)
            if pu != pv:
                parent[pu] = pv
                cnt -= 1
                res += cost
                if cnt == 0:
                    break
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        distance = lambda u, v: abs(points[u][0] - points[v][0]) + abs(points[u][1] - points[v][1])
        
        graph = defaultdict(list)
        for u in range(n):
            for v in range(u + 1, n):
                dist = distance(u, v)
                graph[u].append((dist, v))
                graph[v].append((dist, u))
        
        count = 1
        cost = 0
        visited = [True] + [False] * (n - 1)
        heap = graph[0][:]
        heapify(heap)
        
        while heap:
            dist, u = heappop(heap)
            if not visited[u]:
                visited[u] = True
                count += 1
                cost += dist
                for link in graph[u]:
                    heappush(heap, link)
            
            if count >= n:
                break
        
        return cost


from heapq import *
class Solution:
    def minCostConnectPoints(self, A: List[List[int]]) -> int:
        manhattan = lambda p1, p2: abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        n, g = len(A), collections.defaultdict(list)
        
        for i in range(n):
            for j in range(i+1, n):
                d = manhattan(A[i], A[j])
                g[i].append((d, j))
                g[j].append((d, i))
                
        cnt, ans, seen, q = 1, 0, [0] * n, g[0]
        seen[0] = 1
    
        heapify(q)
        
        while q:
            d, k = heappop(q)
            if seen[k]: continue
            seen[k], ans, cnt = 1, ans + d, cnt + 1
            for r in g[k]: heappush(q, r)
            if cnt >= n:
                break
        return ans


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def getDist(p1, p2):
            # |xi - xj| + |yi - yj|
            xi, yi = p1
            xj, yj = p2
            return abs(xi - xj) + abs(yi - yj)
        
        graph = collections.defaultdict(list)
        for i in range(len(points)):
            for j in range(len(points)):
                graph[i].append((getDist(points[i], points[j]), j))
        start = 0
        res = 0
        visited = { start }
        min_heap = []
        for cost, adj in graph[start]:
            heapq.heappush(min_heap, (cost, adj))
        while len(visited) < len(points) and min_heap:
            cost, next_node = heapq.heappop(min_heap)
            if next_node not in visited:
                visited.add(next_node)
                res += cost
                for next_cost, adj in graph[next_node]:
                    if adj not in visited:
                        heapq.heappush(min_heap, (next_cost, adj))
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n, dists = len(points), collections.defaultdict(list)
        if n <= 1:
            return 0
        for i in range(n-1):
            for j in range(i+1, n):
                dist = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                dists[i].append((dist, j))
                dists[j].append((dist, i))
        res, visited, cnt, heap = 0, [0]*n, 1, dists[0]
        visited[0] = 1
        heapq.heapify(heap)
        while heap:
            dist, i = heappop(heap)
            if not visited[i]:
                res += dist
                cnt += 1
                for ele in dists[i]:
                    heappush(heap, ele)
                visited[i] = 1
            if cnt == n:
                return res

# Solve Leetcode 1584. Min Cost to Connect All Points using the boilerplate code below, and then implement Kruskal's algorithm to solve the problem. Use self.distance(pointA, pointB) to find distance (weight of edge) between two nodes.

class DisjointSet:
    def __init__(self, points):
        self.parent = {}
        self.rank = {}
        for point in points:
            self.parent[point] = point
            self.rank[point] = 1

    def find(self, x):
        if self.parent[x] == x:
            return x
        self.parent[x] = self.find(self.parent[x])
        return self.parent[x]

    def union(self, x, y):
        x_set = self.find(x)
        y_set = self.find(y)

        if self.rank[x_set] < self.rank[y_set]:
            self.parent[x_set] = y_set
        elif self.rank[x_set] > self.rank[y_set]:
            self.parent[y_set] = x_set
        else:
            self.parent[x_set] = y_set
            self.rank[y_set] += 1

        
from collections import defaultdict
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        points = [tuple(point) for point in points]
        disjoint_set = DisjointSet(points)
    
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                distance = self.distance(points[i], points[j])
                edges.append((distance, points[i], points[j]))
        
        edges.sort()
        answer = 0
        times = 0
        for distance, nodeA, nodeB in edges:
            if disjoint_set.find(nodeA) != disjoint_set.find(nodeB):
                disjoint_set.union(nodeA, nodeB)
                answer += distance
                times += 1
            if times == len(points)-1:
                return answer
        return answer
        
        


    def distance(self, pointA, pointB):
        return abs(pointA[0] - pointB[0]) + abs(pointA[1] - pointB[1])

import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        n, c = len(points), collections.defaultdict(list)
        for i in range(n):
            for j in range(i+1, n):
                d = manhattan(points[i], points[j])
                c[i].append((d, j))
                c[j].append((d, i))
        visited = set()
        visited.add(0)
        res = 0
        heap = c[0]
        
        heapq.heapify(heap)

        while len(visited)<n:
            d, j = heapq.heappop(heap)
            if j not in visited:
                visited.add(j)
                res += d
                for record in c[j]:
                    heapq.heappush(heap,record)
                    
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n == 1:
            return 0
        dis = [(abs(points[i][0] - points[j][0])+abs(points[i][1] - points[j][1]),i,j) for i in range(n) for j in range(i+1,n)]
        heapq.heapify(dis)
        father = list(range(n))
        def getfather(x):
            if father[x] != x:
                father[x] = getfather(father[x])
            return father[x]
        def union(x,y):
            fx = getfather(x)
            fy = getfather(y)
            if fx == fy:
                return False
            father[fx] = fy
            return True
        step = 0
        res = 0
        while dis:
            d,i,j = heapq.heappop(dis)
            if union(i,j):
                res += d
                step += 1
                if step == n - 1:
                    break
        return res


from heapq import heappush, heappop
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def helper(i, j, p):
            return abs(p[j][0] - p[i][0]) + \\
                   abs(p[j][1] - p[i][1])
        
        g = defaultdict(lambda: {}); n = len(points)
        for i in range(n-1):
            for j in range(i+1, n):
                g[i][j] = g[j][i] = helper(i,j,points)

                
        visited = set(); res = 0; q = []; cnt=0
        heappush(q, (0, 0)) # u:0, cost:0
        while q:
            cost, u = heappop(q)
            if u in visited: continue
            res += cost
            cnt += 1
            for v, w in g[u].items():
                heappush(q, (w, v))
            visited.add(u)
            if cnt >= n: break
        return res
        
        
    
\"\"\"
[[0,0],[2,2],[3,10],[5,2],[7,0]]
[[3,12],[-2,5],[-4,1]]
[[0,0],[1,1],[1,0],[-1,1]]
[[-1000000,-1000000],[1000000,1000000]]
[[0,0]]
\"\"\"            

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        n, c = len(points), collections.defaultdict(list)
        for i in range(n):
            for j in range(i+1, n):
                d = manhattan(points[i], points[j])
                c[i].append((d, j))
                c[j].append((d, i))
        cnt, ans, visited, heap = 1, 0, [0] * n, c[0]
        visited[0] = 1
        heapq.heapify(heap)
        while heap:
            d, j = heapq.heappop(heap)
            if not visited[j]:
                visited[j], cnt, ans = 1, cnt+1, ans+d
                for record in c[j]: heapq.heappush(heap, record)
            if cnt >= n: break        
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) < 2:
            return 0
        
        def dist(p1, p2):
            return abs(points[p1][0] - points[p2][0]) + abs(points[p1][1] - points[p2][1])
        
        edges = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                edges.append((i,j,dist(i, j)))
        edges = sorted(edges, key=lambda x : x[2])
        #print(edges)
        
        total = 0
        group = [x for x in range(len(points))]
        while sum(group) > 0:
            x, y, w = edges.pop(0)
            #print(group)
            #print(f\"{x} {y} {w} {total} {edges}\")
            if group[x] == group[y]:
                continue
            
            gx = group[x]
            gy = group[y]
            g = min(gx, gy)
            for i in range(len(group)):
                if group[i] == gy or group[i] == gx:
                    group[i] = g
                #print(f\"\\t{g} {i} {group}\")
            total += w
        #print(group)
        #print(f\"{x} {y} {w} {total} {edges}\")            
        return total


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        distances = []
        n = len(points)
        for i in range(n-1):
            for j in range(i+1, n):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                distances.append([(i,j), dist])
        distances.sort(key = lambda x: x[1])
        # print(distances)
        parent = [i for i in range(n)]
        size = [1 for _ in range(n)]
        def find(x):
            if parent[x] == x:
                return x
            else:
                return find(parent[x])
        def union(px, py):
            # px, py = find(x), find(y)
            # if px != py:
            if size[px] < size[py]:
                px, py = py, px
            parent[py] = px
            size[px] += size[py]
        count = 0
        ans = 0
        for (x,y), dist in distances:
            px, py = find(x), find(y)
            if px != py:
                union(px, py)
                count += 1
                ans += dist
                if count == n-1:
                    break
        return ans

class DSU:
    def __init__(self, size):
        self.par = list(range(size))
    def find(self,x): 
        if self.par[x] != x: 
            return self.find(self.par[x])
        return self.par[x]
    def union (self, x, y):
        self.par[self.find(x)] = self.find(y)

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def distance (u, v): 
            return abs(u[0] - v[0]) + abs(u[1] - v[1])
        points_dist = collections.defaultdict(dict)
        edges = []
        for i, p1 in enumerate(points): 
            for j in range(i + 1, len(points)):
                points_dist[i][j] = distance(points[i], points[j])
                heapq.heappush(edges, (distance(points[i], points[j]), i, j))
        res = 0
        count = 0 
        dsu = DSU(len(points))
        while count < len(points) - 1:
            distance, x , y = heapq.heappop(edges)
            p_x, p_y = dsu.find(x), dsu.find(y)
            if p_x != p_y:
                count += 1
                res += distance
                dsu.union(x, y)
        return res

# Solve Leetcode 1584. Min Cost to Connect All Points using the boilerplate code below, and then implement Kruskal's algorithm to solve the problem. Use self.distance(pointA, pointB) to find distance (weight of edge) between two nodes.

class DisjointSet:
    def __init__(self, points):
        self.parent = {}
        self.rank = {}
        for point in points:
            self.parent[point] = point
            self.rank[point] = 1

    def find(self, x):
        if self.parent[x] == x:
            return x
        self.parent[x] = self.find(self.parent[x])
        return self.parent[x]

    def union(self, x, y):
        x_set = self.find(x)
        y_set = self.find(y)

        if self.rank[x_set] < self.rank[y_set]:
            self.parent[x_set] = y_set
        elif self.rank[x_set] > self.rank[y_set]:
            self.parent[y_set] = x_set
        else:
            self.parent[x_set] = y_set
            self.rank[y_set] += 1

        
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        points = [tuple(point) for point in points]
        disjoint_set = DisjointSet(points)
        
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                distance = self.distance(points[i], points[j])
                edges.append((distance, points[i], points[j]))
                
        answer = 0
        times = 0
        edges.sort()
        for distance, nodeA, nodeB in edges:
            if disjoint_set.find(nodeA) != disjoint_set.find(nodeB):
                disjoint_set.union(nodeA, nodeB)
                answer += distance
                times += 1
            if times == len(points) - 1:
                return answer
        return answer


    def distance(self, pointA, pointB):
        return abs(pointA[0] - pointB[0]) + abs(pointA[1] - pointB[1])

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        n, c = len(points), collections.defaultdict(list)
        for i in range(n):
            for j in range(i+1, n):
                d = manhattan(points[i], points[j])
                c[i].append((d, j))
                c[j].append((d, i))
        cnt, ans, visited, heap = 1, 0, [0] * n, c[0]
        visited[0] = 1
        heapq.heapify(heap)
      
        while heap:
            d, j = heapq.heappop(heap)
          
            if not visited[j]:
                visited[j], cnt, ans = 1, cnt+1, ans+d
                for record in c[j]: heapq.heappush(heap, record)
            if cnt >= n: break        
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        dis = []
        for i in range(len(points)):
            for j in range(i, len(points)):
                dis.append(
                    (
                        abs(points[i][0] - points[j][0])
                        + abs(points[i][1] - points[j][1]),
                        i,
                        j,
                    )
                )
        dis = sorted(dis, key=lambda x: x[0])

        joined = 1
        cost = 0
        parents = [x for x in range(len(points))]

        def find(x):
            if parents[x] != x:
                parents[x] = find(parents[x])
            return parents[x]

        for edge in dis:
            if find(edge[1]) != find(edge[2]):
                joined += 1
                cost += edge[0]
                parents[find(edge[1])] = edge[2]
            if joined == len(points):
                return cost


from collections import defaultdict

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        edges = []
        
        n = len(points)
        
        parent = defaultdict(lambda:-1)
        
        # ----------------------------------------------
        
        def find_parent(x,y):
            
            if parent[(x,y)] == -1:
                return x, y
            
            else:
                #print( parent[(x,y)] )
                parent[(x,y)] = find_parent( *parent[(x,y)] )
                return parent[(x,y)]
        
        # ----------------------------------------------
        
        def merge(x1, y1, x2, y2):
            
            if x1 == x2 and y1 == y2:
                return
            
            # x2, y2 merge to x1, y1
            parent_of_i = find_parent( x1, y1 )
            parent_of_j = find_parent( x2, y2 )
            
            parent[parent_of_j] = parent_of_i
            
        # ----------------------------------------------
        
        def dist(pi, pj):
            
            return abs( pi[0] - pj[0] ) + abs( pi[1] - pj[1] )
        
        # ----------------------------------------------
        
        for i in range(n-1):
            for j in range(i+1, n):
                
                cost = dist(points[i], points[j])
                
                edges.append( ( cost, tuple(points[i]), tuple(points[j]) ) )
                
        edges.sort(key = lambda e: e[0] )
        
        min_cost = 0
        selected_edge = 0
        
        for edge in edges:
            
            node_v, node_u = edge[1], edge[2]
            if find_parent( *node_v ) == find_parent( *node_u ):
                continue
            
            merge( *(node_v+node_u) )
            min_cost += edge[0]
            selected_edge += 1
            
            if selected_edge == n-1:
                break
                
        return min_cost


# int minCostConnectPoints(vector<vector<int>>& ps) {
#     int n = ps.size(), res = 0, i = 0, connected = 0;
#     vector<bool> visited(n);
#     priority_queue<pair<int, int>> pq;
#     while (++connected < n) {
#         visited[i] = true;
#         for (int j = 0; j < n; ++j)
#             if (!visited[j])
#                 pq.push({-(abs(ps[i][0] - ps[j][0]) + abs(ps[i][1] - ps[j][1])), j});
#         while (visited[pq.top().second])
#             pq.pop();
#         res -= pq.top().first;
#         i = pq.top().second;
#         pq.pop();
#     }
#     return res;
# }

class Solution:
    def minCostConnectPoints(self, a: List[List[int]]) -> int:                        
        n, vis, ans, pq, i = len(a), set([0]), 0, [], 0
        rem = set(range(1, n))
        while len(vis) < n:            
            for j in rem: heappush(pq, (abs(a[i][0]-a[j][0]) + abs(a[i][1] - a[j][1]), j))
            while pq[0][1] in vis: heappop(pq)
            val, i = heappop(pq)
            vis.add(i); rem.discard(i)
            ans += val            
        return ans                                            

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        groups = [a for a in range(len(points))]
        for index_a in range(len(points)):
            for index_b in range(index_a+1, len(points)):
                edge = (index_a, index_b, abs(points[index_a][0] - points[index_b][0]) + abs(points[index_a][1] - points[index_b][1]))
                edges.append(edge)
        edges.sort(key = lambda a:a[2])
        
        
        def find(a):
            return a if groups[a] == a else find(groups[a])
        
        def union(a, b):
            group_a = find(a)
            group_b = find(b)
            if group_a != group_b:
                return group_a, group_b
            return 
        
        sum = 0
        while len(set(groups)) != 1:
            edge = edges.pop(0)
            merged = union(edge[0], edge[1])
            if merged is not None:
                groups = [merged[1] if x == merged[0] else x for x in groups]
                sum += edge[2]
        return sum

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        distances, n = {i: [] for i in range(len(points))}, len(points)
        for i in range(n-1):
            for j in range(i+1, n):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                distances[i].append((dist, j))
                distances[j].append((dist, i))
        import heapq
        heap = distances[0]
        heapq.heapify(heap)
        ans = 0
        count = 0
        visited = set([0])
        while heap:
            dist, j = heapq.heappop(heap)
            if j not in visited:
                visited.add(j)
                ans += dist
                count += 1
                for x in distances[j]:
                    heapq.heappush(heap, x)
            if count == n -1: break
        return ans
            
    
                
        
        


class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:

        def manhattan(x, y):
            return abs(x[0]-y[0]) + abs(x[1]-y[1])

        ans, n = 0, len(p)
        seen = set()
        vertices = [(0, (0, 0))] # (distance, (last_vertice, cur_vertice))

        while len(seen) < n:
            # print(vertices, seen)
            d, (u, v) = heapq.heappop(vertices)            
            if v in seen: continue
            ans += d
            seen.add(v)
            for j in range(n):
                if j not in seen and j!=v:
                    heapq.heappush(vertices, (manhattan(p[j], p[v]), (v, j)))

        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        def dist(a, b):
            return abs(a[0] - b[0]) + abs(a[1] - b[1])
        edges = []
        for i in range(n):
            for j in range(i + 1, n):
                edges.append((dist(points[i], points[j]), i, j))
        edges.sort()
        cost = 0
        #print(edges)
        parent = [i for i in range(n)]
        size = [1] * n
        def find(a):
            if parent[a] == a:
                p = a
            else:
                p = find(parent[a])
            parent[a] = p
            return p
            
        def union(a, b):
            pa = find(a)
            pb = find(b)
            if pa != pb:
                parent[pa] = pb
                size[pb] += size[pa]
                if size[pb] == n:
                    return True
            return False
        
        for e in edges:
            a, b = e[1], e[2]
            pa, pb = find(a), find(b)
            if pa != pb:
                cost += e[0]
                if (union(e[1], e[2])):
                    break
        return cost
                             
                
                


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)

        root = [i for i in range(n+1)]
        def find(x):
            if root[x] != x:
                root[x] = find(root[x])
            return root[x]

        def uni(x, y):
            x, y = find(x), find(y)
            if x == y: return 0
            root[x] = y
            return 1 

        def distance(a, b):
            return abs(a[0] - b[0]) + abs(a[1] - b[1])

        routes = []
        unconnected = n - 1
        costs = 0
        for i in range(n):
            for j in range(i + 1, n): 
                routes.append([distance(points[i], points[j]), i, j])
        routes.sort(key=lambda l: l[0], reverse=True)
        while unconnected:
            route = routes.pop()
            if uni(route[1], route[2]):
                costs += route[0]
                unconnected -= 1
        return costs

class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:
        
        def find(x):
            if dp[x]!=x:
                dp[x]=find(dp[x])
            return dp[x]

        def uni(x,y):
            x,y=find(x),find(y)
            if x!=y:
                dp[x]=find(y)
                return False   
            return True
            
        n=len(p)
        dp=list(range(n))    

        pool=sorted((abs(p[i][0]-p[j][0])+abs(p[i][1]-p[j][1]),i,j) for i in range(n) for j in range(i+1,n))
        
        ct=res=0
        

        for dis,u,v in pool:
            if not uni(u,v):
                res+=dis
                ct+=1
                if ct==n-1:
                    break
        return res

from pprint import pprint
class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:
        
        def getMinNode(n, val, mst):
            mn = math.inf
            mn_idx = None
            for i in range(n):
                if (mst[i] == False and val[i] < mn):
                    mn = val[i]
                    mn_idx = i
            return mn_idx
        
        res = 0
        n = len(p)
        parent = [None] * n
        parent[0] = -1
        
        dists = [[0] * n for _ in range(n)]
        for i in range(n):
            for j in range(n):
                if i != j:
                    dists[i][j] = dists[j][i] = abs(p[i][0] - p[j][0]) + abs(p[i][1] - p[j][1])
        
        # pprint(dists)
        mst = [False] * n
        val = [math.inf] * n
        val[0] = 0
        for i in range(n - 1):
            u = getMinNode(n, val, mst)
            mst[u] = True
            for v in range(n):
                if dists[u][v] and mst[v] == False and dists[u][v] < val[v]:
                    val[v] = dists[u][v]
                    parent[v] = u
        for i in range(1, n):
            # print(dist[parent[i]])
            # print(dist)
            res += dists[parent[i]][i]
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        n, c = len(points), collections.defaultdict(list)
        for i in range(n):
            for j in range(i+1, n):
                d = manhattan(points[i], points[j])
                c[i].append((d, j))
                c[j].append((d, i))
        cnt, ans, visited, heap = 1, 0, [0] * n, c[0]
        visited[0] = 1
        heapq.heapify(heap)
        while heap:
            d, j = heapq.heappop(heap)
            if not visited[j]:
                visited[j], cnt, ans = 1, cnt+1, ans+d
                for record in c[j]: heapq.heappush(heap, record)
            if cnt >= n: break        
        return ans    
    def minCostConnectPoints3(self, points: List[List[int]]) -> int:
        n = len(points)
        if len(points) == 1: return 0
        res = 0
        curr = 0 # select a random point as the starting point
        dis = [math.inf] * n
        explored = set()
        
        for i in range(n - 1):
            x0, y0 = points[curr]
            explored.add(curr)
            for j, (x, y) in enumerate(points):
                if j in explored: continue
                dis[j] = min(dis[j], abs(x - x0) + abs(y - y0))
                
            delta, curr = min((d, j) for j, d in enumerate(dis)) 
            dis[curr] = math.inf
            res += delta
            
        return res    
    def minCostConnectPoints2(self, P: List[List[int]]) -> int:
        res=0
        n=len(P)
        px,py=P[0]
        seen={0}
        todo=set(range(1,n))
        while len(seen)<n:
            mn=float('inf')
            used=-1
            for i in todo:
                cx,cy=P[i]
                for j in seen:
                    px,py=P[j]
                    can=abs(cx-px)+abs(cy-py)
                    if can <mn:
                        mn=can
                        used=i
            res+=mn
            todo.remove(used)
            seen.add(used)
        return res

    # def minCostConnectPoints1(self, P: List[List[int]]) -> int:
    #     P.sort(key=lambda a:(abs(a[0])+abs(a[1])))
    #     print(P)
    #     res=0
    #     px,py=P[0]
    #     for cx,cy in P[1:]:
    #         res+=abs(cx-px)+abs(cy-py)
    #         px,py=cx,cy
    #     return res    


from collections import defaultdict
    
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def find(x):
            if x != parent[x]:
                parent[x] = find(parent[x])
            return parent[x]

        total_points = len(points)    
        parent = list(range(total_points))
        weight_matrix = []
        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) +abs(p1[1]-p2[1])
   
        for i in range(total_points):
            for j in range(i+1, total_points):
                dist = manhattan(points[i],points[j])
                weight_matrix.append((i,j, dist))
                
        cost = 0
        for u, v, w in sorted(weight_matrix, key=lambda x: x[2] ):
            ru, rv = find(u), find(v)
            if ru == rv:
                continue
            cost += w
            parent[ru] = rv
            
        return cost
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if not points or len(points) == 1:
            return 0
        dist = {}
        for p in range(1,len(points)):
            dist[p] = abs(points[p][0] - points[0][0]) + abs(points[p][1] - points[0][1])
        print(dist)
        cost = 0
        while dist:
            min_k = 0
            min_v = 1e10
            for k,v in list(dist.items()):
                if v < min_v:
                    min_v = v
                    min_k = k
            print((min_k,min_v))
            cost += min_v
            for k,v in list(dist.items()):
                dist[k] = min(dist[k], abs(points[min_k][0] - points[k][0]) + abs(points[min_k][1] - points[k][1]))
            assert dist[min_k] == 0
            del dist[min_k]
            
        return cost
                


from queue import PriorityQueue

class Solution:
    def findParent(self, parents, i):
        if parents[i] is None:
            return i
        else:
            return self.findParent(parents, parents[i])
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) == 0:
            return 0
        
        edges = []
        req_edges = len(points)-1
        dist = 0
        parents = [None] * len(points)
        
        for i, p1 in enumerate(points):
            for j, p2 in enumerate(points):
                if i < j:
                    edges.append([i, j, (abs(p1[0]-p2[0]) + abs(p1[1]-p2[1]))])
        edges = sorted(edges, key=lambda x: x[2])
        
        for edge in edges:
            parent_i = self.findParent(parents, edge[0])
            parent_j = self.findParent(parents, edge[1])
            if parent_i == parent_j:
                continue
            parents[parent_i] = parent_j
            dist += edge[2]

            req_edges -= 1
            if req_edges == 0:
                break
            
        return dist


from collections import defaultdict
import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) < 1: return 0
        
        graph = defaultdict(list)
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                graph[i].append((dist, j))
                graph[j].append((dist, i))
        
        heap, visited, cost = graph[0], set([0]), 0
        heapq.heapify(heap)
        while len(visited) != len(points):
            dist, node = heapq.heappop(heap)
            if node not in visited:
                visited.add(node)
                for edge in graph[node]:
                    heapq.heappush(heap, edge)
                cost += dist
        return cost


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n == 1:
            return 0
        dis = collections.defaultdict(list)
        
        for i in range(n - 1):
            for j in range(i + 1, n):
                length = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                dis[i].append((length, j))
                dis[j].append((length, i))
        
        visit = {0}
        queue = collections.deque([0])
        pull = dis[0]
        heapq.heapify(pull)
        cost = 0
        # print(dis[0])
        while queue and len(visit) != n:
            # print(pull)
            node = queue.popleft()
            can = heapq.heappop(pull)
            while can[1] in visit:
                can = heapq.heappop(pull)
            cost += can[0]
            for ele in dis[can[1]]:
                heapq.heappush(pull, ele)
            visit.add(can[1])
            queue.append(can[1])
        return cost

class Solution:
    def find_min_node(self, n, key, mst_set):
        min, min_node = sys.maxsize, -1
        for i in range(n):
            if not mst_set[i] and key[i] < min:
                min, min_node = key[i], i
        return min_node
    
    def solve(self, n, edges):
        mst_set = [False] * n;
        key = [sys.maxsize] * n;
        parent = [-1] * n;
        
        key[0] = 0
        parent[0] = -1
        
        for i in range(n):
            u = self.find_min_node(n, key, mst_set)
            mst_set[u] = True
            for v in range(n):
                if (not mst_set[v] and edges[u][v] < key[v]):
                    parent[v] = u
                    key[v] = edges[u][v]
        
        res = 0
        for i in range(1, n):
            res += edges[parent[i]][i]
        return res
        
        
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        edges = [[0] * n for _ in range(n)]
        for i in range(n):
            for j in range(n):
                edges[i][j] = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                
        return self.solve(n, edges)


class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:
        n, c = len(p), collections.defaultdict(list)
        for i in range(n):
            for j in range(i+1, n):
                d = abs(p[i][0]-p[j][0]) + abs(p[i][1]-p[j][1])
                c[i].append((d, j))
                c[j].append((d, i))
        cnt, ans, visited, heap = 1, 0, [0] * n, c[0]
        visited[0] = 1
        heapq.heapify(heap)
        while heap:
            d, j = heapq.heappop(heap)
            if not visited[j]:
                visited[j], cnt, ans = 1, cnt+1, ans+d
                for record in c[j]: heapq.heappush(heap, record)
            if cnt >= n: break        
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        cc = [i for i in range(len(points))]
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                d = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((d, i, j))
        edges.sort()
        
        def root(x):
            if cc[x] != x:
                cc[x] = root(cc[x])
            return cc[x]
        def join(x, y):
            rx = root(x)
            ry = root(y)
            if rx != ry:
                cc[rx] = ry
            return rx != ry
        
        cct = len(points)
        cost = 0
        # print('foo')
        for x, i, j in edges:
            if join(i, j):
                cost += x
                # print(x)
                cct -= 1
                if cct == 1:
                    break
        return cost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        n, c = len(points), collections.defaultdict(list)
        for i in range(n):
            for j in range(i+1, n):
                d = manhattan(points[i], points[j])
                c[i].append((d, j))
                c[j].append((d, i))
        cnt, ans, visited, heap = 1, 0, [0] * n, c[0]
        visited[0] = 1
        heapq.heapify(heap)
    
        while heap:
            d, j = heapq.heappop(heap)
            if not visited[j]:
                visited[j], cnt, ans = 1, cnt+1, ans+d
                for record in c[j]: heapq.heappush(heap, record)
            if cnt >= n: break        
        return ans
        
#         if not points or len(points) <= 1:
#             return 0
        
#         heap = []
#         for i in range(len(points)):
#             for j in range(i + 1, len(points)):
#                 p1 = points[i]
#                 p2 = points[j]
#                 dis = abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
#                 heapq.heappush(heap, (dis, i, j))
        
#         self.father = [i for i in range(len(points))]
#         res = 0
#         while heap:
#             dis, u, v = heapq.heappop(heap)
#             root_u = self.find(u)
#             root_v = self.find(v)
#             if root_u == root_v:
#                 continue
#             self.father[max(root_u, root_v)] = min(root_u, root_v)
#             res += dis
        
#         return res
    
#     def find(self, x):
#         if self.father[x] == x:
#             return self.father[x]
#         self.father[x] = self.find(self.father[x])
#         return self.father[x]


class DSU:
    def __init__(self, N):
        self.parent = [i for i in range(N)]
        self.rank = [0] * N
        
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
            
        return self.parent[x]
    
    def union(self, x, y):
        xRoot = self.find(x)
        yRoot = self.find(y)
        
        if xRoot == yRoot:
            return False
        
        if self.rank[xRoot] > self.rank[yRoot]:
            self.parent[yRoot] = xRoot
        elif self.rank[yRoot] > self.rank[xRoot]:
            self.parent[xRoot] = yRoot
        else:
            self.parent[yRoot] = xRoot
            self.rank[xRoot] += 1
            
        return True

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        pq = []
        
        for i in range(N):
            for j in range(i):
                x1, y1 = points[i]
                x2, y2 = points[j]
                dist = abs(x1 - x2) + abs(y1 - y2)
                pq.append((dist, i, j))
                    
        heapify(pq)
        dsu = DSU(N)
        edges = 0
        cost = 0
        
        while edges < N - 1:
            dist, i, j = heappop(pq)
            
            if dsu.union(i, j):
                cost += dist
                edges += 1
                
        return cost
    
# class Solution:
#     def minCostConnectPoints(self, points: List[List[int]]) -> int:
#         N = len(points)
#         graph = defaultdict(list)
        
#         for i in range(N):
#             for j in range(N):
#                 if i != j:
#                     x1, y1 = points[i]
#                     x2, y2 = points[j]
#                     dist = abs(x1 - x2) + abs(y1 - y2)
#                     graph[i].append((j, dist))
#                     graph[j].append((i, dist))
                    
#         pq = [(0, 0)]
#         visited = set()
#         cost = 0
        
#         while len(visited) < N:
#             dist, node = heappop(pq)
            
#             if node not in visited:
#                 visited.add(node)
#                 cost += dist
                
#                 for adj, dist in graph[node]:
#                     if adj not in visited:
#                         heappush(pq, (dist, adj))
                
#         return cost


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        md = lambda p1, p2: abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        n = len(points)
        graph = defaultdict(list)
        for i in range(n):
            for j in range(i+1, n):
                d = md(points[i], points[j])
                graph[i].append((d, j))
                graph[j].append((d, i))
        
        visited = {0}
        q = graph[0]
        heapq.heapify(q)
        res = 0
        
        while len(q)!=0:
            d, j = heapq.heappop(q)
            if j not in visited:
                visited.add(j)
                res += d
                for item in graph[j]:
                    heapq.heappush(q, item)
            if len(visited) == n:
                break
        
        return res
        


from collections import defaultdict
from heapq import heappop, heappush, heapify
def prim(N, E):
    edges = defaultdict(list)
    for x, y, c in E:
        edges[x].append((c, y))
        edges[y].append((c, x))
    heap = []
    heappush(heap, (0, 0))
    cnt = 0
    visited = {}
    ans = 0
    while heap:
        c, n = heappop(heap)
        if n in visited: continue
        visited[n] = 1
        ans += c
        for e in edges[n]:
            heappush(heap, e)
        cnt += 1
        if cnt >= N:
            break
    return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        E = []
        n = len(points)
        for i in range(n):
            for j in range(i+1, n):
                d = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                E.append((i, j, d))
        ans = prim(n, E)
        return ans


class Solution:     
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        n, c = len(points), collections.defaultdict(list)
        for i in range(n):
            for j in range(i+1, n):
                d = manhattan(points[i], points[j])
                c[i].append((d, j))
                c[j].append((d, i))
        cnt, ans, visited, heap = 1, 0, [0] * n, c[0]
        visited[0] = 1
        heapq.heapify(heap)
        while heap:
            d, j = heapq.heappop(heap)
            if not visited[j]:
                visited[j], cnt, ans = 1, cnt+1, ans+d
                for record in c[j]: heapq.heappush(heap, record)
            if cnt >= n: break        
        return ans

        
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        #基本功不扎实呀，是一个minimum spanning tree
        visited = set()
        graph = [[0]*len(points) for _ in range(len(points))]
        for i in range(len(points)):
            for j in range(i+1,len(points)):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                graph[i][j] = graph[j][i] = dist 
        heap = [(0,0)]
        asr = 0
        for i in range(len(points)):
            dist,idx = heapq.heappop(heap)
            while heap and idx in visited:
                dist,idx = heapq.heappop(heap)
            visited.add(idx)
            asr+=dist
            for v in range(len(points)):
                if v not in visited:
                    heapq.heappush(heap,(graph[idx][v],v))
        return asr

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
    # #没有现成的edge list，想到当遍历到某一个点才现算它与其他点的权重值并压进pqueue，故考虑首选Prim算法而不是Krusal (1000ms, 95%faster)
    #     N = len(points)
    #     seen = set()
    #     cost = 0
    #     cnt = 0
    #     pq = [(0, 0)]
    #     while pq:
    #         c, i = heapq.heappop(pq)
    #         if i in seen: continue
    #         cost += c
    #         cnt += 1
    #         if cnt == N: return cost    #early termination. another advantage of using Prim over Krusal
    #         seen.add(i)
    #         pt_x, pt_y = points[i]
    #         for j in range(N):
    #             if j in seen: continue
    #             nei_x, nei_y = points[j]
    #             nei_c = abs(pt_x - nei_x) + abs(pt_y - nei_y)
    #             heapq.heappush(pq, (nei_c, j))
    #     return cost
     
        
    #也操练一下Kruskal...
        N = len(points)
        dsu = list(range(N))
        def find(i):
            if dsu[i] != i: dsu[i] = find(dsu[i])
            return dsu[i]
        def union(i, j):
            dsu[find(j)] = find(i)
       
        pq = []
        cost = 0
        #push in all edges, sort by wight_cost
        for i in range(N):
            for j in range(i+1, N):
                i_x, i_y = points[i]
                j_x, j_y = points[j]
                c = abs(i_x - j_x) + abs(i_y - j_y)
                pq.append((c, i, j))
        pq.sort(key = lambda x: x[0], reverse = True)
        # print(pq)
        while pq:
            c, i ,j = pq.pop()
            if find(i) == find(j): continue
            cost += c
            union(i, j)
        return cost
        
        
        
        
        
        
        
        
#         res = 0
#         N = len(points)
#         visited = [[0] * N for _ in range(N)]
#         if len(points) == 1: return 0
#         DP = [[float('inf')] * N for _ in range(N)]
        
#         for i in range(N):
#             # min_dist = float('inf')
#             for j in range(i+1, N):
#                 # print(i, i, j)
#                 x, y = points[i], points[j]
#                 curr_dist = DP[i][j] = DP[j][i] = abs(x[0] - y[0]) + abs(x[1] - y[1])
#                 # if curr_dist < min_dist: 
#                 #     min_dist = curr_dist
#             min_dist = min(DP[i])
#             j = DP[i].index(min_dist) 
#             if not visited[i][j]:
#                 res += min_dist
#                 visited[i][j] = visited[j][i] = 1
#                 DP[i][j] = DP[j][i] = float('inf')
#             print(min_dist, DP)
#             # res += min_dist
#         return res
                


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
      edges = []
      for i in range(len(points)):
        for j in range(i+1, len(points)):
          distance = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
          edges.append((i, j, distance))
      
      edges.sort(key=itemgetter(2))
      
      numComponents = len(points)
      groups = [i for i in range(len(points))]
      size = [1] * len(points)
      
      def find(x):
        if groups[x] == x:
          return x
        groups[x] = find(groups[x])
        return groups[x]
      
      cost = 0
      
      for edge in edges:
        p1 = edge[0]
        p2 = edge[1]
        
        root1 = find(p1)
        root2 = find(p2)
        
        if root1 != root2:
          if size[p1] < size[p2]:
            groups[root1] = groups[root2]
            size[root2] += size[root1]
          else:
            groups[root2] = groups[root1]
            size[root1] += size[root2]
          cost += edge[2]
          numComponents -= 1
          
          
      
      if numComponents == 1:
        return cost
      else:
        return -1


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # We are looking a min spanning tree that can be obtained 
        connections = []
        
        for i, p in enumerate(points):
            for j in range(i + 1, len(points)):
                connections.append((i, j, abs(p[0] - points[j][0]) + abs(p[1] - points[j][1])))
        
        connections.sort(key=itemgetter(2))
        parent = list(range(len(points)))
        size = [1] * len(points)
        
        def find(x):
            if x == parent[x]:
                return x
            
            parent[x] = find(parent[x])
            return parent[x]
        
        total_distance = 0
        for u, v, c in connections:
            p_u = find(u)
            p_v = find(v)
            
            if p_u == p_v:
                continue
                
            total_distance += c
            if size[u] < size[v]:
                size[v] += size[u]
                parent[p_u] = p_v
            else:
                size[u] += size[v]
                parent[p_v] = p_u
        
        return total_distance


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) == 1:
            return 0
        
        root = {}
        for point in points:
            root[(point[0], point[1])] = (point[0], point[1])
        
        #find with compresion
        def find(i):
            if i != root[i]:
                root[i] = find(root[i])
            return root[i]
        
        def union(a, b):
            a, b = find(a), find(b)
            
            if a == b:
                return 0
            
            root[a] = b
            return 1
        
        num = len(points)
        #visited = set()
        edge_count = 0
        distances = []
        
        for i in range(num):
            for j in range(i+1, num):
                #distances[(points[i], points[j])] = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                distances.append((abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]),(points[i], points[j])))
                j += 1
        
        distances.sort(key=lambda x:x[0])
        #print(distances)
        
        ans = 0
        for d in distances:
            a = d[1][0]
            b = d[1][1]
            a_t = tuple(a)
            b_t = tuple(b)
            if find(a_t) != find(b_t):
                #print(f\"adding {d}\")
                edge_count += 1
                ans += d[0]
                union(a_t, b_t)
                #visited.add(a_t)
                #visited.add(b_t)
                if edge_count == num-1:
                    return ans
    
        return -1


from collections import defaultdict
import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:

        graph = defaultdict(list)
        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                cost = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                graph[i].append((cost, j))
                graph[j].append((cost, i))
        
        seen = [0] * (len(points)+1)
        seen[0] = 1
        q = graph[0]
        minimumCost = 0
        connectedNodes = 1
        heapq.heapify(q)
        while q:
            cost, city = heapq.heappop(q)
            if not seen[city]:
                seen[city] = 1
                minimumCost += cost
                connectedNodes += 1
                for connectingCost, neighbour in graph[city]:
                    heapq.heappush(q, (connectingCost, neighbour))
            if connectedNodes >= len(points):
                break
        return minimumCost


class DSU:
    def __init__(self,n):
        self.parent = [i for i in range(n)]
        self.rank = [1 for i in range(n)]
        self.count = n
    
    def find(self,x):
        if x!=self.parent[x]:
            self.parent[x]=self.find(self.parent[x])
        return self.parent[x]
    
    def union(self,x,y):
        px = self.find(x)
        py = self.find(y)
        if px==py:
            return False
        self.count-=1
        if self.rank[px]>self.rank[py]:
            self.parent[py]=px
            self.rank[px]+=self.rank[py]
        else:
            self.parent[px]=py
            self.rank[py]+=self.rank[px]
        return True
                
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        edges = []
        for i in range(n):
            for j in range(i+1, n):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((dist, i, j))
        heapq.heapify(edges)
        res = 0
        ds = DSU(n)
        while edges and ds.count!=1:
            cost,u,v = heapq.heappop(edges)
            if ds.union(u,v):
                res += cost
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
    # #没有现成的edge list，想到当遍历到某一个点才现算它与其他点的权重值并压进pqueue，故考虑首选Prim算法而不是Krusal (1000ms, 95%faster)
    #     N = len(points)
    #     seen = set()
    #     cost = 0
    #     cnt = 0
    #     pq = [(0, 0)]
    #     while pq:
    #         c, i = heapq.heappop(pq)
    #         if i in seen: continue
    #         cost += c
    #         cnt += 1
    #         if cnt == N: return cost    #early termination. another advantage of using Prim over Krusal
    #         seen.add(i)
    #         pt_x, pt_y = points[i]
    #         for j in range(N):
    #             if j in seen: continue
    #             nei_x, nei_y = points[j]
    #             nei_c = abs(pt_x - nei_x) + abs(pt_y - nei_y)
    #             heapq.heappush(pq, (nei_c, j))
    #     return cost
     
        
    #也操练一下Kruskal...
        N = len(points)
        dsu = list(range(N))
        def find(i):
            if dsu[i] != i: dsu[i] = find(dsu[i])
            return dsu[i]
        def union(i, j):
            dsu[find(j)] = find(i)
       
        pq = []
        cost = 0
        #push in all edges, sort by wight_cost
        for i in range(N):
            for j in range(i+1, N):
                i_x, i_y = points[i]
                j_x, j_y = points[j]
                c = abs(i_x - j_x) + abs(i_y - j_y)
                pq.append((c, i, j))
        pq.sort(key = lambda x: x[0], reverse = True)
        # print(pq)
        while pq:
            c, i ,j = pq.pop()
            fi, fj = find(i), find(j)
            if fi == fj: continue
            cost += c
            dsu[fj] = fi
        return cost
        
        
        
        
        
        
        
        
#         res = 0
#         N = len(points)
#         visited = [[0] * N for _ in range(N)]
#         if len(points) == 1: return 0
#         DP = [[float('inf')] * N for _ in range(N)]
        
#         for i in range(N):
#             # min_dist = float('inf')
#             for j in range(i+1, N):
#                 # print(i, i, j)
#                 x, y = points[i], points[j]
#                 curr_dist = DP[i][j] = DP[j][i] = abs(x[0] - y[0]) + abs(x[1] - y[1])
#                 # if curr_dist < min_dist: 
#                 #     min_dist = curr_dist
#             min_dist = min(DP[i])
#             j = DP[i].index(min_dist) 
#             if not visited[i][j]:
#                 res += min_dist
#                 visited[i][j] = visited[j][i] = 1
#                 DP[i][j] = DP[j][i] = float('inf')
#             print(min_dist, DP)
#             # res += min_dist
#         return res
                


def manhattan(p1, p2):
    if p1 == p2:
        return 10**10
    return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        
def makeGraph(points):
    graph = []
    for p1 in range(len(points)):
        for p2 in range(p1):
            graph.append( (p2, p1, manhattan(points[p1], points[p2])) )
    return graph

class Solution:

    #Prim's
    def _minCostConnectPoints(self, points: List[List[int]]) -> int:
        pass
        
        
        
        
    #Kruskal's
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        
        
        def find(subsets, p1):
            if subsets[p1][0] != p1:
                subsets[p1][0] = find(subsets, subsets[p1][0])
            return subsets[p1][0]
        
        def union(subsets, p1, p2):
            p1root = find(subsets, p1)
            p2root = find(subsets, p2)
            
            if subsets[p1root][1] > subsets[p2root][1]:
                subsets[p2root][0] = p1root
            elif subsets[p2root][1] > subsets[p1root][1]:
                subsets[p1root][0] = p2root
            else:
                subsets[p1root][1] += 1
                subsets[p2root][0] = p1root
        
        graph = makeGraph(points)
        
        edges = sorted(graph, key=lambda x: x[2])
        subsets = [[x, 0] for x in range(len(points))]
        
        e = 0 #counts how many edges have been added
        i = 0 #tracks location in edges array
        total_cost = 0
        
        while e < len(points) - 1:
            
            p1, p2, cost = edges[i]
            
            if find(subsets, p1) != find(subsets, p2):               
                union(subsets, p1, p2)
                total_cost += cost
                e += 1
            else:
                pass
                #discard the edge
            
            i += 1
        return total_cost

'''
https://leetcode.com/problems/min-cost-to-connect-all-points/
'''
from typing import List
import heapq

class Solution:
    '''
    Minimum Spanning Tree (Kruskal)
    https://leetcode.com/problems/min-cost-to-connect-all-points/discuss/843940/C%2B%2B-Minimum-Spanning-Tree-(Kruskal)

    Intuition:
    Imagine all the points form a complete graph, and length of an edge is the manhattan distance between the 2 points
    To find the min cost, we therefore need to find the minimum spanning tree

    Algorithm:
    Use the Kruskal algorithm, which invovles min heap to pick the smallest edge, and union-find to check if the edge is redundant.
    Exit when all points are connected.

    The complexity when using sort is O(n * n log (n * n)) - we have n * n edges. Using a min heap is O(k log (n * n)),
    where k is the number of edges we need to pull to complete the tree. It's much smaller than n * n in the average case.
    '''
    def minCostConnectPoints(self, points: List[List[int]]) -> int:

        def find(ds, i):
            if ds[i] < 0:
                return i
            ds[i] = find(ds, ds[i])
            return ds[i]

        n, ans = len(points), 0
        ds = [-1] * n
        arr = []
        for i in range(n):
            for j in range(i+1, n):
                heapq.heappush(arr, [abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1]), i, j])
        while arr:
            dist, i, j = heapq.heappop(arr)
            i, j = find(ds, i), find(ds, j)
            if i != j:
                ans += dist
                ds[i] += ds[j]
                ds[j] = i
                if ds[i] == -n:
                    break
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        l = len(points)
        if l < 2:
            return 0
        
        comps = [i for i in range(l)]
        
        def comp(v):
            return v if comps[v] == v else comp(comps[v])
        
        def join_comp(comp1, comp2):
            for i in range(l):
                if comps[i] == comp1:
                    comps[i] = comp2
        
        edges = []
        for i in range(l):
            for j in range(i+1, l):
                edges.append((abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]), i, j))
        
        edges.sort()
        
        out = 0
        edge_count = l - 1
        for edge in edges:
            comp1 = comp(edge[1])
            comp2 = comp(edge[2])
            if comp1 != comp2:
                out += edge[0]
                join_comp(comp2, comp1)
                edge_count -= 1
                if not edge_count:
                    break
        return out
                


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def get_dist(i, j):
            return abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
        n, c = len(points), collections.defaultdict(list)
        for i in range(n):
            for j in range(i+1, n):
                d = get_dist(i, j)
                c[i].append((d, j))
                c[j].append((d, i))
        
        cnt, ans, visited, heap = 1, 0, [0] * n, c[0]
        visited[0] = 1
        heapq.heapify(heap)
        while heap and cnt < n:
            d, j = heapq.heappop(heap)
            if not visited[j]:
                visited[j], cnt, ans = 1, cnt+1, ans+d
                for record in c[j]: heapq.heappush(heap, record)
        return ans

from heapq import *

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        result = 0
        if len(points) == 1:
            return result
        
        costHeap = []
        n = len(points)
        cur = 0
        distance = lambda p, np: abs(p[0] - np[0]) + abs(p[1] - np[1])
        visited = set()
        visited.add(cur)
        
        for i in range(1, n):
            heappush(costHeap, [distance(points[0], points[i]), i])
        
        while costHeap:
            cost, nextStart = heappop(costHeap)
            # print(cur, nextStart, cost)
            if nextStart not in visited:
                result += cost
                visited.add(nextStart)
                cur = nextStart
                for i in range(n):
                    if i in visited:
                        continue
                    heappush(costHeap, [distance(points[cur], points[i]), i])
            if len(visited) == n:
                break
                
        return result
                    


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        n, c = len(points), collections.defaultdict(list)
        for i in range(n):
            for j in range(i+1, n):
                d = manhattan(points[i], points[j])
                c[i].append((d, j))
                c[j].append((d, i))
        cnt, ans, visited, heap = 1, 0, [0] * n, c[0]
        visited[0] = 1
        heapq.heapify(heap)
        while heap:
            d, j = heapq.heappop(heap)
            if not visited[j]:
                visited[j], cnt, ans = 1, cnt+1, ans+d
                for record in c[j]: heapq.heappush(heap, record)
            if cnt >= n: break        
        return ans
                            


class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:

        def manhattan(x, y):
            return abs(x[0]-y[0]) + abs(x[1]-y[1])

        ans, n = 0, len(p)
        seen = set()
        vertices = [(0, (0, 0))] # (distance, (last_vertice, cur_vertice))

        while len(seen) < n:
            # print(vertices, seen)
            d, (u, v) = heapq.heappop(vertices)            
            if u not in seen and v in seen:
                print(u, v)
            if v in seen: continue
            ans += d
            seen.add(v)
            for j in range(n):
                if j not in seen and j!=v:
                    heapq.heappush(vertices, (manhattan(p[j], p[v]), (v, j)))

        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # edge: from, to, weight
        Edge = namedtuple(\"Edge\", [\"V1\", \"V2\", \"dist\"])
        edges = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                edges.append(Edge(points[i], points[j], abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])))
        edges.sort(key = lambda e: e[2])
        
        uf = {}
        
        def find(x:List[int]):
            xx = (x[0], x[1]) # to a hashable type
            uf.setdefault(xx, xx) # this will only be executed when x's value is missing
            if uf[xx] != xx:
                uf[xx] = find(uf[xx])
            return uf[xx]
        
        def union(x, y):
            uf[find(x)] = find(y)
            
        num = len(points) # we need num-1 lines to form the MST
        
        count, total = 0, 0
        
        for f, t, dist in edges: # already sorted
            # when vertice x and vertice y doesn't have the same root, we union them 
            # and draw a line (count + 1)
            if find(f) != find(t):
                union(f, t)
                count += 1
                total += dist
            if count == num - 1:
                return total
        return total

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        uf = {}
        n = len(points)
        rank = [1] * n
        
        def find(x):
            uf.setdefault(x, x)
            if uf[x] != x:
                uf[x] = find(uf[x])
            return uf[x]
        
        def union(x, y):
            px, py = find(x), find(y)
            if px != py:
                if rank[px] > rank[py]:
                    px, py = py, px
                rank[py] += rank[px]
                uf[px] = py
                return rank[py] == n
            return False
        
        hp = [(abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]), i, j) for i in range(n) for j in range(i + 1, n)]
        heapq.heapify(hp)
        ans = 0
        
        while hp:
            d, i, j = heapq.heappop(hp)
            if find(i) != find(j):
                ans += d
                if union(i, j):
                    break
                
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        from heapq import heappush, heappop
        
        n = len(points)
        h = {i: {} for i in range(n)}
        visited = [False] * n 
        for p1 in range(n):
            for p2 in range(n):
                if p1 == p2:
                    continue
                d = abs(points[p1][0] - points[p2][0]) + abs(points[p1][1] - points[p2][1])
                
                h[p1][p2] = d
                h[p2][p1] = d
        
        
        # print(h)
        
        total = 0
        ans = 0
        queue = [(0, 0)]
        while total < n:
            d, node = heappop(queue)
            if visited[node]:
                continue
            # print(d, node)
            total += 1
            ans += d
            visited[node] = True
            for item in h[node]:
                if not visited[item]:
                    heappush(queue, (h[node][item], item))
        return ans

class Solution:
    def minCostConnectPoints(self, points):
        distance = lambda p1, p2: abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        points.sort(key = lambda p: p[0] + p[1])
        total_cost = 0
        points = [[p, distance(p, points[0])] for p in points]
        while points:
            minIdx, mindist = None, float('inf')
            for i, (p1, dist) in enumerate(points):
                if dist < mindist:
                    minIdx, mindist = i, dist
            p1, cost = points.pop(minIdx)
            total_cost += cost
            for i, (p2, dist) in enumerate(points):
                points[i][1] = min(points[i][1], distance(p1, p2))
        return total_cost

class Solution:
    def minCostConnectPoints(self, points):
        N = len(points)
        dist = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        connections = [[u, v, dist(points[u], points[v])] for u in range(N-1) for v in range(u+1, N)]
        connections.sort(key = lambda x:x[2])
        parent, cnt, res = [i for i in range(N+1)], N-1, 0
        def find(v):
            while parent[v] != parent[parent[v]]:
                parent[v] = parent[parent[v]]
            return parent[v]
        for u, v, cost in connections:
            pu, pv = find(u), find(v)
            if pu != pv:
                parent[pu] = pv
                cnt -= 1
                res += cost
                if cnt == 0:
                    break
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        from collections import defaultdict 
        class Graph: 

            def __init__(self,vertices): 
                self.V= vertices
                self.graph = [] 


            def addEdge(self,u,v,w): 
                self.graph.append([u,v,w]) 

            def find(self, parent, i): 
                if parent[i] == i: 
                    return i 
                return self.find(parent, parent[i]) 

            def union(self, parent, rank, x, y): 
                xroot = self.find(parent, x) 
                yroot = self.find(parent, y) 

                if rank[xroot] < rank[yroot]: 
                    parent[xroot] = yroot 
                elif rank[xroot] > rank[yroot]: 
                    parent[yroot] = xroot 

                else : 
                    parent[yroot] = xroot 
                    rank[xroot] += 1

            def KruskalMST(self): 

                result =[] #This will store the resultant MST 

                i = 0 # An index variable, used for sorted edges 
                e = 0 # An index variable, used for result[] 

                self.graph =  sorted(self.graph,key=lambda item: item[2]) 

                parent = [] ; rank = [] 

                for node in range(self.V): 
                    parent.append(node) 
                    rank.append(0) 

                while e < self.V -1 : 

                    u,v,w =  self.graph[i] 
                    i = i + 1
                    x = self.find(parent, u) 
                    y = self.find(parent ,v) 

                    if x != y: 
                        e = e + 1     
                        result.append([u,v,w]) 
                        self.union(parent, rank, x, y)             
                ret = 0
                for u,v,weight  in result: 
                    ret += weight
                    
                return ret
        
        def dis(i, j):
            return abs(i[0]-j[0])+abs(i[1]-j[1])
        
        l = len(points)
        g = Graph(l)
        for i in range(l):
            for j in range(i,l):
                g.addEdge(i, j, dis(points[i], points[j]))
  
        return g.KruskalMST() 



class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def manhattan(x, y):
            return abs(x[0]-y[0]) + abs(x[1]-y[1])
        
        points = [tuple(p) for p in points]
        
        ans, n = 0, len(points)
        seen = set()
        vertices = [(0, ((points[0]), (points[0])))]
        
        while len(seen) < n:
            w, (u, v) = heapq.heappop(vertices)
            # print(w, u, v, ans, seen)
            if u in seen and v in seen: continue
            ans += w
            seen.add(v)
            for j, p in enumerate(points):
                if tuple(p) != tuple(v) and tuple(p) not in seen:
                    heapq.heappush(vertices, (manhattan(p, v), (tuple(v), tuple(p))))
            # print(vertices)
            seen.add(u)
        
        return ans
                
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        from heapq import heappush, heappop
        
        n = len(points)
        h = {i: {} for i in range(n)}
        visited = [False] * n 
        for p1 in range(n):
            for p2 in range(n):
                if p1 == p2:
                    continue
                d = abs(points[p1][0] - points[p2][0]) + abs(points[p1][1] - points[p2][1])
                
                h[p1][p2] = d
                h[p2][p1] = d
        
        
        # print(h)
        
        total = 0
        ans = 0
        queue = [(0, 0)]
        while total < n:
            d, node = heappop(queue)
            if visited[node]:
                continue
            print((d, node))
            total += 1
            ans += d
            visited[node] = True
            for item in h[node]:
                if not visited[item]:
                    heappush(queue, (h[node][item], item))
        return ans
                
            
            
            
            
        
        
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def find(x):
            if x != parent[x]:
                parent[x] = find(parent[x])
            return parent[x]
        
        parent = list(range(len(points)))
        g = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                g.append((i, j, abs(points[j][1]-points[i][1]) + abs(points[j][0]-points[i][0])))
        
        cost = 0
        for u, v, w in sorted(g, key=lambda x:x[2]):
            ru, rv = find(u), find(v)
            if ru == rv:
                continue
            parent[ru] = rv
            cost += w
        
        return cost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        weight_graph = []
        res = []
        for i in range(len(points)):
            for j in range(i+1,len(points)):
                weight_graph.append([i,j,abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])])
        weight_graph = sorted(weight_graph,key=lambda item:item[2])
        parent = [i for i in range(n)]
        rank = [0 for _ in range(n)]
        def find(i):
            if parent[i] == i:
                return i
            else:
                return find(parent[i])
        def union(x,y):
            if rank[x] < rank[y]:
                parent[x] = parent[y]
            elif rank[x] > rank[y]:
                parent[y] = parent[x]
            else:
                parent[x] = parent[y]
                rank[y] += 1
        for edge in weight_graph:
            if len(res) < len(points)-1:
                u,v,w = edge
                x = find(u)
                y = find(v)
                if x!=y:
                    union(x,y)
                    res.append(w)
        if not res:
            return 0
        return sum(res)


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def manhattan(p1, p2):
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        
        n = len(points)
        seen = set()
        res = 0
        pq = [(0, 0, 0)]
        while len(seen) < n:
            w, u, v = heapq.heappop(pq)
            if u in seen and v in seen:
                continue
            res += w
            seen.add(v)
            for i in range(n):
                if i != v and i not in seen:
                    heapq.heappush(pq, (manhattan(points[v], points[i]), v, i))
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        self.points = points
        n = len(points)
        edges = []
        for i in range(n-1):
            for j in range(i+1,n):
                d = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((d,i,j))
        edges.sort()
        self.comp = list(range(n))
        ans = 0
        e = 0
        for i in range(n-1):
            while e < len(edges):
                d,i,j = edges[e]
                e += 1
                ii = self.find(i)
                jj = self.find(j)
                if ii != jj:
                    self.comp[ii] = jj
                    ans += d
                    break
        return ans
    
    
    def find(self,i):
        idx = []
        while self.comp[i] != i:
            idx.append(i)
            i = self.comp[i]
        for j in idx:
            self.comp[j] = i
        return i
            


class Solution:
    def minCostConnectPoints(self, a: List[List[int]]) -> int:                        
        ans, n, vis, pq, i = 0, len(a), set([0]), [], 0
        rem = set(range(1, n))
        while len(vis) < n:            
            for j in rem: 
                if j not in vis: heappush(pq, (abs(a[i][0]-a[j][0]) + abs(a[i][1] - a[j][1]), j))
            while pq[0][1] in vis: heappop(pq)
            val, i = heappop(pq)
            vis.add(i); rem.discard(i)
            ans += val            
        return ans                                            

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n=len(points)
        cost=0
        if n<=1:
            return 0
        
        g=[]
        for i in range(n):
            x1=points[i][0]
            y1=points[i][1]
            for j in range(i+1,n):
                if j!=i:
                    x2=points[j][0]
                    y2=points[j][1]
                    d=abs(x1-x2)+abs(y1-y2)
                    g.append([i,j,d])
                    
        g.sort(key=lambda x:x[2])
        par=[-1]*n
        for i,(u,v,c) in enumerate(g):
            
            p1=u
            while par[p1]>0:
                p1=par[p1]
            p2=v
            while par[p2]>0:
                p2=par[p2]
                
            if p1==p2:
                continue
            
            
            
            else:
                if abs(par[p1])>abs(par[p2]):
                    par[p1]+=par[p2]
                    if u!=p1:
                        par[u]=p1

                    par[v]=p1
                    par[p2]=p1

                else:
                    par[p2]+=par[p1]
                    if v!=p2:
                        par[v]=p2

                    par[u]=p2
                    par[p1]=p2
                
                cost+=c
            
        
        return cost
                
                
                
        


from collections import defaultdict 
class Graph: 
  
    def __init__(self,n:int) -> None: 
        self.V= n 
        self.graph = []
    def addEdge(self,u:int,v:int,w:int)-> None: 
        self.graph.append([u,v,w]) 
    def find(self, parent:List[int], i:int)->int: 
        if parent[i] == i: 
            return i 
        return self.find(parent, parent[i])
    def union(self, parent:List[int], rank:List[int], x:int, y:int)->None: 
        xroot = self.find(parent, x) 
        yroot = self.find(parent, y) 
 
        if rank[xroot] < rank[yroot]: 
            parent[xroot] = yroot 
        elif rank[xroot] > rank[yroot]: 
            parent[yroot] = xroot 
        else : 
            parent[yroot] = xroot 
            rank[xroot] += 1
     
    def KruskalMST(self)->List[List[int]]: 
 
        result =[] 
        i = 0
        e = 0 
        self.graph =  sorted(self.graph,key=lambda item: item[2]) 
  
        parent = []
        rank = [] 
  
        # Create V subsets with single elements 
        for node in range(self.V): 
            parent.append(node) 
            rank.append(0) 
      
        # Number of edges to be taken is equal to V-1 
        while e < self.V -1 : 
  
            # Step 2: Pick the smallest edge and increment  
                    # the index for next iteration 
            u,v,w =  self.graph[i] 
            i = i + 1
            x = self.find(parent, u) 
            y = self.find(parent ,v) 
  
            # If including this edge does't cause cycle,  
                        # include it in result and increment the index 
                        # of result for next edge 
            if x != y: 
                e = e + 1     
                result.append([u,v,w]) 
                self.union(parent, rank, x, y)             
            # Else discard the edge 
  
        return result
                               
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        graph = Graph(n)
        for i in range(n-1):
           point1 = points[i]
           for j in range(i+1,n):
              point2 = points[j]
              manhattan_distance = abs(point1[0]-point2[0]) + abs(point1[1]-point2[1])                
              graph.addEdge(i,j,manhattan_distance)
        ans = 0                       
        for edge in graph.KruskalMST():
           ans += edge[2]
        return ans


class Graph: 
    def __init__(self,vertices): 
        self.V= vertices
        self.graph = []
    def addEdge(self,u,v,w): 
        self.graph.append([u,v,w]) 
    def find(self, parent, i): 
        if parent[i] == i: 
            return i 
        return self.find(parent, parent[i]) 
    def union(self, parent, rank, x, y): 
        px = self.find(parent, x) 
        py = self.find(parent, y) 
        if rank[px] < rank[py]: 
            parent[px] = py 
        elif rank[px] > rank[py]: 
            parent[py] = px 
        else : 
            parent[py] = px 
            rank[px] += 1
 
    def MST(self): 
        res = 0
        i = 0
        e = 0
        self.graph =  sorted(self.graph,key=lambda item: item[2]) 
        parent = [] ; rank = [] 
        for node in range(self.V): 
            parent.append(node) 
            rank.append(0) 
        while e < self.V -1 :
            u,v,w =  self.graph[i] 
            i = i + 1
            x = self.find(parent, u) 
            y = self.find(parent ,v)
            if x != y: 
                e = e + 1     
                res += w
                self.union(parent, rank, x, y)
        return res
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        g = Graph(n)
        def dis(i, j):
            return abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
        for i in range(n):
            for j in range(i+1, n):
                g.addEdge(i, j, dis(i, j))
        return g.MST() 


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def distance(p1,p2):
            return abs(p1[1] - p2[1]) + abs(p1[0] - p2[0])
        n = len(points)
        edges = [(i,j,distance(points[i],points[j])) for i in range(n) for j in range(i+1,n)]
        edges.sort(key=lambda x: x[2])        
        father = [i for i in range(n + 1)]
        def find(x):
            if father[x] != x:
                father[x] = find(father[x])
            return father[x]
        def union(x,y):
            x = father[x]
            y = father[y]
            if x < y:
                father[y] = x
            else:
                father[x] = y
        ans = 0
        for p1,p2,d in edges:
            if find(p1) != find(p2):
                ans += d
                union(p1,p2)
        return ans
\"\"\"
[[2,-3],[-17,-8],[13,8],[-17,-15]]
[[3,12],[-2,5],[-4,1]]
[[0,0],[2,2],[3,10],[5,2],[7,0]]
[[0,0]]
[[-1000000,-1000000],[1000000,1000000]]
[[0,0],[1,1],[1,0],[-1,1]]
[[3,12],[-2,5],[-4,1]]
\"\"\"

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def distance(p1, p2):
            return abs(p2[0] - p1[0]) + abs(p2[1] - p1[1])
    
        res , n = 0, len(points)
        dist_list = [distance(points[0], p) for p in points]
        for _ in range(n-1):
            d, j = min((d, i) for i, d in enumerate(dist_list) if d > 0)
            res += d
            dist_list = [min(dist_list[i], distance( points[j], p)) for i, p in enumerate(points)]
            
        return res


class UnionFind:
    def __init__(self, size):
        self._parent = list(range(size))
        self._size = [1] * size
    
    def union(self, a, b):
        a, b = self.find(a), self.find(b)
        if a == b:
            return False
        if self._size[a] < self._size[b]:
            a, b = b, a
        self._parent[b] = a
        self._size[a] += self._size[b]
        return True
    
    def find(self, x):
        while self._parent[x] != x:
            self._parent[x] = self._parent[self._parent[x]]
            x = self._parent[x]
        return x
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        
        edges = []
        for u in range(n):
            x0, y0 = points[u]
            for v in range(u + 1, n):
                x1, y1 = points[v]
                edges.append((u, v, abs(x0 - x1) + abs(y0 - y1)))
        edges.sort(key=lambda e: e[2])
        
        uf = UnionFind(n)
        cost = 0
        
        for u, v, w in edges:
            if uf.union(u, v):
                cost += w
        
        return cost

class Solution:
    def minCostConnectPoints(self, A: List[List[int]]) -> int:
        # [[0,0],[2,2],[3,10],[5,2],[7,0]]
        
                # edge[i].append([x+y,j])
                # edge[j].append([x+y,i])
        # print(edge)
        self.graph=[]
        def find(par,i):
            if par[i]==i:
                return i
            return find(par,par[i])

        def union(par, rank, x, y): 
            xroot = find(par, x) 
            yroot = find(par, y) 
            if rank[xroot] < rank[yroot]: 
                par[xroot] = yroot 
            elif rank[xroot] > rank[yroot]: 
                par[yroot] = xroot 
            else : 
                par[yroot] = xroot 
                rank[xroot] += 1


        def kruskal(): 

            result =[] #This will store the resultant MST 

            i = 0 # An index variable, used for sorted edges 
            e = 0 
            self.graph =  sorted(edges,key=lambda item: item[2]) 

            par = []
            rank = [] 

            # Create V subsets with single elements 
            for node in range(len(A)): 
                par.append(node) 
                rank.append(0) 

            # Number of edges to be taken is equal to V-1 
            while e < len(A) -1 : 

                # Step 2: Pick the smallest edge and increment  
                        # the index for next iteration 
                u,v,w =  self.graph[i] 
                i = i + 1
                x = find(par, u) 
                y = find(par ,v) 

                # If including this edge does't cause cycle,  
                            # include it in result and increment the index 
                            # of result for next edge 
                if x != y: 
                    e = e + 1     
                    result.append([u,v,w]) 
                    union(par, rank, x, y) 
            return result
            # Else discard the edge 
                
        edge=defaultdict(list)
        edges=[]
        
        
        for i in range(len(A)):
            for j in range(i+1,len(A)):
                x=abs(A[i][0]-A[j][0])
                y=abs(A[i][1]-A[j][1])
                edges.append([i,j,x+y])
        res=kruskal()
        main=0
        for i in res:
            main+=i[-1]
        return main




               
def find_root(parents, i):
    if parents[i] == -1:
        return i
    else:
        return find_root(parents, parents[i])
   
def calc_dist(p1, p2):
    return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) == 1:
            return 0
       
        graph = []
        n = len(points)
       
        for i in range(len(points) - 1):
            for j in range(i + 1, len(points)):
                dist = calc_dist(points[i], points[j])
                heapq.heappush(graph, [dist, (i, j)])
       
        parents = [-1] * len(points)
        cost = 0
        count = 0
        # print (graph)
        while count < n - 1:
            dist, point_pair = heapq.heappop(graph)
            # print(dist, point_pair)
            p1, p2 = point_pair[0], point_pair[1]
           
            r1 = find_root(parents, p1)
            r2 = find_root(parents, p2)
           
            if r1 != r2:
                parents[r1] = r2
                cost = cost + dist
                count = count + 1
       
        return cost

class Solution:
    def minCostConnectPoints(self, points):
        n = len(points)
        graph = [[] for i in range(n)]
        for i in range(n):
            for j in range(i+1,n):
                dist = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                graph[i].append([j,dist])
                graph[j].append([i,dist])

        return mst(n,graph)

        
def mst(n,graph):

    keyval = [2**31-1]*(n)
    keyval[0] = 0
    mst = [False]*(n)

    for i in range(n):
        u = minVal(keyval, mst)

        mst[u] = True

        for node in graph[u]:
            if mst[node[0]]==False and keyval[node[0]]>node[1]:
                keyval[node[0]] = node[1]

    return sum(keyval[1:])

def minVal(keyval, mst):
    minv = 2**31-1
    minInd = 0
    for i in range(1,len(keyval)):
        if minv>keyval[i] and mst[i]==False:
            minv = keyval[i]
            minInd = i

    return minInd


class DSU:
    def __init__(self,n):
        self.parent = [i for i in range(n)]
        self.rank = [1 for i in range(n)]
        self.count = n
    
    def find(self,x):
        if x!=self.parent[x]:
            self.parent[x]=self.find(self.parent[x])
        return self.parent[x]
    
    def union(self,x,y):
        px = self.find(x)
        py = self.find(y)
        if px==py:
            return False
        self.count-=1
        if self.rank[x]>self.rank[y]:
            self.parent[py]=px
            self.rank[px]+=self.rank[py]
        else:
            self.parent[px]=py
            self.rank[py]+=self.rank[px]
        return True
                
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        edges = []
        for i in range(n):
            for j in range(i+1, n):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((dist, i, j))
        heapq.heapify(edges)
        res = 0
        ds = DSU(n)
        while ds.count!=1:
            cost,u,v = heapq.heappop(edges)
            if ds.union(u,v):
                res += cost
        return res

from typing import List


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        
        P = [i for i in range(N)]
        E = []
        
        for u in range(N):
            x1, y1 = points[u]
            for v in range(u + 1, N):
                x2, y2 = points[v]
                
                E.append((u, v, abs(x1 - x2) + abs(y1 - y2)))

                
        E.sort(key = lambda edge: edge[2])

        def getParent(x):
            if x != P[x]:
                P[x] = getParent(P[x])

            return P[x]

        def join(u, v):
            pu = getParent(u)
            pv = getParent(v)

            if pu == pv:
                return False

            P[pu] = pv
            return True    

        rs, count = 0, 0
        for u, v, w in E:
            if join(u, v):
                rs = rs + w
                count = count + 1
            
            if count == N:
                break
        
        return rs


# Kruskal
class UnionFindSet:
    def __init__(self, n):
        self.parents = [i for i in range(n + 1)]
        self.ranks = [0 for i in range(n + 1)]
        
    def find(self, u):
        if u != self.parents[u]:
            self.parents[u] = self.find(self.parents[u])            
        return self.parents[u]
    
    def union(self, u, v):
        pu = self.find(u)
        pv = self.find(v)
        if pu == pv: return False
        
        if self.ranks[pu] < self.ranks[pv]:
            self.parents[pu] = pv
        elif self.ranks[pu] > self.ranks[pv]:
            self.parents[pv] = pu
        else:
            self.parents[pu] = pv
            self.ranks[pv] += 1
            
        return True


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        edges = []
        for i in range(n):
            for j in range(i + 1, n):
                edges.append([abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]), i, j])
        edges.sort()
        ans = 0
        count = 0
        uf = UnionFindSet(n)
        for e in edges:
            if not uf.union(e[1], e[2]): continue
            ans += e[0]
            count += 1
            if count == n - 1: return ans
            
        return ans
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        a = points
        n = len(a)
        def d(i, j): return abs(a[i][0]-a[j][0]) + abs(a[i][1]-a[j][1])
        q = []
        dst = [float('inf')]*n
        vis = [False] * n
        def consider(du, u):
            if vis[u] or du >= dst[u]: return
            dst[u] = du
            heappush(q, (du, u))
        consider(0, 0)
        while q:
            du, u = heappop(q)
            if vis[u]: continue
            vis[u] = True
            for v in range(n): consider(d(u, v), v)
        return sum(dst)
            


from heapq import *
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) <= 1:
            return 0
        edge_list = []
        for idx1, [x1, y1] in enumerate(points):
            for idx2, [x2, y2] in enumerate(points[idx1+1:], idx1+1):
                heappush(edge_list, [abs(x1-x2)+abs(y1-y2), idx1, idx2])

        cost, p1, p2 = heappop(edge_list)
        add_point = {p1, p2}
        ret = cost
        while len(add_point) != len(points) and edge_list:
            temp_list = []
            flag = False
            while not flag:
                cost, p1, p2 = heappop(edge_list)
                if p1 in add_point and p2 in add_point:
                    continue
                elif p1 not in add_point and p2 not in add_point:
                    temp_list.append([cost, p1, p2])
                else:
                    add_point.add(p1)
                    add_point.add(p2)
                    ret += cost
                    flag = True
            while temp_list:
                heappush(edge_list, heappop(temp_list))

        return ret


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def find(i):
            if parent[i] == i:
                return i
            return find(parent[i])
        def union(p1,p2):
            if size[p1] > size[p2]:
                p1,p2=p2,p1
            parent[p1] = p2
            size[p2] += size[p1]
            
        if len(points) <= 1:
            return 0
        dist = []
        for i in range(len(points)):
            for j in range(i+1,len(points)):
                d = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                dist.append((d,i,j))
        dist.sort()
 
        edge = 0
        res = 0
        parent = list(range(len(points)))
        size = [1]*len(points)
        for d,n1,n2 in dist:
            p1,p2 = find(n1),find(n2)
            if p1 == p2:
                continue
            res += d
            union(p1,p2)
            edge += 1
            if edge == len(points)-1:
                return res


import heapq

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def dist(p1, p2):
            return abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        
        def find(i):
            if parent[i] < 0: return i
            parent[i] = find(parent[i])
            return parent[i]
            
        res = 0
        n = len(points)
        parent = [-1]*n
        rank = [0]*n
        h = []
        
        for u in range(n):
            for v in range(u+1, n):
                h.append((dist(points[u], points[v]), u, v))
                
        heapq.heapify(h)
        
        while h:
            d, u, v = heapq.heappop(h)
            u, v = find(u), find(v)
            if u != v:
                res += d
                if rank[u] > rank[v]:
                    parent[u] += parent[v]
                    parent[v] = u
                else:
                    parent[v] += parent[u]
                    parent[u] = v
                    if rank[u] == rank[v]: rank[v] += 1
                
                if parent[u] == -n: break
                    
        return res

def cost(x,y):
    return (abs(x[0]-y[0])+abs(x[1]-y[1]))
def find(z):
    nonlocal p
    a=[]
    while p[z]!=z:
        a.append(z)
        z=p[z]
    for i in a:
        p[i]=z
    return z

class Solution:
    def minCostConnectPoints(self, a: List[List[int]]) -> int:
        nonlocal p
        n=len(a)
        b=[]
        p=[i for i in range(n+1)]
        s=[1 for i in range(n+1)]
        for i in range(n):
            for j in range(i+1,n):
                b.append((i,j,cost(a[i],a[j])))
                    
        b.sort(key=lambda x:x[2])
        su=0
        for i in b:
            x=find(i[0])
            y=find(i[1])
            if x!=y:
                su+=i[2]
                if s[x]>s[y]:
                    p[y]=x
                    s[x]+=s[y]
                else:
                    p[x]=y
                    s[y]+=s[x]
        return su

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def find(x):
            if uf[x] != x:
                uf[x] = find(uf[x])
            return uf[x]
        
        def union(x, y):
            idx = find(x)
            idy = find(y)
            if idx == idy:
                return
            uf[idy] = idx
        
        def dist(x, y):
            return abs(y[0] - x[0]) + abs(y[1] - x[1])
        
        n = len(points)
        uf = {i:i for i in range(n)}
        edges = []
        
        for i in range(n):
            for j in range(i+1, n):
                a = points[i]
                b = points[j]
                edges.append((i,j, dist(a, b)))
        
        edges = sorted(edges, key = lambda  x: x[2])
        cost = 0
        
        for edge in edges:
            x = edge[0]
            y = edge[1]
            if find(x) != find(y):
                union(x, y)
                cost += edge[2]
        
        return cost
            
        
        
                
                
                


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        ok=[-1 for i in range(len(points))]
        def union(x,y):
            x1=find(x)
            x2=find(y)
            ok[x1]=x2
        def find(x):
            if(ok[x]==-1):
                return x
            else:
                ok[x]=find(ok[x])
                return ok[x]
        d=[]
        for i in range(len(points)):
            for j in range(i+1,len(points)):
                d.append([abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1]),i,j])
        d.sort()
        ans=0
        count=0
        for i in d:
            x=find(i[1])
            y=find(i[2])
            if(x!=y):
                union(i[1],i[2])
                ans+=i[0] 
                count+=1
            if(count==len(points)-1):
                return ans
            
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        manhattan = lambda u, v: abs(u[0] - v[0]) + abs(u[1] - v[1])
        from collections import defaultdict
        n = len(points)

        graph = defaultdict(list)
        for i in range(n - 1):
            for j in range(i + 1, n):
                w = manhattan(points[i], points[j])
                graph[i].append((w, j))
                graph[j].append((w, i))

        k = 0
        costs = 0
        seen = [False] * n

        heap = [(0, 0)]
        while heap:
            w, u = heapq.heappop(heap)
            if not seen[u]:
                seen[u] = True
                costs += w
                k += 1

                if k == n: break
                for ew, v in graph[u]:
                        heapq.heappush(heap, (ew, v))
        return costs


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        uf = {}
        n = len(points)
        rank = [1] * n
        
        def find(x):
            uf.setdefault(x, x)
            if uf[x] != x:
                uf[x] = find(uf[x])
            return uf[x]
        
        def union(x, y):
            px, py = find(x), find(y)
            if px != py:
                if rank[px] > rank[py]:
                    px, py = py, px
                rank[py] += rank[px]
                uf[px] = py
                return rank[py] == n
            return False
        
        hp = [(abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]), i, j) for i in range(n) for j in range(i + 1, n)]
        heapq.heapify(hp)
        ans = 0
        
        while hp:
            d, i, j = heapq.heappop(hp)
            if find(i) != find(j):
                ans += d
                if union(i, j):
                    break
                
        return ans
    
        
        
        # n = len(points)
        # dist = lambda x, y: abs(x[0] - y[0]) + abs(x[1] - y[1])
        # dic = collections.defaultdict(list)
        # for i in range(n):
        #     for j in range(i + 1, n):
        #         d = dist(points[i], points[j])
        #         dic[i].append((d, j))
        #         dic[j].append((d, i))
        # hp = dic[0]
        # heapq.heapify(hp)
        # ans, cnt, seen = 0, 1, [1] + [0] * (n - 1)
        # while hp:
        #     d, i = heapq.heappop(hp)
        #     if not seen[i]:
        #         ans += d
        #         cnt += 1
        #         seen[i] = 1
        #         for j in dic[i]:
        #             heapq.heappush(hp, j)
        #         if cnt == n:
        #             break
        # return ans


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        n, graph = len(points), collections.defaultdict(dict)
        for i in range(n):
            for j in range(i+1, n):
                d = manhattan(points[i], points[j])
                graph[i][j] = graph[j][i] = d

        cnt, ans, visited = 0, 0, [0] * n
        heap = [(0, 0)]
        d = [float('inf')] * n
        d[0] = 0

        while heap:
            cost, node = heapq.heappop(heap)
            if visited[node]:
                continue
            visited[node], cnt, ans = 1, cnt + 1, ans + cost
            for nex in graph[node]:
                if d[nex] > graph[node][nex]:
                    d[nex] = graph[node][nex]
                    heapq.heappush(heap, (d[nex], nex))
            # if cnt >= n: break        
        return ans


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        cache = list(range(len(points)))

        def find(val):
            if cache[val] != val:
                cache[val] = find(cache[val])
            return cache[val]

        def union(x, y):
            cache[find(x)] = cache[find(y)]

        dists = []
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                dists.append((dist, i, j))

        dists.sort()
        ans = 0
        count = 0
        n = len(points)
        for dist, a, b in dists:
            if find(a) != find(b):
                count += 1
                ans += dist
                union(a, b)

            if count >= n - 1:
                break
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # for each point, you need to find the nearest point 
        import heapq
        
        graph = self.build_graph(points)
        min_heap = []
        start = 0
  
        for dist, node in graph[start]:
            heapq.heappush(min_heap, (dist, node))
        
        visited = set()
        visited.add(start)
        res = cnt = 0
        
        while len(min_heap) > 0:
            dist, node = heapq.heappop(min_heap)
            if cnt == len(points) - 1:
                break
            
            if node not in visited:
                res += dist 
                cnt += 1 
                visited.add(node)
                for nxt_dist, nxt_node in graph[node]:
                    heapq.heappush(min_heap, (nxt_dist, nxt_node)) 
            
        return res
    
    def build_graph(self, points):
        from collections import defaultdict
        graph = defaultdict(list)
        for i in range(len(points)):
            for j in range(len(points)):
                if i == j:
                    continue
                graph[i].append((self.dist(points[i], points[j]), j))
        return graph
                
    
    def dist(self, p0, p1):
        x0, y0 = p0
        x1, y1 = p1
        return abs(x1 - x0) + abs(y1 - y0)

class Solution:
    def minCostConnectPoints(self, A: List[List[int]]) -> int:
        #kruskal:
        n = len(A)
        distance_arr = []
        for i in range(n):
            for j in range(i+1, n):
                distance_arr.append([abs(A[j][0]-A[i][0])+abs(A[j][1]-A[i][1]), i, j])
        
        distance_arr.sort()
        root = [i for i in range(n)]
        
        def find(x):
            if root[x] != x:
                root[x] = find(root[x])
            return root[x]
        
        cnt = 0
        sm = 0
        for dis, x, y in distance_arr:
            if find(x) == find(y):
                continue
            root[find(x)] = find(y)
            cnt += 1
            sm += dis
            if cnt == n-1:
                break
        return sm

class Solution:
    def find(self, roots, x):
        if x == roots[x]:
            return x
        return self.find(roots, roots[x])
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        n = len(points)
        for i in range(n):
            for j in range(i + 1, n):
                x1, y1 = points[i]
                x2, y2 = points[j]
                d = abs(x1 - x2) + abs(y1 - y2)
                edges.append((d, i, j))
        edges.sort()
        roots = list(range(n))
        ranks = [0] * n
        count = 0
        res = 0
        for d, x, y in edges:
            rx = self.find(roots, x)
            ry = self.find(roots, y)
            if rx != ry:                
                if ranks[rx] > ranks[ry]:
                    roots[ry] = rx
                elif ranks[rx] < ranks[ry]:
                    roots[rx] = ry
                else:
                    roots[ry] = rx
                    ranks[rx] += 1
                count += 1
                res += d
                if count == n - 1:
                    return res
        
        return res

class UnionFind:
    def __init__(self):
        self.parents = {}
        self.sizes = {}

    def findParent(self, x):
        if x not in self.parents:
            self.parents[x] = x
            self.sizes[x] = 1

            return x

        if self.parents[x] != x:
            self.parents[x] = self.findParent(self.parents[x])

        return self.parents[x]

    def union(self, x, y):
        rootX, rootY = self.findParent(x), self.findParent(y)

        if rootX == rootY:
            return

        if self.sizes[rootX] < self.sizes[rootY]:
            self.sizes[rootY] += self.sizes[rootX]
            self.parents[rootX] = rootY
        else:
            self.sizes[rootX] += self.sizes[rootY]
            self.parents[rootY] = rootX

    def numberOfComponents(self):
        return sum(1 for x, p in self.parents.items() if x == p)

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def dist(x1,y1,x2,y2):
            return abs(x1-x2) + abs(y1-y2)
        
        uf = UnionFind()
        N = len(points)
        edges = []
        
        ans = 0
        
        for i in range(N):
            for j in range(i+1, N):
                [x1,y1],[x2,y2] = points[i], points[j]
                edges.append([dist(x1,y1,x2,y2), i, j])
        
        edges.sort()
        ans = 0
        
        edgesTaken = 0
        i = 0
        
        while edgesTaken < N-1:
            d, x, y = edges[i]
            
            if uf.findParent(x) != uf.findParent(y):
                uf.union(x, y)
                ans += d
                edgesTaken += 1
            
            i += 1
            
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def minnode(n, keyval, mstset): 
            mini = 999999999999
            mini_index = None

            # Loop through all the values of  
            # the nodes which are not yet  
            # included in MST and find the  
            # minimum valued one. 
            for i in range(n): 
                if (mstset[i] == False and 
                    keyval[i] < mini):  
                    mini = keyval[i] 
                    mini_index = i 
            return mini_index 
        
        
        def findcost(n, city): 
  
            # Array to store the parent  
            # node of a particular node.  
            parent = [None] * n 

            # Array to store key value  
            # of each node.  
            keyval = [None] * n  

            # Boolean Array to hold bool  
            # values whether a node is 
            # included in MST or not.  
            mstset = [None] * n 

            # Set all the key values to infinite and  
            # none of the nodes is included in MST. 
            for i in range(n): 
                keyval[i] = 9999999999999
                mstset[i] = False

            # Start to find the MST from node 0.  
            # Parent of node 0 is none so set -1.  
            # key value or minimum cost to reach  
            # 0th node from 0th node is 0.  
            parent[0] = -1
            keyval[0] = 0

            # Find the rest n-1 nodes of MST. 
            for i in range(n - 1): 

                # First find out the minimum node  
                # among the nodes which are not yet  
                # included in MST.  
                u = minnode(n, keyval, mstset)  

                # Now the uth node is included in MST.  
                mstset[u] = True

                # Update the values of neighbor  
                # nodes of u which are not yet  
                # included in MST.  
                for v in range(n): 
                    if (city[u][v] and mstset[v] == False and 
                        city[u][v] < keyval[v]):  
                        keyval[v] = city[u][v]  
                        parent[v] = u 

            # Find out the cost by adding  
            # the edge values of MST.  
            cost = 0
            for i in range(1, n): 
                cost += city[parent[i]][i]  
            return cost
    
        n = len(points)
        city = [[0 for c in range(n)] for r in range(n)]
        
        for r in range(n):
            c1 = points[r]
            for c in range(n):
                c2 = points[c]
                
                val = abs(points[r][0] - points[c][0]) + abs(points[r][1] - points[c][1])
                city[r][c] = val
        
        return findcost(n, city)
        
        
        


from queue import PriorityQueue
import math

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # Get lengths of edges, put into Priority Queue
#         q = PriorityQueue()
#         for i, point1 in enumerate(points):
#             for j, point2 in enumerate(points):
#                 if i == j: continue
#                 dist = abs(point1[0] - point2[0]) + abs(point1[1] - point2[1])
#                 q.put((dist, (i, j)))
                
        q = []
        for i in range(len(points)) :
            xi, yi = points[i]
            for j in range(i+1, len(points)) :
                xj, yj = points[j]
                q.append([abs(xi-xj)+abs(yi-yj), i, j])
        q = sorted(q)
        
        # For each edge in PQ, grab it, check if it forms a cycle in graph
        # If not, add it to the graph.
        # Increment cost.
        # We can check for a cycle with union find algorithm. (basically check parents)
        cost = 0
        self.arr = [-1 for el in range(len(points))]
        for el in q:
            d, p1, p2 = el[0], el[1], el[2]
            cycle = self.isCycle(p1, p2)
            # print(\"cycle\", cycle)
            if not cycle:
                cost += d
                # print(\"adding d\", d)
                self.combinePoints(p1, p2)
            else:
                continue
            if self.isDone(): break
            # print(self.arr)
        return cost
    
    def isDone(self):
        n_neg = 0
        for val in self.arr:
            if val < 0: n_neg += 1
        if n_neg ==1 : return True
        return False
        
    
    def combinePoints(self, p1, p2):
        # Find parent of p1, get size
        # Find parent of p2, get size
        # Whichever is smaller, make the smaller parent point to the larger parent.
        # Update the larger parent by adding the size of the smaller parent (keep negatives)
        parent1, children1 = self.getParent(p1, [])
        # print(p1, parent1)
        size1 = self.arr[parent1]
        parent2, children2 = self.getParent(p2, [])
        size2 = self.arr[parent2]
        
        # If parent2 is bigger
        if abs(size2) > abs(size1):
            self.arr[parent1] = parent2
            self.arr[parent2] = size2 + size1
            self.updateChildren(children1, parent2)
        else:
            self.arr[parent2] = parent1
            self.arr[parent1] = size2 + size1
            self.updateChildren(children2, parent1)
        
    def isCycle(self, p1, p2):
        parent1, _ = self.getParent(p1, [])
        parent2, _ = self.getParent(p2, [])
        if parent1 == parent2:
            return True
        else:
            return False
    
    def getParent(self, p1, children):
        if self.arr[p1] < 0: return p1, children
        else:
            children.append(p1)
            return self.getParent(self.arr[p1], children)
        
    def updateChildren(self, children, parent):
        for child in children:
            self.arr[child] = parent
        



class Solution:
    \"\"\"MST
    778. swim-in-rising-water
    787. cheapest-flights-within-k-stops
    1102. path-with-maximum-minimum-value
    1135. connecting-cities-with-minimum-cost
    1584. min-cost-to-connect-all-points
    \"\"\"
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def hm(p1, p2):
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        
        g = collections.defaultdict(list)
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                dist = hm(points[i], points[j])
                g[i].append((dist, j))
                g[j].append((dist, i))
        # print(g)
        
        visited = set()
        pq = [(0, 1)]
        res = 0
        while len(visited) < len(points):
            cost, p = heapq.heappop(pq)
            if p not in visited:
                res += cost
                visited.add(p)
                for nei_cost, nei_p in g[p]:
                    heapq.heappush(pq, (nei_cost, nei_p))
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # MST
        dist = []
        n = len(points)
        for i in range(n):
            for j in range(i):
                p1 = points[i]
                p2 = points[j]
                dist.append((abs(p1[0]-p2[0])+abs(p1[1]-p2[1]), i, j))
        dist.sort()
        ps = list(range(n))
        def find(x):
            while ps[x]!=x:
                ps[x] = ps[ps[x]]
                x = ps[x]
            return x
        
        def union(x, y):
            px = find(x)
            py = find(y)
            if px == py:
                return False
            else:
                ps[px] = py
                return True
        res = 0
        for d, x, y in dist:
            if union(x, y):
                res += d
        
        return res
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        vertices = {}
        x, y = points[0][0], points[0][1]
        
        for u, v in points: 
            vertices[(u, v)] = abs(u - x) + abs(v - y)
            
        def mindistance() -> tuple:
            
            Node = None
            
            for node in vertices:
                
                if not Node: Node = node
                elif vertices[node] < vertices[Node]: Node = node
            
            return Node
        
        n = len(points)
        Cost = 0
        
        for i in range(n):
            
            temp = mindistance()
            Cost += vertices[temp]
            vertices.pop(temp)
            
            for c in vertices:
                vertices[c]  = min(vertices[c], abs(c[0] - temp[0]) + abs(c[1] - temp[1]))
                
        return Cost
                    
            


import heapq

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        \"\"\"
        Prim's Algo - minimum spanning tree
        \"\"\"
        def manhattan(p1, p2):
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        
        res, n = 0, len(points)
        heap = [(0, (0, 0))]
        seen = set()
        
        while len(seen) < n:
            w, (u, v) = heapq.heappop(heap)
            if u in seen and v in seen:
                continue
            res += w
            seen.add(v)
            for j in range(n):
                if j not in seen and j != v:
                    heapq.heappush(heap, (manhattan(points[v], points[j]), (v, j)))
        
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def md(p1, p2):
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        q = [md(points[0], p) for p in points]
        print(q)
        res = 0
        for _ in range(len(points) - 1):
            d, j = min((d, j) for j, d in enumerate(q) if d > 0)
            print((d, j))
            res += d
            q = [min(q[i], md(points[i], points[j])) for i in range(len(q))]
        return res


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        if len(points) ==1:
            return 0
        heap = []      
        visited = set()        
        res = 0
        
        cur = 0
        visited.add(0)
        
        while len(visited)!=len(points):
            
            for i in range(len(points)):
                if cur==i:
                    continue
                heapq.heappush(heap, (abs(points[i][0]-points[cur][0])+abs(points[i][1]-points[cur][1]), i))
                
            while True:
                val, nxt = heapq.heappop(heap)
               
                if nxt not in visited:
                    
                    visited.add(nxt)
                    res+=val
                    cur = nxt
                    break
        
        return res
            
        


class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:
        
        def find(x):
            if dp[x]!=x:
                dp[x]=find(dp[x])
            return dp[x]

        def uni(x,y):
            x,y=find(x),find(y)
            if x!=y:
                dp[x]=find(y)
                return False   
            return True
            
        n=len(p)
        dp=list(range(n))    

        pool=sorted((abs(p[i][0]-p[j][0])+abs(p[i][1]-p[j][1]),i,j) for i in range(n) for j in range(i+1,n))
        
        ct=res=0
        

        for dis,u,v in pool:
            if not uni(u,v):
                res+=dis
                ct+=1
            if ct==n-1:
                break
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        import heapq
        
        connect = list(range(N))
        def find(x):
            if connect[x]!=x:
                connect[x] = find(connect[x])
            return connect[x]
        
        def union(x, y):
            connect[find(x)] = find(y)
        
        
        q = []
        for i in range(N):
            for j in range(i):
                w = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                q.append((w, i, j))
        q.sort()
        
        res = 0
        for w, i, j in q:
            if find(i) == find(j):
                continue
            else:
                res += w
                union(i, j)
        
        return res
                
        
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        parents = {}
        def find(p):
            if p not in parents:
                parents[p] = p
            if parents[p] != p:
                parents[p] = find(parents[p])
            return parents[p]
        
        def merge(p, q):
            i,j = find(p), find(q)
            if i != j:
                parents[j] = i
        
        def isconnected(p, q):
            return find(p) == find(q)
        
        n = len(points)
        pq = []
        for i in range(n):
            for j in range(i+1, n):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                heapq.heappush(pq, [dist, i, j])
            
        edge = 0
        res = 0
        while edge < n-1:
            dist, i, j = heapq.heappop(pq)
            if isconnected(i,j):
                continue
            else:
                edge += 1
                res += dist
                merge(i, j)
        return res


class Ufs:
    def __init__(self, n):
        self.p = [i for i in range(n)]
        self.rank = [0 for i in range(n)]
    def find(self, i):
        if self.p[i]!=i:
            self.p[i] = self.find(self.p[i])
        return self.p[i]
    def union(self, a, b):
        aroot = self.find(a)
        broot = self.find(b)
        if aroot == broot:
            return 
        if self.rank[aroot]<self.rank[broot]:
            self.p[aroot] = broot
        elif self.rank[aroot]>self.rank[broot]:
            self.p[broot] = aroot
        else:
            self.p[aroot] = broot
            self.rank[broot] +=1
    def connect(self, a, b):
        if self.find(a)==self.find(b):
            return True
        else:
            return False
        
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        calc = lambda x,y: abs(x[0]-y[0])+abs(x[1]-y[1])
        edges = []
        n = len(points)
        vis = {}
        for i in range(n):
            for j in range(i+1,n):
                edges.append([calc(points[i], points[j]), i, j])
        edges.sort()
        ans = 0
        ufs = Ufs(n)
        cnt = i = 0
        while(cnt<n-1):
            w, u, v = edges[i]
            i +=1
            if ufs.connect(u,v):
                continue
            ans +=w
            ufs.union(u,v)
            cnt+=1
        return ans
                


from collections import defaultdict
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = defaultdict(list)
        n = len(points)
        for i in range(n-1):
            x,y = points[i]
            for j in range(i+1, n):
                u,v = points[j]
                d = abs(x-u) + abs(y-v)
                edges[d].append((i,j))
        find = {i:i for i in range(n)}
        union = {i:set([i]) for i in range(n)}
        cost = 0
        m = n-1
        min_edges = sorted(edges.keys())
        while m>0:
            d = min_edges.pop(0)
            j = 0
            while m>0 and j<len(edges[d]):
                u,v = edges[d][j]
                if find[u]!=find[v]:
                    x = min(find[u], find[v])
                    y = max(find[u], find[v])
                    
                    for z in union[y]:
                        find[z] = x
                    
                    union[x] = union[x] | union[y]
                    
                    cost += d
                    m -= 1
                j += 1
        return cost


class DSU:
    def __init__(self,n):
        self.parent = [i for i in range(n)]
        self.rank = [1 for i in range(n)]
        self.count = n
    
    def find(self,x):
        if x!=self.parent[x]:
            self.parent[x]=self.find(self.parent[x])
        return self.parent[x]
    
    def union(self,x,y):
        px = self.find(x)
        py = self.find(y)
        if px==py:
            return False
        self.count-=1
        if self.rank[x]>self.rank[y]:
            self.parent[py]=px
            self.rank[px]+=self.rank[py]
        else:
            self.parent[px]=py
            self.rank[py]+=self.rank[px]
        return True
                
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        edges = []
        for i in range(n):
            for j in range(i+1, n):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((dist, i, j))
        # print(edges)
        # edges.sort()
        heapq.heapify(edges)
        res = 0
        ds = DSU(n)
        while edges and ds.count!=1:
            cost,u,v = heapq.heappop(edges)
            if ds.union(u,v):
                res += cost
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # for each point, you need to find the nearest point 
        import heapq
        
        graph = self.build_graph(points)
        min_heap = []
        start = 0
  
        for dist, node in graph[start]:
            heapq.heappush(min_heap, (dist, node))
        
        visited = set()
        visited.add(start)
        res = cnt = 0
        
        while len(min_heap) > 0:
            dist, node = heapq.heappop(min_heap)
            if node not in visited:
                res += dist 
                cnt += 1 
                visited.add(node)
                for nxt_dist, nxt_node in graph[node]:
                    heapq.heappush(min_heap, (nxt_dist, nxt_node)) 
            
            if cnt == len(points) - 1:
                break
            
        return res
    
    def build_graph(self, points):
        from collections import defaultdict
        graph = defaultdict(list)
        for i, p0 in enumerate(points):
            for j, p1 in enumerate(points):
                if i == j:
                    continue
                graph[i].append((self.dist(p0, p1), j))
        return graph
                
    
    def dist(self, p0, p1):
        x0, y0 = p0
        x1, y1 = p1
        return abs(x1 - x0) + abs(y1 - y0)

import heapq

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        num_of_points = len(points)
        if num_of_points == 1:
            return 0
        distance = [[float(\"inf\") for _ in range(num_of_points)] for _ in range(num_of_points)]
        for i in range(num_of_points):
            for j in range(i+1, num_of_points):
                temp_distance = self.countDistance(points[i], points[j])
                distance[i][j] = temp_distance
                distance[j][i] = temp_distance
        visited = [False for _ in range(num_of_points)]
        q = [(0, 0)]
        cost = 0
        heapq.heapify(q)
        while False in visited:
            # print(visited)
            d, node= heapq.heappop(q)
            while visited[node]:
                d, node = heapq.heappop(q)
            visited[node] = True
            cost += d
            for i in range(num_of_points):
                if not visited[i]:
                    heapq.heappush(q, (distance[node][i], i))
        return cost
            
    
            
    def countDistance(self, p1, p2):
        return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        
        def find(u):
                
            while parents[u]>=0:
                u = parents[u]
            
            return u
        
        def union(u,v):
             
            if parents[u]<parents[v]:
                parents[u] += parents[v]
                parents[v] = u
            
            else:
                parents[v]+=parents[u]
                parents[u]=v
                
        n = len(points)
        costs = {}
        
        for i in range(n):
            for j in range(i+1,n):
                costs[(i,j)] = abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                
        sorted_costs = sorted(list(costs.items()), key=lambda cost: -cost[1])
        
        s = set()
        cost = 0
        parents = [-1]*n
        
        while sorted_costs:
            
            (u,v),weight = sorted_costs.pop()
            
            pu = find(u)
            pv = find(v)
            
            if (pu!=pv):
                union(pu,pv)
                cost+=weight
            
        return cost
    
        


from heapq import heappush, heappop
class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:
        
        def helper(i, j):
            return abs(p[j][0]-p[i][0]) + abs(p[j][1]-p[i][1])
        
        g = defaultdict(lambda: {}); n = len(p)
        for i in range(n-1):
            for j in range(i+1, n):
                g[i][j] = g[j][i] = helper(i,j)

        visited = set(); res = 0; q = []; cnt=0
        heappush(q, (0, 0)) # u:0, cost:0
        while q:
            cost, u = heappop(q)
            if u in visited: continue
            res += cost
            #cnt += 1
            for v, w in g[u].items():
                heappush(q, (w, v))
            visited.add(u)
            #if cnt >= n: break
            if len(visited) >= n: break
        return res
        
        
    
\"\"\"
[[0,0],[2,2],[3,10],[5,2],[7,0]]
[[3,12],[-2,5],[-4,1]]
[[0,0],[1,1],[1,0],[-1,1]]
[[-1000000,-1000000],[1000000,1000000]]
[[0,0]]
\"\"\"            

from queue import PriorityQueue as PQ
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        dist = [[] for _ in range(n)]
        for i in range(n):
            xi, yi = points[i]
            for j in range(i+1, n):
                xj, yj = points[j]
                d = abs(xi-xj) + abs(yi-yj)
                dist[i].append((j, d))
                dist[j].append((i, d))
        chosen = set([0])
        pq = PQ()
        seen = [0]*n
        for i, d in dist[0]:
            pq.put((d, i))
            seen[i] = d
        ans, edges = 0, 0
        while not pq.empty() and edges < n-1:
            d, i = pq.get()
            if i not in chosen:
                chosen.add(i)
                ans += d
                edges += 1
                for j, dj in dist[i]:
                    if j not in chosen and dj < seen[j]:
                        pq.put((dj, j))
                        seen[j] = dj
        return ans


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def md(p1, p2):
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        q = [md(points[0], p) for p in points]
        #print(q)
        res = 0
        n = len(points)
        for _ in range(n - 1):
            d, j = min((d, j) for j, d in enumerate(q) if d > 0)
            #print(d, j)
            res += d
            q = [min(q[i], md(points[i], points[j])) for i in range(n)]
        return res


class DisjointSet:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [1 for i in range(n)]
        
    def find(self, a):
        if self.parent[a] == a:
            return a
        
        self.parent[a] = self.find(self.parent[a])
        return self.parent[a]
    
    def union(self, a, b):
        pa, pb = self.parent[a], self.parent[b]
        if pa == pb:
            return 
        
        if self.rank[a] > self.rank[b]:
            self.parent[pb] = pa
            self.rank[pa] += self.rank[pb]
            
        else:
            self.parent[pa] = pb
            self.rank[pb] += self.rank[pa]



class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        # minimum spanning tree
        man_dist = lambda a, b: abs(a[0] - b[0]) + abs(a[1] - b[1])
        
        n = len(points)
        
        all_dists = []
        for i in range(n):
            for j in range(i+1, n):
                all_dists.append((man_dist(points[i], points[j]), i, j))
                
                
        all_dists.sort(key=lambda x: x[0])
        
        # print(all_dists)
        # print(len(all_dists))
        
        ans = 0
        dis_set = DisjointSet(n)
        
        for dist, u, v in all_dists:
            if dis_set.find(u) != dis_set.find(v):
                dis_set.union(u, v)
                ans += dist
                
                
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) == 1:
            return 0
        
        neibors = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                point1 = points[i]
                point2 = points[j]
                dis = abs(point1[0]-point2[0]) + abs(point1[1]-point2[1])
                neibors.append((dis, i, j))
        neibors_sorted = sorted(neibors)
        
        unions = {i:i for i in range(len(points))}
        
        def find(i):
            if unions[i] == i:
                return i
            else:
                unions[i] = find(unions[i])
                return unions[i]
        
        ret = 0
        line = 0
        for neibor in neibors_sorted:
            if find(neibor[1]) != find(neibor[2]):
                unions[find(neibor[1])] = find(neibor[2])
                ret += neibor[0]
                line += 1
                if line == (len(points)-1):
                    return ret
            else:
                continue
            
            
            
        
        
        
        
        
        
        
        
        
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # dikstra algo
        if len(points) == 0:
            return 0
        heap = []
        for i in range(1, len(points)):
            heapq.heappush(heap, (abs(points[i][0] - points[0][0]) + abs(points[i][1] - points[0][1]), i))
        ret = 0
        while heap:
            cost, e_pop = heapq.heappop(heap)
            ret += cost
            heap_new = []
            for cost_old, e in heap:
                heapq.heappush(heap_new, (min(cost_old, abs(points[e][0] - points[e_pop][0]) + abs(points[e][1] - points[e_pop][1])), e))
            heap = heap_new
        return ret


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        edges = []
\t\t
        for i in range(n):
            for j in range(i+1, n):
                d = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((d, i, j))
        
        edges.sort()
        
        roots = [i for i in range(n)]
        
        def find(v):
            if roots[v] != v:
                roots[v] = find(roots[v])
            return roots[v]
        
        def union(u, v):
            p1 = find(u); p2 = find(v)
            if p1 != p2:
                roots[p2] = roots[p1]
                return True
            return False
        
        res = 0
        for d, u, v in edges:
            if union(u, v):
                res += d
        return res

class Solution:
    def getWeight(self, x, y):
        xi, xj = x[0], x[1]
        yi, yj = y[0], y[1]
        return abs(xi - yi) + abs(xj - yj)
    
    def find(self, parent, i):
        if parent[i] == i: return i
        return self.find(parent, parent[i])

    def union(self, parent, rank, x, y):
        xroot = self.find(parent, x)
        yroot = self.find(parent, y)
        if rank[xroot] < rank[yroot]:
            parent[xroot] = yroot
        elif rank[xroot] > rank[yroot]:
            parent[yroot] = xroot
        else:
            parent[yroot] = xroot
            rank[xroot] += 1

    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        E = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                u = points[i]
                v = points[j]
                E.append([i, j, self.getWeight(u, v)])
        E = sorted(E, key=lambda item: item[2])
        parent = []
        rank = []
        for node in range(len(points)):
            parent.append(node)
            rank.append(0)
        e = 0
        i = 0
        result = 0
        while e < len(points)-1:
            u, v, w = E[i]
            i += 1
            x = self.find(parent, u)
            y = self.find(parent, v)
            if x != y:
                e += 1
                result += w
                self.union(parent, rank, x, y)
        return result

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        def distance(p1, p2):
            return abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        
        ans = 0
        h = []
        heappush(h, (0, points[0]))
        visited = set()
        
        while h:
            d, p = heappop(h)
            if (p[0], p[1]) in visited:
                continue
            visited.add((p[0], p[1]))
            ans += d
            
            for point in points:
                if (point[0], point[1]) not in visited:
                    heappush(h, (distance(p, point), point))
                    
            if len(visited) == N:
                break
                
        return ans
                    
        
    def minCostConnectPoints_2(self, points: List[List[int]]) -> int:
        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        n, c = len(points), collections.defaultdict(list)
        for i in range(n):
            for j in range(i+1, n):
                d = manhattan(points[i], points[j])
                c[i].append((d, j))
                c[j].append((d, i))
        cnt, ans, visited, heap = 1, 0, [0] * n, c[0]
        visited[0] = 1
        heapq.heapify(heap)
        while heap:
            d, j = heapq.heappop(heap)
            if not visited[j]:
                visited[j], cnt, ans = 1, cnt+1, ans+d
                for record in c[j]: heapq.heappush(heap, record)
            if cnt >= n: break        
        return ans  
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        npoints = len(points)
        if npoints == 1:
            return 0
        edges = dict()
        for i in range(npoints):
            for j in range(i+1,npoints):
                edges[(i,j)] = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
        
        sortededges = {k: v for k,v in sorted(edges.items(), key=lambda item: item[1]) }

        parent = [i for i in range(npoints)]
        mincost = 0
        numedges = 0
        for edge in sortededges:
            if self.findParent(parent, edge[0]) == self.findParent(parent, edge[1]):
                continue
            else:
                mincost += sortededges[edge]
                self.union(parent, edge[0], edge[1])
                numedges += 1
                if numedges == npoints-1:
                    return mincost
    
    def findParent(self, parent, i):
        if parent[i] == i:
            return i
        return self.findParent(parent, parent[i])
    
    def union(self, parent, u, v):
        u_set = self.findParent(parent, u)
        v_set = self.findParent(parent, v)
        parent[u_set] = v_set

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def manhantan_distance(x, y):
            return abs(x[0] - y[0]) + abs(x[1] - y[1])
        
        n = len(points)
        included = {0}
        distances = [manhantan_distance(points[0], point) for point in points]
        cost = 0
        while len(included) < n:
            to_add = None
            cost_to_add = float('inf')
            for i, distance in enumerate(distances):
                if i in included:
                    continue
                if distance < cost_to_add:
                    to_add = i
                    cost_to_add = distance
            
            included.add(to_add)
            cost += cost_to_add
            
            new_point = points[to_add]
            for i, point in enumerate(points):
                new_distance = manhantan_distance(new_point, point)
                distances[i] = min(distances[i], new_distance)
            
        return cost


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n == 1:
            return 0
        
        d = []
        for i, (xi,yi) in enumerate(points[:-1]):
            for j, (xj,yj) in enumerate(points[i+1:]):
                d.append([i,i+j+1,abs(xj-xi)+abs(yj-yi)])
        d = sorted(d, key=lambda r: r[2])
        
        father = {i:i for i in range(n)}
        def find(x):
            if x != father[x]:
                father[x] = find(father[x])
            return father[x]

        res, c = 0, 0
        for i,j,distance in d:
            if find(i) != find(j):
                father[find(i)] = j
                res += distance
                c += 1
                if c == n-1:
                    return res
            


class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:
        n=len(p)

        parents=list(range(n))
        def find(x):
            if parents[x]!=x:
                parents[x]=find(parents[x])
                
            return parents[x]
                
        def union(x,y):
            r1=find(x)
            r2=find(y)
            
            if r1!=r2:
                parents[r2]=r1
                return True
            else:
                return False

        def dist(p1,p2):
            return abs(p1[0]-p2[0])+abs(p1[1]-p2[1])
        
        a=[]
        for i in range(n):
            for j in range(i+1,n):
                d=dist(p[i],p[j])
                a.append((d,i,j))
        
        a.sort()
        ans=0
        for d,p1,p2 in a:
            if union(p1,p2):
                ans+=d
        
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # Prims algorithm O(V+ElogV)
        if not points or len(points) <= 1:
            return 0
        
        p_dis = {}
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                p1 = points[i]
                p2 = points[j]
                dis = abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
                p_dis.setdefault(i, [])
                p_dis.setdefault(j, [])
                p_dis[i].append((dis, j))
                p_dis[j].append((dis, i))
        
        visited = [False] * len(points)
        visited[0] = True
        count = 1
        heap = []
        res = 0
        for d, p in p_dis[0]:
            heapq.heappush(heap, (d, p))
        while heap:
            dis, p = heapq.heappop(heap)
            if not visited[p]:
                count += 1
                visited[p] = True
                res += dis
                for _d, _p in p_dis[p]:
                    heapq.heappush(heap, (_d, _p))
            
            if count == len(points):
                break
        
        return res
        
        
        
        # Kruskal algorithm
#         if not points or len(points) <= 1:
#             return 0
        
#         heap = []
#         for i in range(len(points)):
#             for j in range(i + 1, len(points)):
#                 p1 = points[i]
#                 p2 = points[j]
#                 dis = abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
#                 heapq.heappush(heap, (dis, i, j))
        
#         self.father = [i for i in range(len(points))]
#         res = 0
#         while heap:
#             dis, u, v = heapq.heappop(heap)
#             root_u = self.find(u)
#             root_v = self.find(v)
#             if root_u == root_v:
#                 continue
#             self.father[max(root_u, root_v)] = min(root_u, root_v)
#             res += dis
        
#         return res
    
#     def find(self, x):
#         if self.father[x] == x:
#             return self.father[x]
#         self.father[x] = self.find(self.father[x])
#         return self.father[x]



class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) == 1: 
            return 0

        result = 0 
        distance = [math.inf] * len(points)  # idx -> distance 
        current = 0
        combined = set() 

        for i in range(len(points)-1): 
            combined.add(current)
            x, y = points[current]
            for j in range(len(points)): 
                if j in combined:
                    continue
                x2, y2 = points[j]
                distance[j] = min(distance[j], abs(x-x2) + abs(y-y2))

            d = 0
            for j in range(len(distance)):
                if distance[j] < distance[current]:
                    current = j
                    d = distance[j]\t
            distance[current] = math.inf
            result += d

        return result 




class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        parents = [i for i in range(n)]
        def ufind(node):
            nonlocal parents 
            if parents[node] == node:
                return node 
            parents[node] = ufind(parents[node])
            return parents[node] 
        
        def union(node1, node2):
            p1 = ufind(node1) 
            p2 = ufind(node2) 
            if p1!=p2:
                parents[p2] = p1 
                
                
        def MST(edges):
            nonlocal n
            edges.sort(key = lambda x: x[2]) 
            ans = 0 
            for i in edges: 
                p1 = ufind(i[0]) 
                p2 = ufind(i[1]) 
                if p1!=p2:
                    ans += i[2] 
                    union(p1,p2) 
            return ans 
            
        
        edges = []
        for i in range(n):
            for j in range(i+1,n):
                edges.append((i,j, abs(points[i][0]- points[j][0]) + abs(points[i][1] - points[j][1]))) 
        return MST(edges) 


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        arr = []
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                xi, yi = points[i]
                xj, yj = points[j]
                arr.append([i, j, abs(xi - xj) + abs(yi - yj)])
        arr.sort(key=lambda x: x[2])
        visited = set()
        res = 0
        group = []
        for i in range(len(arr)):
            u, v, d = arr[i]
            if u not in visited and v not in visited:
                visited.add(u)
                visited.add(v)
                res += d
                group.append({u, v})
            elif u in visited and v in visited:
                for idx, tmp in enumerate(group):
                    if u in tmp:
                        ui = idx
                    if v in tmp:
                        vi = idx
                if ui != vi:
                    group[ui].update(group[vi])
                    group.pop(vi)
                    res += d
            else:
                for idx, tmp in enumerate(group):
                    if u in tmp:
                        group[idx].add(v)
                        break
                    elif v in tmp:
                        group[idx].add(u)
                        break
                visited.add(u)
                visited.add(v)
                res += d

        return res


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n, res = len(points), 0
        if n <= 1: return res
        dists = [(abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]), i, j) 
                for i in range(n-1) for j in range(i+1, n)]
        dists.sort()
        parents = list(range(n))
        def find(c):
            prec = c
            while parents[c] != c:
                c = parents[c]
            union(prec, c)
            return c
        def union(src, dst):
            if src != dst:
                parents[src] = dst
        for d, src, dst in dists:
            ps, pd = find(src), find(dst)
            if ps != pd:
                res += d
                union(ps, pd)
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def distance(p1, p2):
            return abs(p2[0]-p1[0]) + abs(p2[1]-p1[1])
        
        dist_list = [distance(points[0], p) for p in points]
        
        res, n = 0, len(points)
        for _ in range(n-1):
            d, j = min((d, j) for j, d in enumerate(dist_list) if d > 0)
            res += d
            dist_list = [min(dist_list[i], distance(p, points[j])) for i, p in enumerate(points)] 
            
        return res

class DSU:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [0 for _ in range(n)]
        
    def find(self, i):
        if self.parent[i] == i:
            return i
        else: return self.find(self.parent[i])
        
    def union(self, i, j):
        x, y = self.find(i), self.find(j)
        
        rx, ry = self.rank[x], self.rank[y]
        
        if rx > ry:
            self.parent[y] = x
            
        elif rx < ry:
            self.parent[x] = y
            
        else:
            self.parent[y] = x
            self.rank[x] += 1 


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        edges = []
        
        
        for i in range(n):
            for j in range(n):
                dist = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                
                edges.append((i, j, dist))
                
        edges.sort(key = lambda x: x[2])
        
        d = DSU(n)
        
        e = 0
        i = 0
        ret = 0
        
        while e < n-1:
            if d.find(edges[i][0]) != d.find(edges[i][1]):
                ret += edges[i][2]
                d.union(edges[i][0], edges[i][1])
                e += 1
                
            i += 1
            
            
        return ret

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        from collections import defaultdict
        graph = []
        for i in range(len(points)):
            for j in range(i+1,len(points)):
                val = abs(abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]))
                graph.append([tuple(points[i]),tuple(points[j]),val])
        graph.sort(key = lambda x:x[-1])
        parent = {tuple(i):tuple(i) for i in points}
        def find(x):
            if parent[x] == x:
                return x
            parent[x] = find(parent[x])
            return parent[x]
        def union(x,y):
            a,b = find(x),find(y)
            if a!=b:
                parent[a] = b
                return True
            else:
                return False
        v = 0
        n = len(points)
        res = 0
        i = 0
        while v != n-1:
            a,b,dist = graph[i]
            if union(a,b):
                res += dist
                v += 1
            i += 1
        return res


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        
        dist = {}
        pair, mindist = (0, 0), math.inf        
        for i in range(N):
            for j in range(i + 1, N):
                d = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                dist[(i, j)] = dist[(j, i)] = d
                if d < mindist:
                    pair, mindist = (i, j), d
            
        res = mindist
        mst = set(pair)
        other = set(i for i in range(N) if i not in mst)
        h = []
        for v in mst:
            for i in other:
                heapq.heappush(h, (dist[(v, i)], i))
        
        while len(mst) < N:
            d, i = heapq.heappop(h)
            if i not in mst:
                res += d
                mst.add(i)
                other.remove(i)
                for j in other:
                    heapq.heappush(h, (dist[(i, j)], j))
                    
        return res if N > 1 else 0


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) == 1:
            return 0
        points = sorted(points, key=lambda r: r[0])
        (x1,y1), (x2,y2) = points[:2]
        cost = abs(x2-x1) + abs(y2-y1)
        
        if len(points) == 2:
            return cost
        
        n = len(points)
        d = []
        for i, (x,y) in enumerate(points[:-1]):
            for j, (xj,yj) in enumerate(points[i+1:]):
                d.append([i,i+j+1, abs(xj-x)+abs(yj-y)])
        connections = sorted(d, key=lambda r: r[2])
        
        parent = [i for i in range(n)]
        
        def find(x):
            if x != parent[x]:
                parent[x] = find(parent[x])
            return parent[x]
        
        res, e, k = 0, 0, 0
        while e < n - 1:
            u, v, w = connections[k]
            k += 1
            x, y = find(u-1), find(v-1)
            if x != y:
                e += 1
                res += w
                parent[x] = y
        return res
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        def dist(points,i,j):
            return abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
        a = collections.defaultdict(list)
        for i in range(n):
            for j in range(i+1,n):
                d = dist(points,i,j)
                a[i].append((d,j))
                a[j].append((d,i))
        ans,cnt,q,visited = 0,1,a[0],[0] * n
        visited[0] = 1
        heapify(q)
        while q:
            d,j = heappop(q)
            if not visited[j]:
                visited[j] = 1
                cnt += 1
                ans += d
                for i in a[j] : heappush(q,i)
            if cnt >= n:
                break
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        @functools.lru_cache(None)
        def distance(i,j):
            return abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
        not_added=set([i for i in range(1,len(points))])
        distance_to_added=[math.inf for i in range(len(points))]
        i=0
        res=0
        while not_added:
            for j in not_added:
                distance_to_added[j]=min(distance_to_added[j],distance(i,j))
            while not_added:
                i=min(range(len(points)),key=lambda x:distance_to_added[x])
                if i in not_added:
                    res+=distance_to_added[i]
                    not_added.remove(i)
                    break
                distance_to_added[i]=math.inf
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        dis = [math.inf for i in range(n)]
        myset = set()
        myset.add(0)
        res = 0
        pt = points[0]
        for i in range(n-1):
            for idx, item in enumerate(points):
                if(idx in myset):
                    continue
                else:
                    dis[idx] = min(dis[idx], abs(pt[0]-item[0])+abs(pt[1]-item[1]))
            mins = min(dis)
            res += mins
            cur = dis.index(mins)
            myset.add(cur)
            dis[cur] = math.inf
            pt = points[cur]
        return res
        
                


class DSU:
    def __init__(self, n):
        self.par = list(range(n))
        self.rnk = [0] * n

    def find(self, x):
        if self.par[x] != x:
            self.par[x] = self.find(self.par[x])
        return self.par[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        if xr == yr:
            return False
        if self.rnk[xr] < self.rnk[yr]:
            xr, yr = yr, xr
        if self.rnk[xr] == self.rnk[yr]:
            self.rnk[xr] += 1
        self.par[yr] = xr
        return True

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # Prim
        N = len(points)
        
        def dist(i, j):
            return (
                abs(points[i][0] - points[j][0]) + 
                abs(points[i][1] - points[j][1])
            )
        
        pq = [[dist(0, j), 0, j] for j in range(1, N)]
        heapq.heapify(pq)
        actives = {0}
        ans = 0
        
        while len(actives) != N:
            d, u, v = heapq.heappop(pq)
            if u not in actives or v not in actives:
                ans += d
                node, = {u, v} - actives
                actives.add(node)
                for nei in range(N):
                    if nei not in actives:
                        heapq.heappush(pq, [dist(node, nei), node, nei])
                        
        return ans
        
        # Kruskal 
        N = len(points)
        edges = []
        for u in range(N-1):
            for v in range(u+1, N):
                edges.append([u, v, abs(points[u][0] - points[v][0]) + abs(points[u][1] - points[v][1])])
                
        def MST():
            # Kruskals, edges sorted
            dsu = DSU(N)
            ans = 0
            for u, v, w in sorted(edges, key=lambda e: e[2]):
                if dsu.union(u, v):
                    ans += w
            return ans
        
        return MST()


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # create MST over a created graph
        q = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                dis = abs(points[i][0]-points[j][0]) + abs(points[i][1] - points[j][1])
                q.append((dis, i, j))
        
        # MST search algorithm Kruskal
        def find(x):
            if (x != parent[x]):
                parent[x] = find(parent[x])
            return parent[x]
        def union(x, y):
            if size[x] > size[y]:
                size[x] += size[y]
                parent[y] = x
            else:
                size[y] += size[x]
                parent[x] = y
                
        n = len(points)
        parent = [i for i in range(n+1)]
        size = [1 for _ in range(n+1)]  
        q.sort()  # sort edges
        res = 0
        count = 0
        for w, u, v in q:
            rA, rB = find(u), find(v)
            if rA == rB:
                continue
            union(rA, rB)
            res += w
            # Optimize so that we don't traverse all edges
            count += 1
            if count == n:
                return res
        return res 

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def md(p1, p2):
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        q = [md(points[0], p) for p in points]
        res = 0
        for _ in range(len(points) - 1):
            d, j = min((d, j) for j, d in enumerate(q) if d > 0)
            res += d
            q = [min(q[i], md(points[i], points[j])) for i in range(len(q))]
        return res


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        graph = collections.defaultdict(list) #没事不要用default(dict)
        for i in range(N):
            x1,y1 = points[i]
            for j in range(i + 1):
                x2, y2 = points[j]
                z = abs(x1-x2) + abs(y1 - y2)
                graph[i].append((j,z))
                graph[j].append((i,z))
        
            
        heap = []
        visited = set()
        heapq.heappush(heap,(0,1))
        total = 0
        while heap:
            cost, node = heapq.heappop(heap)
            if node in visited: continue #prim 算法都是先检测有没有访问过，再添加到visited里面，而不是在后面的next node添加到visited中去
            visited.add(node)
            total += cost
            if len(visited) == N:
                return total
            for nxt,c  in graph[node]:
                if nxt  not in visited:
                    heapq.heappush(heap,(c, nxt)) #放入到heap中的绝对是新的单边距离，而不是总距离
        return -1


class Solution:
    def find(self, x, parent):
        if parent[x] != x:
            parent[x] = self.find(parent[x], parent)
        return parent[x]
    
    def union(self, x, y, parent):
        px, py = self.find(x, parent), self.find(y, parent)
        parent[py] = px
        
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        parent = []
        n = len(points)
        for i in range(n):
            parent.append(i)
        edges = []
        for i in range(len(points)):
            x, y = points[i]
            for j in range(i+1, len(points)):
                u, v = points[j]
                edges.append([i,j,abs(x-u)+abs(y-v)])
        edges = sorted(edges, key = lambda x:x[2])
        cost  = 0
        for i in range(len(edges)):
            p1, p2, w = edges[i]
            if self.find(p1, parent) != self.find(p2, parent):
                self.union(p1, p2, parent)
                cost += w
        return cost
                


class DSU:
    def __init__(self, arr):
        self.p = {}
        self.n = 0
            
    def add(self, u):
        self.p[u] = u
        self.n += 1
        
    def find(self, u):
        if self.p[u]!=u:
            self.p[u] = self.find(self.p[u])
        return self.p[u]
    
    def union(self, x, y):
        self.p[self.find(x)] = self.find(y)
        self.n -= 1

from itertools import combinations
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        '''
        d = DSU([])
        edge = []
        ans = 0
        for i in range(len(points)-1):
            d.add(tuple(points[i]))
            for j in range(i+1,len(points)):
                dis = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                edge.append([(points[i],points[j]), dis])
        d.add(tuple(points[-1]))
        edge.sort(key=lambda x:x[1])
        for e in edge:
            if d.find(tuple(e[0][0])) != d.find(tuple(e[0][1])):
                d.union(tuple(e[0][0]),tuple(e[0][1]))
                ans += e[1]
            if d.n == 0:
                break
        return ans
        '''
        
        
        comb = list(combinations(points, 2))
        edges = []
        ans = 0
        for c in comb:
            d = abs(c[0][0]-c[1][0])+abs(c[0][1]-c[1][1])
            edges.append((c, d))
        edges.sort(key=lambda x: x[1])
        s = []
        for p in points:
            p = tuple(p)
            t = set()
            t.add(p)
            s.append(t)
        print(s)
        for e in edges:
            u1 = -1
            u2 = -1
            for i in range(len(s)):
                if tuple(e[0][0]) in s[i]:
                    u1 = i
                if tuple(e[0][1]) in s[i]:
                    u2 = i
            if u1 != u2:
                s[u1] = s[u1] | s[u2]
                s.pop(u2)
                ans += e[1]
            if len(s) == 1:
                break
        return ans
       


class UnionFind:
    def __init__(self, n):
        self.parents = [i for i in range(n)]
        self.size = [1] * n

    def find(self, i):
        while i != self.parents[i]:
            self.parents[i] = self.parents[self.parents[i]] # path halving
            i = self.parents[i]
        return i
    
    def union(self, a, b):
        aPar = self.find(a)
        bPar = self.find(b)
        
        if aPar == bPar:
            return False
        
        # union by size
        if self.size[aPar] > self.size[bPar]:
            self.parents[bPar] = aPar
            self.size[aPar] += self.size[bPar]
        else:
            self.parents[aPar] = bPar
            self.size[bPar] += self.size[aPar]
        
        return True
    
    def getSize(self, a):
        return self.size[self.find(a)]

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def getDistance(a,b):
            return abs(a[0] - b[0]) + abs(a[1] - b[1])
        
        N = len(points)
        uf = UnionFind(N)
        edges = []
        
        for i in range(N):
            for j in range(i+1, N):
                edges.append((getDistance(points[i], points[j]), i, j))
                
        edges.sort(key=lambda x:x[0])
        
        cost = 0
        seen = 0
        for w,a,b in edges:
            if uf.union(a,b):
                cost += w
                i += 1
                if seen == N:
                    break
                    
        return cost


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def find(x):
            if x != p[x]:
                p[x] = find(p[p[x]])
            return p[x]
        
        p = list(range(len(points)))
        g = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                g.append((i, j, abs(points[j][1]-points[i][1]) + abs(points[j][0]-points[i][0])))
        
        cost = 0
        for u, v, w in sorted(g, key=lambda x:x[2]):
            ru, rv = find(u), find(v)
            if ru == rv:
                continue
            p[ru] = rv
            cost += w
        
        return cost

#Kruskal's Algorithm
class UnionFind:
    def __init__(self, n):
        self.leaders = [i for i in range(n)]
        self.ranks = [1 for i in range(n)]
    
    def find(self, x):
        # p = x
        # while p != self._leaders[p]:
        #     p = self._leaders[p]
        # while x != p:
        #     self._leaders[x], x = p, self._leaders[x]
        # return p
        if self.leaders[x] != x:
            self.leaders[x] = self.find(self.leaders[x])
        return self.leaders[x]
    
    def union(self, x, y):
        p = self.find(x)
        q = self.find(y)
        if p == q: 
            return False
        if self.ranks[p] < self.ranks[q]:
            self.leaders[p] = q
        elif self.ranks[p] > self.ranks[q]:
            self.leaders[q] = p
        else:        
            self.leaders[q] = p
            self.ranks[p] += 1
        return True
    
class Solution:
    def minCostConnectPoints(self, points):
        n = len(points)
        if n == 1:
            return 0
        edges = []
        dist = lambda p0, p1: abs(p1[0] - p0[0]) + abs(p1[1] - p0[1])
        for u in range(n):
            for v in range(u + 1, n):
                w = dist(points[u], points[v])
                edges.append([u, v, w])
        res, cnt = 0, 0
        edges.sort(key=lambda x: x[2])
        uf = UnionFind(n + 1)
        for u, v, w in edges:
            if uf.union(u, v):
                res += w
                cnt += 1
            if cnt == n - 1:
                return res


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        d = [99999999] * n
        d[0] = 0
        added = set()
        ans = 0
        
        for i in range(n):
            j_min = -1
            d_min = 99999999
            for j in range(n):
                if j not in added:
                    if d[j] < d_min:
                        j_min = j
                        d_min = d[j]
            added.add(j_min)
            ans += d_min
            
            for k in range(n):
                if k not in added:
                    if abs(points[k][0] - points[j_min][0]) + abs(points[k][1] - points[j_min][1]) < d[k]:
                        d[k] = abs(points[k][0] - points[j_min][0]) + abs(points[k][1] - points[j_min][1])
            
        return ans

from heapq import heappush, heappop
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        g = defaultdict(lambda: {}); n = len(points)
        for i in range(n-1):
            x1, y1 = points[i][0], points[i][1]
            for j in range(i+1, n):
                x2, y2 = points[j][0], points[j][1]
                val = abs(x2-x1) + abs(y2-y1)
                g[i][j] = g[j][i] = val

                
        visited = set(); res = 0; q = []; cnt=0
        heappush(q, (0, 0)) # u:0, cost:0
        while q:
            cost, u = heappop(q)
            if u in visited: continue
            res += cost
            cnt += 1
            for v, w in g[u].items():
                heappush(q, (w, v))
            visited.add(u)
            if cnt >= n: break
        return res
        
        
    
\"\"\"
[[0,0],[2,2],[3,10],[5,2],[7,0]]
[[3,12],[-2,5],[-4,1]]
[[0,0],[1,1],[1,0],[-1,1]]
[[-1000000,-1000000],[1000000,1000000]]
[[0,0]]
\"\"\"            

#Prim's algorithm
from collections import defaultdict
from heapq import *
class Solution:
    def minCostConnectPoints(self, points):
        graph = defaultdict(list)
        n = len(points)
        dist = lambda p0, p1: abs(p1[0] - p0[0]) + abs(p1[1] - p0[1])
        for u in range(n):
            for v in range(u + 1, n):
                w = dist(points[u], points[v])
                graph[u].append((v, w))
                graph[v].append((u, w))
        q = [(0, 0)]
        visited = set()
        res = 0
        while q:
            d, u = heappop(q)
            if u in visited:
                continue
            visited.add(u)
            res = res + d
            if len(visited) == n:
                return res
            for v, w in graph[u]:
                if v not in visited:
                    heappush(q, (w, v))

import heapq

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def manhattan(x, y):
            return abs(x[0]-y[0]) + abs(x[1]-y[1])
        
        res, n = 0, len(points)
        seen = set()
        vertices = [(0, (0, 0))]
        
        while len(seen) < n:
            d, (u, v) = heapq.heappop(vertices)            
            if u in seen and v in seen: continue
            res += d
            seen.add(v)
            for j in range(n):
                if j not in seen and j != v:
                    heapq.heappush(vertices, (manhattan(points[j], points[v]), (v, j)))
                    
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n == 1:
            return 0
        edges = []
        for i in range(n):
            for j in range(i + 1, n):
                dis = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((dis, i, j))
        
        UF = {i: i for i in range(n)}
        def find(i):
            if i != UF[i]:
                UF[i] = find(UF[i])
            return UF[i]
        def union(i, j):
            UF[find(i)] = find(j)
            
        ans = 0
        for w, x, y in sorted(edges):
            if find(x) != find(y):
                ans += w
                union(x, y)
        return ans

import sys

class Solution:
    def manhattan(self,p1, p2):
        cost = abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        return cost
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) == 1:
            return 0
        total_cost = 0
        connected = []
        edges = []
        for i in range(len(points)):
            connected.append(set([i]))
        if len(points) == 1:
            return 0
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                edges.append([i, j, self.manhattan(points[i], points[j])])
        edges = sorted(edges, key = lambda i: i[2])
        edge_counter = 0
        while len(connected) > 1:
                edge = edges[edge_counter]
                edge_counter+=1
                cycle = False
                for tree in connected:
                    if edge[0] in tree and edge[1] in tree:
                        cycle = True
                        break
                if cycle == True:
                    continue
                else:
                    set1 = None
                    index1 = None
                    set2 = None
                    index2 = None
                    for i in range(len(connected)):
                        sets = connected[i]
                        if not set1 and edge[0] in sets:
                            set1 = sets
                            index1 = i
                        if not set2 and edge[1] in sets:
                            set2 = sets
                            index2 = i
                        if set1 and set2:
                            break
                    connected.append(set1.union(set2))
                    del connected[max(index1, index2)]
                    del connected[min(index1,index2)]
                    total_cost += edge[2]
        return total_cost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        #prims
        def manhattan(p1, p2):
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])

        g = collections.defaultdict(list)
        n = len(points)
        #create graph
        for i in range(n):
            for j in range(n):
                if i != j:
                    g[i].append((manhattan(points[i], points[j]), j))

        heap = [(0,0)]
        ans = 0
        visited = set()
        while heap and len(visited) < n:
            weight, to = heapq.heappop(heap)
            if to in visited:
                continue
            ans += weight
            visited.add(to)

            for cost, nei in g[to]:
                if nei not in visited:
                    heapq.heappush(heap, (cost, nei))

        return ans

from heapq import *
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        dist = []
        for i in range(len(points)):dist.append([])
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                d = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                dist[i].append((d, i, j))
                dist[j].append((d, j, i))
                
        visited = [False]*len(points)
        hq = []
        for x in dist[0]:
            heappush(hq, x)
        visited[0] = True
        cost = 0
        print(hq)
        while not all(visited):
            d, i, j = heappop(hq)
            if visited[i] and visited[j]:
                continue
            
            if visited[i]==False:
                ind = i
            else:
                ind = j
            
            visited[ind] = True
            cost+=d
            for x in dist[ind]:
                if visited[x[1]]==False or visited[x[2]]==False:
                    heappush(hq, x)
        return cost

# int minCostConnectPoints(vector<vector<int>>& ps) {
#     int n = ps.size(), res = 0, i = 0, connected = 0;
#     vector<bool> visited(n);
#     priority_queue<pair<int, int>> pq;
#     while (++connected < n) {
#         visited[i] = true;
#         for (int j = 0; j < n; ++j)
#             if (!visited[j])
#                 pq.push({-(abs(ps[i][0] - ps[j][0]) + abs(ps[i][1] - ps[j][1])), j});
#         while (visited[pq.top().second])
#             pq.pop();
#         res -= pq.top().first;
#         i = pq.top().second;
#         pq.pop();
#     }
#     return res;
# }

class Solution:
    def minCostConnectPoints(self, a: List[List[int]]) -> int:                        
        n, vis, ans, pq, i = len(a), set([0]), 0, [], 0
        while len(vis) < n:            
            for j in range(n):
                if j not in vis:
                    heappush(pq, (abs(a[i][0]-a[j][0]) + abs(a[i][1] - a[j][1]), j))
            while pq[0][1] in vis: heappop(pq)
            val, i = heappop(pq)
            vis.add(i)
            ans += val            
        return ans                                            

class UnionFind:
    def __init__(self, n):
        self.parents = [i for i in range(n)]
        self.size = [1] * n

    def find(self, i):
        while i != self.parents[i]:
            self.parents[i] = self.parents[self.parents[i]] # path halving
            i = self.parents[i]
        return i
    
    def union(self, a, b):
        aPar = self.find(a)
        bPar = self.find(b)
        
        if aPar == bPar:
            return False
        
        # union by size
        if self.size[aPar] > self.size[bPar]:
            self.parents[bPar] = aPar
            self.size[aPar] += self.size[bPar]
        else:
            self.parents[aPar] = bPar
            self.size[bPar] += self.size[aPar]
        
        return True
    
    def getSize(self, a):
        return self.size[self.find(a)]

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def getDistance(a,b):
            return abs(a[0] - b[0]) + abs(a[1] - b[1])
        
        N = len(points)
        uf = UnionFind(N)
        edges = []
        
        for i in range(N):
            for j in range(i+1, N):
                edges.append((getDistance(points[i], points[j]), i, j))
                
        edges.sort()
        
        cost = 0
        i = 0
        while uf.getSize(0) != N:
            w, a, b = edges[i]
            if uf.union(a,b):
                cost += w
            i += 1
        
        return cost


import heapq
class Solution:
    def minCostConnectPoints_Prim(self, points: List[List[int]]) -> int:
        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        n, c = len(points), collections.defaultdict(list)
        for i in range(n):
            for j in range(i+1, n):
                d = manhattan(points[i], points[j])
                c[i].append((d, j))
                c[j].append((d, i))
        visited = set()
        visited.add(0)
        res = 0
        heap = c[0]
        
        heapq.heapify(heap)

        while len(visited)<n:
            d, j = heapq.heappop(heap)
            if j not in visited:
                visited.add(j)
                res += d
                for record in c[j]:
                    heapq.heappush(heap,record)
                    
        return res
    
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        n = len(points)
        edges = []
        for i in range(n):
            for j in range(i+1, n):
                edges.append((manhattan(points[i], points[j]), i, j))
        edges.sort()
        res = 0
        ds = DisjointSet(n)
        for cost, u, v in edges:
            if ds.find(u) != ds.find(v):
                ds.union(u,v)
                res += cost
        return res
class DisjointSet:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [1 for _ in range(n)]
    def union(self, a, b):
        pa = self.find(a)
        pb = self.find(b)
        if pa==pb:
            return
        if self.rank[pa] > self.rank[pb]:
            self.parent[pb] = pa
            self.rank[pa] += self.rank[pb]
        else:
            self.parent[pa] = pb
            self.rank[pb] += self.rank[pa] 
    def find(self, p):
        if self.parent[p] == p:
            return p
        self.parent[p] = self.find(self.parent[p])
        return self.parent[p]

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def heap_pop(h):
            res=h[0]
            h[0]=h[-1]
            h.pop()
            current=0
            while(2*current+1<len(h)):
                child=2*current+1
                if child+1<len(h):
                    if h[child+1][0]<h[child][0]:
                        child+=1
                if h[current][0]<=h[child][0]:
                    break
                h[current],h[child]=h[child],h[current]
                current=child
            return res
        
        def heap_insert(h,val):
            current=len(h)
            h.append(val)
            while(current>0):
                p=(current-1)//2
                if h[p][0]<=h[current][0]:
                    break
                h[p],h[current]=h[current],h[p]
                current=p
                
        n=len(points)
        dp=[[0 for i in range(n)] for j in range(n)]
        for i in range(n):
            for j in range(n):
                dp[i][j]=abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
        visited=[0 for i in range(n)]
        visited[0]=1
        res=0
        heap=[(dp[0][j],0,j) for j in range(n)]
        heap.sort()
        heap.pop(0)
        while(sum(visited)<n):
            cost,_,current=heap_pop(heap)
            if visited[current]==1:
                continue
            visited[current]=1
            res+=cost
            for j in range(n):
                if visited[j]!=1 and j!=current:
                    heap_insert(heap,(dp[current][j],current,j))
        return res

class DisjointSet:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [1 for _ in range(n)]
    
    # make a and b part of the same component
    # union by rank optimization
    def union(self, a, b):
        pa = self.find(a)
        pb = self.find(b)
        if pa == pb: return
        if self.rank[pa] > self.rank[pb]:
            self.parent[pb] = pa
            self.rank[pa] += self.rank[pb]
        else:
            self.parent[pa] = pb
            self.rank[pb] += self.rank[pa]
    
    # find the representative of the 
    # path compression optimization
    def find(self, a):
        if self.parent[a] == a:
            return a
        
        self.parent[a] = self.find(self.parent[a])
        return self.parent[a]
    

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        n = len(points)
        edges = []
        for i in range(n):
            for j in range(i+1, n):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((dist, i, j))
        
        # sort based on cost (i.e. distance)
        edges.sort()
        
        # using Kruskal's algorithm to find the cost of Minimum Spanning Tree
        res = 0
        ds = DisjointSet(n)
        for cost, u, v in edges:
            if ds.find(u) != ds.find(v):
                ds.union(u, v)
                res += cost
        
        return res
# class DSU:
#     def __init__(self,n):
#         self.parent = [i for i in range(n)]
#         self.rank = [1 for i in range(n)]
#         self.count = n
    
#     def find(self,x):
#         if x!=self.parent[x]:
#             self.parent[x]=self.find(self.parent[x])
#         return self.parent[x]
    
#     def union(self,x,y):
#         px = self.find(x)
#         py = self.find(y)
#         if px==py:
#             return False
#         self.count-=1
#         if self.rank[x]>self.rank[y]:
#             self.parent[py]=px
#             self.rank[px]+=self.rank[py]
#         else:
#             self.parent[px]=py
#             self.rank[py]+=self.rank[px]
#         return True
                
# class Solution:
#     def minCostConnectPoints(self, points: List[List[int]]) -> int:
#         n = len(points)
#         edges = []
#         for i in range(n):
#             for j in range(i+1, n):
#                 dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
#                 edges.append((dist, i, j))
#         heapq.heapify(edges)
#         res = 0
#         ds = DSU(n)
#         while edges and ds.count!=1:
#             cost,u,v = heapq.heappop(edges)
#             if ds.union(u,v):
#                 res += cost
#         return res


from collections import defaultdict
from heapq import *
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        edges = []
        for i, (x, y) in enumerate(points):
            for j, (h, k) in enumerate(points):
                if j <= i:
                    continue
                d = abs(x-h)+abs(y-k)
                edges.append((i, j, d))
        
        g = defaultdict(list)
        for e in edges:
            g[e[0]].append((e[1], e[2]))
            g[e[1]].append((e[0], e[2]))

        q = []
        cost = 0
        seen = set()
        heappush(q, (0, 0))
        for _ in range(n):
            while True:
                w, u = heappop(q)
                if u in seen: continue  
                cost += w
                seen.add(u)
                for v, w in g[u]:
                    if v in seen: continue
                    heappush(q, (w, v))
                break           
        return cost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        edges = []
\t\t
        for i in range(n):
            for j in range(i+1, n):
                d = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((d, i, j))
        
        edges.sort()
        
        roots = [i for i in range(n)]
        
        def find(v):
            if roots[v] != v:
                roots[v] = find(roots[v])
            return roots[v]
        
        def union(u, v):
            p1 = find(u); p2 = find(v)
            if p1 != p2:
                roots[p2] = roots[p1]
                return True
            return False
        
        res = 0
        for d, u, v in edges:
            if union(u, v):
                res += d
        return res
        
        

class Solution:
\tdef minCostConnectPoints(self, points: List[List[int]]) -> int:
\t\tfrom    itertools   import  combinations
\t\tParent\t\t= {}
\t\tRank\t\t= {}
\t\tVertices\t= list(range(len(points)))
\t\tEdges\t\t= []

\t\tdef\tMakeGraph():
\t\t\tnonlocal\tpoints, Parent, Rank, Vertices, Edges
\t\t\tCombi\t= list(combinations(Vertices, 2))
\t\t\t
\t\t\tfor pair in Combi:
\t\t\t\tu, v\t= pair
\t\t\t\tnDist\t=\tabs(points[u][0] - points[v][0]) \\
\t\t\t\t\t+ abs(points[u][1] - points[v][1])
\t\t\t\tEdges.append((nDist, u, v))
\t\t\tEdges.sort()

\t\tdef MakeSet(v):
\t\t\tnonlocal\tParent, Rank
\t\t\tParent[v]\t= v
\t\t\tRank[v]\t\t= 0

\t\tdef FindRoot(v):
\t\t\tnonlocal\tParent
\t\t\tif Parent[v] != v:
\t\t\t\tParent[v] = FindRoot(Parent[v])

\t\t\treturn Parent[v]

\t\tdef Union(u, v):
\t\t\troot1 = FindRoot(v)
\t\t\troot2 = FindRoot(u)

\t\t\tif root1 != root2:
\t\t\t\t# 짧은 트리의 루트가 긴 트리의 루트를 가리키게 만드는 것이 좋다.
\t\t\t\tif Rank[root1] > Rank[root2]:
\t\t\t\t\tParent[root2] = root1
\t\t\t\telse:
\t\t\t\t\tParent[root1] = root2

\t\t\t\t\tif Rank[root1] == Rank[root2]:
\t\t\t\t\t\tRank[root2] += 1

\t\tMakeGraph()
\t\tfor v in Vertices:
\t\t\tMakeSet(v)

\t\tnMinCost\t= 0
\t\tfor Edge in Edges:
\t\t\tnCost, u, v\t= Edge
\t\t\tif FindRoot(u) != FindRoot(v):
\t\t\t\tUnion(u, v)
\t\t\t\tnMinCost\t+= nCost
\t\t
\t\treturn  nMinCost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points)<=1:
            return 0
        prior=[[] for _ in points]
        for i in range(len(points)):
            for j in range(i+1,len(points)):
                dist=abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                prior[i].append((dist,j))
                prior[j].append((dist,i))
        heapify(prior[0])
        seen=set([0])
        cur=prior[0]
        res=0
        while len(seen)<len(points):
            dist,tar=heappop(cur)
            if tar not in seen:
                res+=dist
                seen.add(tar)
                for d,t in prior[tar]:
                    if t not in seen:
                        heappush(cur,(d,t))
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        nodes = len(points)
        edges = sorted(
            [(abs(points[src][0] - points[dst][0]) + abs(points[src][1] - points[dst][1]), src, dst) for src in
             range(nodes) for dst in range(src + 1, nodes)])

        roots = [node for node in range(nodes)]

        def find(v):
            if roots[v] != v:
                roots[v] = find(roots[v])
            return roots[v]

        def union(u, v):
            p1, p2 = find(u), find(v)
            if p1 != p2:
                roots[p2] = roots[p1]
                return True
            return False

        return sum(distance for distance, src, dst in edges if union(src, dst))

class DSU():
    
    def __init__(self,n):
        self.parent=list(range(n))
        self.size=[1]*n
    
    def find(self,x):
        if x!=self.parent[x]:
            self.parent[x]=self.find(self.parent[x])
        return self.parent[x]
    
    def union(self,x,y):
        xp,yp=self.find(x),self.find(y)
        if xp==yp:
            return False
        if self.size[xp]<self.size[yp]:
            xp,yp=yp,xp
        
        self.size[xp]+=self.size[yp]
        self.parent[yp]=xp
        return True
    


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        dsu=DSU(len(points))
        ans=0
        edges=[]
        for i,(xi,yi) in enumerate(points):
            for j in range(i+1,len(points)):
                xj,yj=points[j]
                edges.append((abs(xi-xj)+abs(yi-yj),i,j))
        
        edges.sort()
        ans=0
        for d,v1,v2 in edges:
            # print(v1,v2,'a')
            if dsu.find(v1)!=dsu.find(v2):
                # print(v1,v2,'j')
                ans+=d
                dsu.union(v1,v2)
        
        # print(dsu.parent)
        return ans
                


class Solution:
    def minCostConnectPoints(self, points):
        N = len(points)
        dist = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        connections = [[u, v, dist(points[u], points[v])] for u in range(N-1) for v in range(u+1, N)]
        connections.sort(key = lambda x:x[2])
        parent, cnt, res = [i for i in range(N+1)], N-1, 0
        def find(v):
            while parent[v] != parent[parent[v]]:
                parent[v] = parent[parent[v]]
            return parent[v]
        for u, v, cost in connections:
            pu, pv = find(u), find(v)
            if pu != pv:
                parent[pu] = pv
                cnt -= 1
                res += cost
                if cnt == 0:
                    break
        return res
    
class Solution:
    def minCostConnectPoints(self, points):
        distance = lambda p1, p2: abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        points.sort(key = lambda p: p[0] + p[1])   # points.sort(key = lambda p: abs(p[0]) + abs(p[1]))
        total_cost = 0
        points = [[p, distance(p, points[0])] for p in points]
        while points:
            minIdx, mindist = None, float('inf')
            for i, (p1, dist) in enumerate(points):
                if dist < mindist:
                    minIdx, mindist = i, dist
            p1, cost = points.pop(minIdx)
            total_cost += cost
            for i, (p2, dist) in enumerate(points):
                # points[i][1] = min(points[i][1], distance(p1, p2))
                newdist = distance(p1, p2)
                if newdist < dist:
                    points[i][1] = newdist
        return total_cost

class Solution:
    class Union:
        def __init__(self):
            self.collection = {}
        
        def get_head(self, i):
            if i not in self.collection:
                return -1, 1
            while i in self.collection and self.collection[i][0] != i:
                i = self.collection[i][0]
            return self.collection[i]
                
        def add(self, i, j):
            head_i, cnt_i = self.get_head(i)
            head_j, cnt_j = self.get_head(j)
            
            if head_i == head_j and head_i != -1:
                return False, cnt_i
            
            head = head_i if cnt_i >= cnt_j else head_j
            cnt = cnt_i + cnt_j
            if head == -1:
                head = i

            self.collection[head_i] = (head, cnt)
            self.collection[head_j] = (head, cnt)
            self.collection[i] = (head, cnt)
            self.collection[j] = (head, cnt)
            return True, cnt
            
    from heapq import heappush, heappop
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        heap = []
        union = Solution.Union()
        total = 0
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                val = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                heappush(heap, (val, i, j))
                
        while heap:
            val, i, j = heappop(heap)
            added, cnt = union.add(i, j)
            if added:
                total += val
            if cnt == len(points):
                break
            
        return total

def top(idx, i):
    d, j = 0, idx[i]
    while i != j: i, j, d = j, idx[j], d + 1
    return j, d
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        best, idx = 0, { i: i for i in range(len(points)) }
        buf = [ (abs(x1 - x2) + abs(y1 - y2), i1, i2)
              for i1,(x1,y1) in enumerate(points[:-1])
              for i2,(x2,y2) in enumerate(points[i1+1:], i1+1) ]
        for now,i1,i2 in sorted(buf):
            j1, d1 = top(idx, i1)
            j2, d2 = top(idx, i2)
            if j1 == j2: continue
            best += now
            if d1 < d2: idx[i1] = idx[i2] = idx[j1] = j2
            else: idx[i1] = idx[i2] = idx[j2] = j1
        return best

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points)==1:
            return 0
        d=collections.defaultdict(int)
        dmn=collections.defaultdict(int)
        n=len(points)
        def distance(a,b):
            return abs(a[0]-b[0])+abs(a[1]-b[1])
        res=0
        start=[0,float(\"inf\")]
        for i in range(n):
            dmn[i]=0
            for j in range(i+1,n):
                t=distance(points[i],points[j])
                d[(i,j)]=t
                d[(j,i)]=t
                if d[(i,j)]<start[1]:
                    start[1]=d[(i,j)]
                    start[0]=(i,j)
        a=start[0][0]
        b=start[0][1]
        del dmn[a]
        del dmn[b]
        res+=start[1]
        
        for k in dmn.keys():
            dmn[k]=min(d[(k,a)],d[(k,b)])
        n-=2
        
        while n>0:
            nxDistance=float(\"inf\")
            for k in dmn.keys():
                if dmn[k]<nxDistance:
                    nx=k
                    nxDistance=dmn[k]
            res+=nxDistance
            del dmn[nx]
            for k in dmn.keys():
                dmn[k]=min(dmn[k],d[(k,nx)])
            n-=1
        return res
                        

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        graph = []
        self.parent = [i for i in range(len(points))]
        cost = 0
        self.N = len(points)
        
        for i in range(len(points)-1):
            for j in range(len(points)):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                heapq.heappush(graph, [dist, i, j])
                
        # graph = sorted(graph, key = lambda x: x[2])
        
        while self.N > 1:
            c, u, v = heapq.heappop(graph)
            if u != v and self.union(u, v):
                cost += c
                
        return cost
    
    
    def union(self, x, y):
        parentX = self.find(x)
        parentY = self.find(y)
        
        if parentX == parentY:
            return False
        
        if self.parent[parentX] <= self.parent[parentY]:
            self.parent[parentY] = parentX
        else:
            self.parent[parentX] = parentY
        self.N -= 1
        return True
    
    
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
            
        return self.parent[x]

class Solution(object):
    def minCostConnectPoints(self, points):

        g = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                g.append((i, j, abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])))
        
        g0 = sorted(g, key = lambda x: x[2])
        uf = UnionFind(len(points))
        
        ans = 0
        for x, y, z in g0:
            if uf.union(x, y):
                ans += z
        
        return ans
                         
class UnionFind():
    def __init__(self, n):
        self.parents = [i for i in range(n)]

    def find(self, x):
        if self.parents[x] == x:
            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 False

        self.parents[y] = x
        return True

import heapq
class Solution:
    def minCostConnectPoints_Prim(self, points: List[List[int]]) -> int:
        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        n, c = len(points), collections.defaultdict(list)
        for i in range(n):
            for j in range(i+1, n):
                d = manhattan(points[i], points[j])
                c[i].append((d, j))
                c[j].append((d, i))
        visited = set()
        visited.add(0)
        res = 0
        heap = c[0]
        
        heapq.heapify(heap)

        while len(visited)<n:
            d, j = heapq.heappop(heap)
            if j not in visited:
                visited.add(j)
                res += d
                for record in c[j]:
                    heapq.heappush(heap,record)
                    
        return res
    
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        n = len(points)
        edges = []
        for i in range(n):
            for j in range(i+1, n):
                edges.append((manhattan(points[i], points[j]), i, j))
        edges.sort()
        res = 0
        ds = DisjointSet(n)
        for cost, u, v in edges:
            if ds.find(u) != ds.find(v):
                ds.union(u,v)
                res += cost
        return res
class DisjointSet:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [1 for _ in range(n)]
    def union(self, a, b):
        pa = self.find(a)
        pb = self.find(b)
        if pa==pb:
            return
        self.parent[pa] = pb
        '''if self.rank[pa] > self.rank[pb]:
            self.parent[pb] = pa
            self.rank[pa] += self.rank[pb]
        else:
            self.parent[pa] = pb
            self.rank[pb] += self.rank[pa] '''
    def find(self, p):
        if self.parent[p] == p:
            return p
        self.parent[p] = self.find(self.parent[p])
        return self.parent[p]

class DSU:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [0 for _ in range(n)]
        self.size = n
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    def union(self, x, y):
        xp, yp = self.find(x), self.find(y)
        if xp == yp:
            return False
        if self.rank[xp] < self.rank[yp]:
            self.parent[xp] = yp
        elif self.rank[xp] > self.rank[yp]:
            self.parent[yp] = xp
        else:
            self.parent[xp] = yp
            self.rank[yp] += 1
        self.size -= 1
        return True
    def getSize(self):
        return self.size
    
class Solution:
    import heapq
    
    # prime + heap, not using unionfind.
    # https://leetcode.com/problems/min-cost-to-connect-all-points/discuss/850185/Java-or-Min-Spanning-Tree-or-Prim-%2B-PriorityQueue
    def minCostConnectPoints1(self, points: List[List[int]]) -> int:
        def getDist(i, j):
            return abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
        heap, n, visited, res = [], len(points), set([0]), 0
        for i in range(1, n):
            heapq.heappush(heap, (getDist(0, i), (0, i)))
        while len(visited) < n:
            dist, (i, j) = heapq.heappop(heap)
            if j not in visited:
                visited.add(j)
                res += dist
                for k in range(n):
                    if k not in visited:
                        heapq.heappush(heap, (getDist(j, k), (j, k)))
        return res
    
    # slow
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        graph = []
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                graph.append((i, j, abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])))
        graph.sort(key = lambda x:x[2])
        dsu = DSU(len(points) + 1)
        res = 0
        for i, j, cost in graph:
            if dsu.union(i, j):
                res += cost
        return res

def dist(p1, p2):
    return int(abs(p1[0] - p2[0]) + abs(p1[1] - p2[1]))

def find(x, uf):
    if uf[x] == x:
        return x
    uf[x] = find(uf[x], uf)
    return uf[x]

def union(x, y, uf):
    xx = find(x, uf)
    yy = find(y, uf)
    if xx == yy:
        return False
    uf[xx] = yy
    return True

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        edges = []
        for i in range(n):
            for j in range(i + 1, n):
                edges.append((dist(points[i], points[j]), i, j))
        edges.sort()
        uf = list(range(n))
        ans = 0
        for e in edges:
            if union(e[1], e[2], uf):
                ans += e[0]
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # my gut said a kruskal MST? YES

        N = len(points)
        edge_list = [];
        for i in range(N):
            x0,y0 = points[i]
            for j in range(i+1,N):
                x1,y1 = points[j]
                mh = abs(x1-x0)+abs(y1-y0);
                edge_list.append((mh, i,j));
        edge_list.sort()
        #print(edge_list)
        
        ## implement kruskal
        edge_count = 0;
        val = 0;
        uf = UnionFind(N)

        while(edge_count!=N-1):
            mh,i,j = edge_list.pop(0)

            if(uf.union(i,j)):
                ## we're good
                val+=mh;
                edge_count+=1;
            #print(edge_count, val, x0,y0, x1, y1)

        return val
    
class UnionFind():
    def __init__(self, n):
        self.parents = {i:i for i in range(0, n)}
        self.groups = n

    def find(self, x):
        if self.parents[x] == x:
            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 False

        self.parents[y] = x
        self.groups -= 1
        return True

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # a = points
        # n = len(a)
        # def d(i, j): return abs(a[i][0]-a[j][0]) + abs(a[i][1]-a[j][1])
        # q = []
        # dst = [float('inf')]*n
        # vis = [False] * n
        # def consider(du, u):
        #     if vis[u] or du >= dst[u]: return
        #     dst[u] = du
        #     heappush(q, (du, u))
        # consider(0, 0)
        # while q:
        #     du, u = heappop(q)
        #     if vis[u]: continue
        #     vis[u] = True
        #     for v in range(n): consider(d(u, v), v)
        # return sum(dst)
        
        n = len(points)
        edges = []
        for i in range(n):
            for j in range(i+1,n):
                d = abs(points[i][0] - points[j][0]) + abs(points[i][1]-points[j][1])
                edges.append((d,i,j))
        edges.sort()
        
        roots = [i for i in range(n)]
        
        def find(v):
            if roots[v] != v:
                roots[v] = find(roots[v])
            return roots[v]
        
        def union(u,v):
            p1 = find(u)
            p2 = find(v)
            if p1 != p2:
                roots[p2] = roots[p1]
                return True
            return False
        
        res = 0
        for d,u,v in edges:
            if union(u,v):
                res += d
        return res


class DisjointSet:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [0 for _ in range(n)]
    
    # make a and b part of the same component
    # union by rank optimization
    def union(self, a, b):
        pa = self.find(a)
        pb = self.find(b)
        if pa == pb: return
        if self.rank[pa] > self.rank[pb]:
            self.parent[pb] = pa
            self.rank[pa] += self.rank[pb]
        else:
            self.parent[pa] = pb
            self.rank[pb] += self.rank[pa]
    
    # find the representative of the 
    # path compression optimization
    def find(self, a):
        if self.parent[a] == a:
            return a
        
        self.parent[a] = self.find(self.parent[a])
        return self.parent[a]
    

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        n = len(points)
        edges = []
        for i in range(n):
            for j in range(i+1, n):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((dist, i, j))
        
        # sort based on cost (i.e. distance)
        edges.sort()
        
        # using Kruskal's algorithm to find the cost of Minimum Spanning Tree
        res = 0
        ds = DisjointSet(n)
        for cost, u, v in edges:
            if ds.find(u) != ds.find(v):
                ds.union(u, v)
                res += cost
        
        return res


class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:
        class DSU:
            def __init__(self, n):
                self.parent = list(range(n))
                self.size = [1] * n
            
            def find(self, x):
                if self.parent[x] != x:
                    self.parent[x] = self.find(self.parent[x])
                return self.parent[x]
            
            def unite(self, x, y):
                px, py = self.find(x), self.find(y)
                if px == py:
                    return False
                if self.size[px] > self.size[py]:
                    px, py = py, px
                self.size[py] += self.size[px]
                self.parent[px] = py
                return True
        n = len(p)
        total = 0
        dsu = DSU(n)
        edges = []
        for x in range(1, n):
            for y in range(x):
                edges.append((x, y, abs(p[x][0] - p[y][0]) + abs(p[x][1] - p[y][1])))
        edges.sort(key=lambda x: x[2])
        for x, y, cost in edges:
            if dsu.unite(x, y):
                total += cost
        return total

from collections import defaultdict


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def calc_distance(p1, p2):
            x1, y1 = p1
            x2, y2 = p2
            return abs(x1 - x2) + abs(y1 - y2)
        
        def find_best_node(min_dists, mst_set):
            min_dist = float('inf')
            for i, dist in enumerate(min_dists):
                if i not in mst_set and dist < min_dist:
                    best_node = i
                    min_dist = dist
            return best_node, min_dist
        
        def update_min_dists(node, min_dists, graph):
            for i, dist in graph[node]:
                min_dists[i] = min(min_dists[i], dist)            
        
        
        n = len(points)
        if n <= 1:
            return 0
        
        graph = defaultdict(list)
        for i in range(n):
            for j in range(i+1, n):
                p1, p2 = points[i], points[j]
                dist = calc_distance(p1, p2)
                graph[i].append((j, dist))
                graph[j].append((i, dist))
                
        min_dists = [float('inf') for _ in range(n)]
        mst_set = {0}
        for i, dist in graph[0]:
            min_dists[i] = min(min_dists[i], dist)
        
        total_dist = 0
        for _ in range(n-1):
            best_node, min_dist = find_best_node(min_dists, mst_set)
            mst_set.add(best_node)
            update_min_dists(best_node, min_dists, graph)
            total_dist += min_dist
        
        return total_dist
            
            
            
        
        
        
        
            
        
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def find(a):
            if a != root[a]:
                root[a] = find(root[a])
            return root[a]
        def union(a, b):
            a, b = find(a), find(b)
            if a == b:
                return 0
            root[a] = b
            return 1
        root = [i for i in range(len(points))]
        res = 0
        edges = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                a, b = points[i]
                c, d = points[j]
                edges.append([abs(a-c)+abs(b-d), i, j])
        edges.sort()
        us = 0
        while us != len(points)-1:
            dis, i, j = edges.pop(0)
            if union(i, j):
                res += dis
                us += 1
        return res

class Solution:
    def minCostConnectPoints(self, A: List[List[int]]) -> int:
        N = len(A)
        P = [i for i in range(N)]                     
        E = []
        for u in range(N):
            x1, y1 = A[u]
            for v in range(u + 1, N):
                x2, y2 = A[v]
                w = abs(x1 - x2) + abs(y1 - y2)
                E.append([ u, v, w ])                   
        E.sort(key = lambda edge: edge[2])              
        def find(x):
            P[x] = P[x] if P[x] == x else find(P[x])
            return P[x]
        def union(a, b):
            a = find(a)
            b = find(b)
            if a == b:
                return False
            P[a] = b                                    
            return True
        return sum([w for u, v, w in E if union(u, v)])

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) == 1:
            return 0
        
        def distance(p1,p2):
            return abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        n = len(points)
        parents = list(range(n))
        
        def find(x):
            if x != parents[x]:
                parents[x] = find(parents[x])
            return parents[x]
        
        def union(x,y):
            px, py = find(x), find(y)
            if px != py:
                parents[py] = px
                return True
            return False
        ans = 0
        # visited = set()#
        count = 0
        g = []
        for i in range(n):
            for j in range(i+1,n):
                cost = distance(points[i],points[j])
                g.append([cost,i,j])
        for cost,pt1,pt2 in sorted(g):
            if union(pt1,pt2):
                ans += cost
                count +=1
                # visited.add(pt1)
                # visited.add(pt2)
            if count == n-1:
                return ans


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # APPROACH 1 - My Kruskal trial
        \"\"\"
        sets, edges = [], []
        res = []

        for i in range(len(points)):
            sets.append([i])
        
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                val = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((i,j,val))
        def custom_sort(t):
            return t[2]
        edges.sort(key=custom_sort)
        #print(edges); print(sets)
        
        for (u,v,cost) in edges:
            for i in range(len(sets)):
                if u in sets[i]:
                    setu = i
                    break
            for i in range(len(sets)):
                if v in sets[i]:
                    setv = i
                    break
            if setu != setv:
                w1 = sets[setu]
                w2 = sets[setv]
                res.append((u,v,cost))
                [w1.append(x) for x in w2 if x not in w1]
                sets = sets[:setv]+sets[setv+1:]
        
        sum = 0
        for e in res:
            sum += e[2]
        return sum
        \"\"\"
        
        # APPRTOACH 2 - MIN_HEAP/Prim
        \"\"\"
        edges = [[None] * len(points) for _ in range(len(points))]
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                val = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges[i][j] = val
                edges[j][i] = val
        
        cost = 0
        min_heap = [(0, 0)]
        visited = set()
        while len(min_heap):
            #print('cur_min_heap', min_heap)
            min_node = heapq.heappop(min_heap)
            if min_node[1] in visited: continue
            vertex = min_node[1]
            weight = min_node[0]
            cost += weight
            visited.add(vertex)
            #print('visted vertex is', vertex, '; cost is', weight, '; total', cost, '; cur_min_heap', min_heap)
            for neigh in range(len(edges[vertex])):
                if neigh not in visited:
                    heapq.heappush(min_heap, (edges[vertex][neigh], neigh))
        
        return cost
        \"\"\"
        
        #APPROACH 3 - Prim
        ##### https://leetcode.com/problems/min-cost-to-connect-all-points/discuss/854251/Python-Kruskals-algo-implemented-with-array-easy-to-understand
        visited = []
        l = len(points)
\t\t# points are node in graph, and there're at most l^2 edges.
        edges = []
\t\t# Get all the edges, and each is represented with [cost, two_ends]
        for i in range(l):
            for j in range(i+1, l):
                x = abs(points[i][0] - points[j][0])
                y = abs(points[i][1] - points[j][1])
                edges.append([x + y, [i,j]])
\t\t# Sort the edges by their cost
        edges.sort(key = lambda x:x[0])
        result = 0
        nodes = [0]* l
\t\t# union connected nodes,  mark the node with mark = 1, and for each separated group, we use mark = 2 /3 ...
        mark = 1
        for e in edges:
\t\t   # Two end nodes
            i = e[1][0]
            j = e[1][1]
\t\t\t# Both are not marked, so are not connected at all, and can be marked with new mark
            if nodes[i] == 0 and nodes[j] == 0:
                
                nodes[i] = mark
                nodes[j] = mark
                mark += 1
                result += e[0]
\t\t\t# One of them is marked, so connected to some connected components
            elif nodes[i] == 0:
                nodes[i] = nodes[j]
                result += e[0]
\t\t\t# One of them is marked, so connected to some connected components
            elif nodes[j] == 0:
                nodes[j] = nodes[i]
                result += e[0]
\t\t\t# Both of them are marked, so are already connected to some connected components;
\t\t\t# if they are in the same connected component, this edge cannot be added; Or there'd be a cycle
\t\t\t# If they are in different c.c., they should be united, so we need to update the mark on the nodes. And the method is to loop all the nodes, change the mark for all the nodes in one c.c. to the mark of the other c.c.
            else:
                if nodes[i] != nodes[j]:
                    result += e[0]
                    target = nodes[i]
                    source = nodes[j]
                    for index in range(l):
                        if nodes[index] == source:
                            nodes[index] = target
        return result
        
        

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def method1():
            class UF:
                def __init__(self,size):
                    self.p=list(range(size))
                    self.rank=[1]*size
                    
                def find(self,x):
                    if x!=self.p[x]:
                        self.p[x]=self.find(self.p[x])
                    return self.p[x]
                
                def union(self,x,y):
                    px=self.find(x)
                    py=self.find(y)
                    
                    if self.rank[px]<self.rank[py]:
                        px,py=py,px
                    
                    self.p[px]=py
                    if self.rank[px]==self.rank[py]:
                        self.rank[px]+=1
                        
                
            edges=[]
            n=len(points)
            
            for i in range(n-1):
                for j in range(i+1,n):
                    dist=abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                    edges.append((dist,i,j))
                        
            edges.sort()
        
            uf=UF(n)
            res=0
            for cost, u, v in edges:
                if uf.find(u) != uf.find(v):
                    uf.union(u, v)
                    res += cost
        
            return res
        return method1()
                    
            


class Solution:
    def minCostConnectPoints_1(self, points: List[List[int]]) -> int:
        \"\"\"
        MST - minimum spanning tree
        Greedy - each time we add the shortest edge into the tree
        Prim's Algo
        \"\"\"
        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        
        n, c = len(points), collections.defaultdict(list)
        # init
        for i in range(n):
            for j in range(i+1, n):
                d = manhattan(points[i], points[j])
                c[i].append((d, j))
                c[j].append((d, i))
        
        cnt, ans, visited, heap = 1, 0, [0] * n, c[0]
        visited[0] = 1
        heapq.heapify(heap)
        # each time we add a v from outside of the MST into the MST
        while heap:
            d, j = heapq.heappop(heap)
            if not visited[j]:
                visited[j], cnt, ans = 1, cnt+1, ans+d
                for record in c[j]:
                    heapq.heappush(heap, record)
            if cnt >= n:
                break
        
        return ans

    def minCostConnectPoints(self, p: List[List[int]]) -> int:
        
        def manhattan(x, y):
            return abs(x[0]-y[0]) + abs(x[1]-y[1])
        
        ans, n = 0, len(p)
        seen = set()
        vertices = [(0, (0, 0))]
        
        while len(seen) < n:
            # print(vertices, seen)
            w, (u, v) = heapq.heappop(vertices)            
            if u in seen and v in seen: continue
            ans += w
            seen.add(v)
            for j in range(n):
                if j not in seen and j!=v:
                    heapq.heappush(vertices, (manhattan(p[j], p[v]), (v, j)))
        
        return ans

class Solution:
    def find(self, par, x):
        if par[x] == x:
            return x
        else:
            par[x] = self.find(par, par[x])
            return par[x]

    def merge(self, par, x, y):
        x = self.find(par, x)
        y = self.find(par, y)
        if x == y:
            return False
        par[x] = y
        return True

    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        par = [i for i in range(len(points))]
        dis = lambda p1, p2: abs(p1[0]-p2[0])+abs(p1[1]-p2[1])
        edges = []
        visited = set()
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                edges.append((dis(points[i], points[j]), i, j))
        edges.sort()
        r = 0
        for d, i, j in edges:
            if self.merge(par, i, j):
                r += d
        return r

class DisjointSet:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
    
    # make a and b part of the same component
    # union by rank optimization
    def union(self, a, b):
        pa = self.find(a)
        pb = self.find(b)
        if pa == pb: return
        self.parent[pa] = pb
    
    # find the representative of the 
    # path compression optimization
    def find(self, a):
        if self.parent[a] == a:
            return a
        
        self.parent[a] = self.find(self.parent[a])
        return self.parent[a]
    

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        n = len(points)
        edges = []
        for i in range(n):
            for j in range(i+1, n):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((dist, i, j))
        
        # sort based on cost (i.e. distance)
        edges.sort()
        
        # using Kruskal's algorithm to find the cost of Minimum Spanning Tree
        res = 0
        ds = DisjointSet(n)
        for cost, u, v in edges:
            if ds.find(u) != ds.find(v):
                ds.union(u, v)
                res += cost
        
        return res

class DisjointSet:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [1 for _ in range(n)]
    
    # make a and b part of the same component
    # union by rank optimization
    def union(self, a, b):
        pa = self.find(a)
        pb = self.find(b)
        if pa == pb: return
        if self.rank[pa] > self.rank[pb]:
            self.parent[pb] = pa
            self.rank[pa] += self.rank[pb]
        else:
            self.parent[pa] = pb
            self.rank[pb] += self.rank[pa]
    
    # find the representative of the 
    # path compression optimization
    def find(self, a):
        if self.parent[a] == a:
            return a
        
        self.parent[a] = self.find(self.parent[a])
        return self.parent[a]
    

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        n = len(points)
        edges = []
        for i in range(n):
            for j in range(i+1, n):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((dist, i, j))
        
        # sort based on cost (i.e. distance)
        edges.sort()
        
        # using Kruskal's algorithm to find the cost of Minimum Spanning Tree
        res = 0
        ds = DisjointSet(n)
        for cost, u, v in edges:
            if ds.find(u) != ds.find(v):
                ds.union(u, v)
                res += cost
        
        return res

import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        l=len(points)
        stc=[]
        heapq.heapify(stc)
        cost=0
        self.parent=[-1 for i in range(l)]
        
        def find(a):
            if self.parent[a]<0:
                print(('a ',a))
                return a
            else:
                return find(self.parent[a])
        
        
        
        def union(a,b):
            u=find(a)
            v=find(b)
            if u==v:
                return False
            else:
                if abs(self.parent[u])>=abs(self.parent[v]):
                    self.parent[u]+=self.parent[v]
                    self.parent[v]=u
                else:
                    self.parent[v]+=self.parent[u]
                    self.parent[u]=v
                return True
        
        
        
        
        for i in range(l):
            for j in range(l):
                if i!=j:
                    heapq.heappush(stc,[abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1]),i,j])         
        edge=0
        while(edge<l-1):
            t=heapq.heappop(stc)
            y=union(t[1],t[2])
            if y==True:
                cost+=t[0]
                edge+=1
        return cost
                    
        
        
        
        
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def method1():
            class UF:
                def __init__(self,size):
                    self.p=list(range(size))
                    self.rank=[1]*size
                    
                def find(self,x):
                    if x!=self.p[x]:
                        self.p[x]=self.find(self.p[x])
                    return self.p[x]
                
                def union(self,x,y):
                    px=self.find(x)
                    py=self.find(y)
                    
                    if self.rank[px]<self.rank[py]:
                        px,py=py,px
                    
                    self.p[px]=py
                    if self.rank[px]==self.rank[py]:
                        self.rank[px]+=1
                        
            edges=[]
            n=len(points)
            
            for i in range(n-1):
                for j in range(i+1,n):
                    dist=abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                    edges.append((dist,i,j))
                        
            edges.sort()
        
            uf=UF(n)
            res=0
            for cost, u, v in edges:
                if uf.find(u) != uf.find(v):
                    uf.union(u, v)
                    res += cost
        
            return res
        return method1()
                    
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # https://leetcode.com/problems/min-cost-to-connect-all-points/discuss/843995/Python-3-or-Min-Spanning-Tree-or-Prim's-Algorithm
        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        n, c = len(points), collections.defaultdict(list)
        for i in range(n):
            for j in range(i+1, n):
                d = manhattan(points[i], points[j])
                c[i].append((d, j))
                c[j].append((d, i))
        cnt, ans, visited, heap = 1, 0, [0] * n, c[0]
        visited[0] = 1
        heapq.heapify(heap)
        while heap:
            d, j = heapq.heappop(heap)
            if not visited[j]:
                visited[j], cnt, ans = 1, cnt+1, ans+d
                for record in c[j]: heapq.heappush(heap, record)
            if cnt >= n: break        
        return ans

class Node:
    def __init__(self,val):
        self.val = val
        self.next = None
        self.parent = None

class Component:
    def __init__(self):
        self.length = 0
        self.head = None
        self.tail = None
        
class Solution:
    def __init__(self):
        self.ds = {}
        
    def findSet(self,key):
        if key in self.ds:
            return self.ds[key]
        node = Node(key)
        component = Component()
        node.parent = component
        component.head = node
        component.tail = node
        component.length+=1
        self.ds[key] = component
        return component
    
    def unionSet(self, c1,c2):
        if c1.length<c2.length:
            c1,c2=c2,c1
        c1.tail.next = c2.head
        c1.tail = c2.tail
        tmp = c2.head
        while tmp:
            tmp.parent = c1
            self.ds[tmp.val] = c1
            tmp = tmp.__next__
        c1.length+=c2.length
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        edges = []
        for i in range(n):
            j=i+1
            while j<n:
                edges.append((i,j,abs(abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1]))))
                j+=1
        edges.sort(key=lambda x:x[2])
        cost = 0
        for edge in edges:
            c1 = self.findSet(edge[0])
            c2 = self.findSet(edge[1])
            if c1 != c2:
                self.unionSet(c1,c2)
                cost+=edge[2]
        return cost
                


class DisjointSet:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [0 for _ in range(n)]
    
    # make a and b part of the same component
    # union by rank optimization
    def union(self, a, b):
        pa = self.find(a)
        pb = self.find(b)
        if pa == pb: return
        if self.rank[pa] > self.rank[pb]:
            self.parent[pb] = pa
            self.rank[pa] += self.rank[pb]
        else:
            self.parent[pa] = pb
            self.rank[pb] += self.rank[pa]
    
    # find the representative of the 
    # path compression optimization
    def find(self, a):
        if self.parent[a] == a:
            return a
        
        self.parent[a] = self.find(self.parent[a])
        return self.parent[a]
    

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        n = len(points)
        edges = []
        for i in range(n):
            for j in range(i+1, n):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((dist, i, j))
        
        # sort based on cost (i.e. distance)
        edges.sort()
        
        # using Kruskal's algorithm to find the cost of Minimum Spanning Tree
        res = 0
        ds = DisjointSet(n)
        for cost, u, v in edges:
            if ds.find(u) != ds.find(v):
                ds.union(u, v)
                res += cost
        
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        def distance(p1,p2):
            return abs(p1[0]-p2[0])+abs(p1[1]-p2[1])
        sets = [i for i in range(n+1)]
        def find(i):
            if i != sets[i]:
                sets[i]=find(sets[i])
            return sets[i]
        def union(x,y):
            x,y = find(x),find(y)
            if x == y: return 0
            sets[x] = y
            return 1
        edges = []
        for i in range(n):
            for j in range(i+1,n):
                edges.append([distance(points[i],points[j]),i,j])
        
        edges.sort(key=lambda x:x[0])
        weight = 0
        for w,i,j in edges:
            if union(i,j):
                weight += w
        return weight
                
                


import sys
input = sys.stdin.readline

class Unionfind:
    def __init__(self, n):
        self.par = [-1]*n
        self.rank = [1]*n
    
    def root(self, x):
        r = x
        
        while not self.par[r]<0:
            r = self.par[r]
        
        t = x
        
        while t!=r:
            tmp = t
            t = self.par[t]
            self.par[tmp] = r
        
        return r
    
    def unite(self, x, y):
        rx = self.root(x)
        ry = self.root(y)
        
        if rx==ry:
            return
        
        if self.rank[rx]<=self.rank[ry]:
            self.par[ry] += self.par[rx]
            self.par[rx] = ry
            
            if self.rank[rx]==self.rank[ry]:
                self.rank[ry] += 1
        else:
            self.par[rx] += self.par[ry]
            self.par[ry] = rx
    
    def is_same(self, x, y):
        return self.root(x)==self.root(y)
    
    def count(self, x):
        return -self.par[self.root(x)]
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        
        for i in range(len(points)):
            xi, yi = points[i]
            for j in range(i+1, len(points)):
                xj, yj = points[j]
                edges.append((abs(xi-xj)+abs(yi-yj), i, j))
        
        edges.sort()
        uf = Unionfind(len(points))
        ans = 0
        
        for w, u, v in edges:
            if not uf.is_same(u, v):
                ans += w
                uf.unite(u, v)
        
        return ans


class UF:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.size = [1 for i in range(n)]
        
    def find(self, a):
        # if a's parent is not a -> we didn't find the root of a
        while self.parent[a] != a:
            self.parent[a] = self.parent[self.parent[a]]
            a = self.parent[a]
        return a
    
    def isConnected(self, a, b):
        return self.find(a) == self.find(b)
    
    def union(self, a, b):
        parentA = self.find(a)
        parentB = self.find(b)
        if self.isConnected(a, b): 
            return
        # add the small tree to the large tree
        if self.size[parentA] > self.size[parentB]:
            self.parent[parentB] = parentA
            # update the large tree size
            self.size[parentA] += self.size[parentB]
        else:
            self.parent[parentA] = parentB
            self.size[parentB] += self.size[parentA]
        
        
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        n = len(points)
        # make edges list with the two vertices
        for i in range(n):
            for j in range(i+1, n):
                manhattanDist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((manhattanDist, i ,j))
        # sort the edges
        edges.sort()
        res = 0
        uf = UF(n)
        # starting connect the vertices from the smallest cost
        # if the two vertices have already been connected, then skip (get rid of makeing cycles)
        for cost, i, j in edges:
            if not uf.isConnected(i, j):
                uf.union(i, j)
                res += cost
        return res


class Solution:
    def minCostConnectPoints(self, points):
        N = len(points)
        dist = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        connections = [[u, v, dist(points[u], points[v])] for u in range(N-1) for v in range(u+1, N)]
        connections.sort(key = lambda x:x[2])
        parent, cnt, res = [i for i in range(N+1)], N-1, 0
        def find(v):
            while parent[v] != parent[parent[v]]:
                parent[v] = parent[parent[v]]
            return parent[v]
        for u, v, cost in connections:
            pu, pv = find(u), find(v)
            if pu != pv:
                parent[pu] = pv
                cnt -= 1
                res += cost
                if cnt == 0:
                    break
        return res
    
class Solution:
    def minCostConnectPoints(self, points):
        distance = lambda p1, p2: abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        points.sort(key = lambda p: p[0] + p[1])   # points.sort(key = lambda p: abs(p[0]) + abs(p[1]))
        total_cost = 0
        points = [[p, distance(p, points[0])] for p in points]
        while points:
            minIdx, mindist = None, float('inf')
            for i, (p1, dist) in enumerate(points):
                if dist < mindist:
                    minIdx, mindist = i, dist
            p1, cost = points.pop(minIdx)
            total_cost += cost
            for i, (p2, dist) in enumerate(points):
                points[i][1] = min(points[i][1], distance(p1, p2))
        return total_cost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        dsu = [i for i in range(n)]
        
        def get_root(id: int):
            dsu[id] = id if dsu[id] == id else get_root(dsu[id])
            return dsu[id]
        
        def unite(a: int, b: int) -> bool:
            a = get_root(a)
            b = get_root(b)
            if a == b:
                return False
            dsu[a] = b
            return True
        
        e = []
        for i in range(n):
            for j in range(i + 1, n):
                e.append([i, j, abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])])
        e.sort(key = lambda edge: edge[2])
        
        return sum([edge[2] for edge in e if unite(edge[0], edge[1])])


class DSU:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [0 for _ in range(n)]
        self.size = n
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    def union(self, x, y):
        xp, yp = self.find(x), self.find(y)
        if xp == yp:
            return False
        if self.rank[xp] < self.rank[yp]:
            self.parent[xp] = yp
        elif self.rank[xp] > self.rank[yp]:
            self.parent[yp] = xp
        else:
            self.parent[xp] = yp
            self.rank[yp] += 1
        self.size -= 1
        return True
    def getSize(self):
        return self.size
    
class Solution:
    import heapq
    
    # prime + heap, not using unionfind.
    # https://leetcode.com/problems/min-cost-to-connect-all-points/discuss/850185/Java-or-Min-Spanning-Tree-or-Prim-%2B-PriorityQueue
    def minCostConnectPoints1(self, points: List[List[int]]) -> int:
        def getDist(i, j):
            return abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
        heap, n, visited, res = [], len(points), set([0]), 0
        for i in range(1, n):
            heapq.heappush(heap, (getDist(0, i), (0, i)))
        while len(visited) < n:
            dist, (i, j) = heapq.heappop(heap)
            if j not in visited:
                visited.add(j)
                res += dist
                for k in range(n):
                    if k not in visited:
                        heapq.heappush(heap, (getDist(j, k), (j, k)))
        return res
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        graph = []
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                graph.append((i, j, abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])))
        graph.sort(key = lambda x:x[2])
        dsu = DSU(len(points) + 1)
        res = 0
        for i, j, cost in graph:
            if dsu.union(i, j):
                res += cost
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        costs = []
        ans = 0
        for i, node_x in enumerate(points):
            for j, node_y in enumerate(points):
                if i != j:
                    costs.append((abs(node_x[0] - node_y[0]) + abs(node_x[1] - node_y[1]), i, j))
        costs.sort()
        def get_fa(i):
            if fa[i] != i:
                fa[i] = get_fa(fa[i])
            return fa[i]
        fa = list(range(len(points)))
        count = 0
        for v, i, j in costs:
            if get_fa(i) != get_fa(j):
                ans += v
                fa[fa[i]] = fa[j]
                count += 1
                if count == len(points) - 1:
                    return ans
        return ans
        
            
        
        
        
        
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        edges = collections.defaultdict(dict)
        n = len(points)
        for i in range(n):
            for j in range(i):
                x1, y1 = points[i]
                x2, y2 = points[j]
                d = abs(x1-x2) + abs(y1-y2)
                edges[i][j] = d
                edges[j][i] = d
                
                
        ans = 0
        visited = set([0])
        cand = []
        for j in edges[0]:
            heapq.heappush(cand, [edges[0][j], j])
        ans = 0
        while len(visited) < n:
            d, j = heapq.heappop(cand)
            if j not in visited:
                ans += d
                visited.add(j)
                for i in edges[j]:
                    heapq.heappush(cand, [edges[j][i], i])
        return ans
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        
        if n <= 1:
            return 0
        
        edges = []
        for i, coor in enumerate(points):
            x1, y1 = coor
            for j in range(i + 1, n):
                x2, y2 = points[j]
                edges.append((abs(x1 - x2) + abs(y1 - y2), i, j))
        
        root = [i for i in range(n)]
        
        def union(p, q):
            r1, r2 = find(p), find(q)
            if r1 != r2:
                root[r1] = r2
                return False
            return True
        
        def find(p):
            if p == root[p]:
                return p
            
            root[p] = find(root[p])
            return root[p]
        
        distance = 0
        for d, p1, p2 in sorted(edges):
            if not union(p1, p2):
                distance += d
        
        return distance


from collections import defaultdict
import heapq

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def manhattan(x,y):
            return abs(x[0] - y[0]) + abs(x[1] - y[1])
        
        dist_dict = defaultdict(list)
        n_points = len(points)
        
        for i in range(n_points):
            for j in range(i+1, n_points):
                dist_curr = manhattan(points[i], points[j])
                dist_dict[i].append((dist_curr, j))
                dist_dict[j].append((dist_curr, i))
                
        total_dist = 0
        visited = [False] * n_points
        counter = 1
        dist_heap = dist_dict[0]
        heapq.heapify(dist_heap)
        visited[0] = True
        
        while dist_heap:
            dist_curr, point_curr = heapq.heappop(dist_heap)
            if not visited[point_curr]:
                visited[point_curr] = True
                for neighbor in dist_dict[point_curr]:
                    heapq.heappush(dist_heap, neighbor)
                total_dist += dist_curr
                counter += 1
            if counter >= n_points: break
         
        return total_dist
                
            
            
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        num_points = len(points)
        pairwise_dist = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                pairwise_dist.append([abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1]), i, j])

        pairwise_dist.sort(key=lambda x: x[0])
        distance = 0
        
        par = list(range(num_points))
        rank = [0]*num_points
        def find(node):
            if par[node] != node:
                par[node] = find(par[node])
            return par[node]
                
            
        def union(x, y):
            par_x = find(x)
            par_y = find(y)
            if rank[par_x] > rank[par_y]:
                par[par_y] = par_x
            elif rank[par_x] < rank[par_y]:
                par[par_x] = par_y
            else:
                par[par_x] = par_y
                rank[par_y] += 1
            
        for pair in pairwise_dist:
            if find(pair[1]) == find(pair[2]):
                continue
            
            distance += pair[0]
            union(pair[1], pair[2])
        
        return distance

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        from collections import defaultdict
        import heapq
        manhattan = lambda a, b:abs(a[0]-b[0]) + abs(a[1]-b[1])
        n, c = len(points), defaultdict(list)
        if n==0:
            return 0
        for i in range(n):
            for j in range(i+1, n):
                dis = manhattan(points[i], points[j])
                c[i].append((dis, j))
                c[j].append((dis, i))
        cnt, ans, visited, heap = 1, 0, [0]*n, c[0]
        visited[0] = 1
        heapq.heapify(heap)
        while cnt<n:
            dis, p = heapq.heappop(heap)
            if not visited[p]:
                visited[p], cnt, ans = 1, cnt+1, ans+dis
                for record in c[p]:
                    heapq.heappush(heap, record)
        return ans 

class UF(object):

    def __init__(self, size):
        # initially, each node is an independent component
        self.parent = [i for i in range(size)]
        # keep the size of each component
        self.size = [1] * (size)
        #count of the disconnected sets

    def union(self, p, q):
        rootp = self.find(p)
        rootq = self.find(q)
        if rootq == rootp:
            return
        if self.size[rootp] > self.size[rootq]:
            self.parent[rootq] = rootp
            self.size[rootp] += self.size[rootq]
        else:
            self.parent[rootp] = rootq
            self.size[rootq] += self.size[rootp]

    def connected(self,p, q):
        rootp = self.find(p)
        rootq = self.find(q)
        return rootp == rootq

    def find(self, x):
        while self.parent[x] != x:
            self.parent[x] = self.parent[self.parent[x]]
            x = self.parent[x]
        return x

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
         
        distances= []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                distance = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                distances.append((distance, i,j))
        distances.sort()
        uf = UF(len(points))
        res = 0
        for dis, u,v in distances:
            if not uf.connected(u,v):
                uf.union(u,v)
                res += dis
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        def dist(points,i,j):
            return abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
        visited = [(0,(0,0))]
        ans, n = 0, len(points)
        seen = set()
        
        while len(seen) < n:
            d,(u,v) = heappop(visited)
            if u in seen and v in seen:continue
            ans += d
            seen.add(v)
            for j in range(n):
                if j not in seen and  j != v:
                    heappush(visited, (dist(points,j,v), (v, j)))
        return ans
            


class Solution:
    class Union:
        def __init__(self, n):
            self.collection = [(i, 1) for i in range(n)]
            self.max_cnt = 0
            self.size = n
        
        def get_head(self, i):
            if self.collection[i][0] != i:
                return self.get_head(self.collection[i][0])
            return self.collection[i]
                
        def add(self, i, j):
            head_i, cnt_i = self.get_head(i)
            head_j, cnt_j = self.get_head(j)
            if head_i == head_j:
                return False, self.max_cnt == self.size
            
            head = head_i if cnt_i >= cnt_j else head_j
            cnt = cnt_i + cnt_j
            
            for x in [head_i, head_j, i, j]:
                self.collection[x] = (head, cnt)

            self.max_cnt = max(self.max_cnt, cnt)
            return True, self.max_cnt == self.size
            
    from heapq import heappush, heappop
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        heap = []
        union = Solution.Union(len(points))
        total = 0
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                val = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                heappush(heap, (val, i, j))
                
        while heap:
            val, i, j = heappop(heap)
            x, y = union.add(i, j)
            if x:
                total += val
            if y:
                break
            
        return total

from heapq import heappush, heappop
class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:
        
        def helper(i, j):
            return abs(p[j][0]-p[i][0]) + abs(p[j][1]-p[i][1])
        
        g = defaultdict(lambda: {}); n = len(p)
        for i in range(n-1):
            for j in range(i+1, n):
                g[i][j] = g[j][i] = helper(i,j)

        visited = set(); res = 0; q = []; cnt=0
        heappush(q, (0, 0)) # u:0, cost:0
        while q and len(visited) < n:
            cost, u = heappop(q)
            if u in visited: continue
            res += cost
            for v, w in g[u].items(): heappush(q, (w, v))
            visited.add(u)
        return res
        
        
    
\"\"\"
[[0,0],[2,2],[3,10],[5,2],[7,0]]
[[3,12],[-2,5],[-4,1]]
[[0,0],[1,1],[1,0],[-1,1]]
[[-1000000,-1000000],[1000000,1000000]]
[[0,0]]
\"\"\"            

class DSU:
    def __init__(self, n):
        self.p = [i for i in range(n)]
    def find(self, u):
        if self.p[u]!=u:
            self.p[u] = self.find(self.p[u])
        return self.p[u]
    def union(self, x, y):
        self.p[self.find(x)] = self.find(y)
        
from collections import defaultdict
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        edges = []
        for i in range(n):
            for j in range(i+1, n):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((dist, i, j))
        
        edges.sort()
        
        # using Kruskal's algorithm to find the cost of Minimum Spanning Tree
        res = 0
        ds = DSU(n)
        for cost, u, v in edges:
            if ds.find(u) != ds.find(v):
                ds.union(u, v)
                res += cost
        
        return res


class DSU: 
    def __init__(self, n): 
        self.p = list(range(n))
        self.r = [0] * n
    def find(self, i): 
        if self.p[i] != i:
            self.p[i] = self.find(self.p[i])
        return self.p[i]
    def union(self, i, j): 
        pi, pj = self.find(i), self.find(j)
        if pi != pj: 
            if self.r[pi] >= self.r[pj]: 
                self.p[pj] = pi
                self.r[pi] += (self.r[pi] == self.r[pj])
            else: 
                self.p[pi] = pj
            return True
        return False

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # try minimum spanning treee
        
        to_visit = set(range(1, len(points)))
        pq = [(abs(points[0][0] - points[x][0]) + abs(points[0][1] - points[x][1]), x) for x in range(1, len(points))]
        heapq.heapify(pq)
        ans = 0
        while pq:
            cost, to = heapq.heappop(pq)
            if to in to_visit:
                to_visit.remove(to)
                ans += cost
                for nei in to_visit:
                    x, y = points[nei]
                    heapq.heappush(pq, (abs(x-points[to][0]) + abs(y-points[to][1]), nei))

        return ans
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = [ (abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]), i, j) for i in range(len(points)) for j in range(i+1, len(points)) ]
        edges.sort()
        
        ans = 0
        uf = DSU(len(points))
        for cost, i, j in edges: 
            if uf.find(i) != uf.find(j): 
                uf.union(i, j)
                ans += cost
        return ans
        
                



class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        n, c = len(points), collections.defaultdict(list)
        for i in range(n):
            for j in range(i+1, n):
                d = manhattan(points[i], points[j])
                c[i].append((d, j))
                c[j].append((d, i))
        cnt, ans, visited, heap = 1, 0, [0] * n, c[0]
        visited[0] = 1
        heapq.heapify(heap)
        while heap:
            d, j = heapq.heappop(heap)
            if not visited[j]:
                visited[j], cnt, ans = 1, cnt+1, ans+d
                for record in c[j]: heapq.heappush(heap, record)
            if cnt >= n: break        
        return ans    

from heapq import heappush, heappop
class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:
        
        helper = lambda pi, pj: abs(pj[0]-pi[0]) + abs(pj[1]-pi[1])
        g = defaultdict(lambda: {}); n = len(p)
        for i in range(n-1):
            for j in range(i+1, n):
                g[i][j] = g[j][i] = helper(p[i], p[j])

        visited = set(); res = 0; pq = []
        heappush(pq, (0, 0)) # u:0, cost:0
        while pq and len(visited) < n:
            cost, u = heappop(pq)
            if u in visited: continue
            res += cost
            for v, w in g[u].items(): heappush(pq, (w, v))
            visited.add(u)
        return res
        
        
    
\"\"\"
[[0,0],[2,2],[3,10],[5,2],[7,0]]
[[3,12],[-2,5],[-4,1]]
[[0,0],[1,1],[1,0],[-1,1]]
[[-1000000,-1000000],[1000000,1000000]]
[[0,0]]
\"\"\"            

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        return self.prim(points)
    def generategraph(self, points):
        adjList = defaultdict(list)
        for p in points:
            for q in points:
                if p == q:
                    continue
                adjList[(p[0], p[1])].append(((abs(p[0]-q[0]) + abs(p[1]-q[1])),(q[0], q[1])))
        return adjList
    def prim(self, points):
        if len(points) <= 1:
            return 0
        adjList = self.generategraph(points)
        visited = set()
        minCost = 0
        
        heap =[(0, tuple(points[0]), tuple(points[0]))]
        print(heap)
        while heap and len(visited) < len(points):
            cost, u, v = heapq.heappop(heap)
            if v in visited:
                continue
            minCost += cost
            visited.add(v)
            for costNei, nei in adjList[v]:
                if nei in visited:
                    continue
                heapq.heappush(heap, (costNei, v, nei))
                
        return minCost

class Solution:
    
    def kruskal(self, n, edges):
        def find(x):
            if x != parent[x]:
                parent[x] = find(parent[x])
            return parent[x]
        def union(x, y):
            px, py = find(x), find(y)
            if px == py:
                return (False, False)
            parent[px] = py
            rank[py] += rank[px] 
            return (True, True) if rank[py] == n else (True, False)
        mst_cost = 0
        parent = list(range(n))
        rank = [0] * n
        for f, t, w in edges:
            isUnion, isEnd = union(f, t)
            if isUnion:
                mst_cost += w
            if isEnd:
                break
        return mst_cost
        
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        manhattan = lambda xx, yy: abs(xx[0] - yy[0]) + abs(xx[1] - yy[1])
        
        if (n := len(points)) == 1:
            return 0
        
        edges = []
        for i in range(n):
            for j in range(i + 1, n):
                x, y = points[i], points[j]
                edges.append([i, j, manhattan(x, y)])
        edges.sort(key = lambda x: x[2])
        return self.kruskal(n, edges)
        
        # graph = collections.defaultdict(list)
        # for i in range(n):
        #     for j in range(i + 1, n):
        #         x, y = points[i], points[j]
        #         graph[i].append((manhattan(x, y), j))
        #         graph[j].append((manhattan(x, y), i))
        # return prim(graph)
            
                
#         def prim(graph):
#             V = {0}
#             edges = graph[0]
#             heapify(edges)
#             sum_cost = 0
#             while edges:
#                 cost, p2 = heappop(edges)
#                 if p2 in V:
#                     continue
#                 sum_cost += cost
#                 V.add(p2)
#                 for new_edge in graph[p2]:
#                     if new_edge[1] not in V:
#                         heappush(edges, new_edge)
#                 if len(V) == len(graph):
#                     break
#             return sum_cost


class UnionFind:
    def __init__(self, n):
        self.parents = [i for i in range(n)]
        self.rank = [1 for i in range(n)]
        
    def union(self, x, y):
        a, b = self.find(x), self.find(y)
        if a == b:
            return
        if self.rank[a] > self.rank[b]:
            self.parents[b] = self.parents[a]
            self.rank[a] += self.rank[b]
        else:
            self.parents[a] = self.parents[b]
            self.rank[b] += self.rank[a]
    
    def find(self, x):
        if self.parents[x] != x:
            self.parents[x] = self.find(self.parents[x])
        return self.parents[x]

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        UF = UnionFind(len(points))
        cost = 0
        for i in range(len(points)-1):
            for j in range(i+1, len(points)):
                edges.append([abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1]), i, j])
        edges.sort(key = lambda x: x[0])
        for i in range(len(edges)):
            dist, j, k = edges[i]
            if UF.find(j) != UF.find(k):
                cost += dist
                UF.union(j, k)
        return cost

class UnionFind:
    def __init__(self, length):
        self.parents = [-1] * length
        self.ranks = [1] * length
    
    def find(self, src):
        if self.parents[src] == -1:
            return src
        self.parents[src] = self.find(self.parents[src])
        return self.parents[src]

    def union(self, src, dest):
        rootSrc, rootDest = self.find(src), self.find(dest)
        if rootSrc == rootDest:
            return False
        
        if self.ranks[rootSrc] > self.ranks[rootDest]:
            self.parents[rootDest] = rootSrc
            self.ranks[rootSrc] += self.ranks[rootDest]
            return True
        else:
            self.parents[rootSrc] = rootDest
            self.ranks[rootDest] += self.ranks[rootSrc]
            return True
        
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def calHamming(pt1, pt2):
            return abs(pt1[0] - pt2[0]) + abs(pt1[1] - pt2[1])
        
        ptsDistance = []
        for i, j in itertools.combinations(range(len(points)), 2):
            ptsDistance.append((calHamming(points[i], points[j]), i, j))
        
        ptsDistance.sort()
        
        result = 0
        uf = UnionFind(len(points))
        for distance, src, dest in ptsDistance:
            if uf.union(src, dest):
                result += distance
        return result

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if len(points) == 1: return 0
        res = 0
        curr = 0 # select a random point as the starting point
        dis = [math.inf] * n
        explored = set()
        
        for _ in range(n - 1):
            x0, y0 = points[curr]
            explored.add(curr)
            dis[curr] = math.inf
            for j, (x, y) in enumerate(points):
                if j in explored: continue
                if dis[j] >  abs(x - x0) + abs(y - y0):
                    dis[j] = abs(x - x0) + abs(y - y0)
                
            delta, curr = min((d, j) for j, d in enumerate(dis)) 
            res += delta
            
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def find(i):
            while i != root[i]:
                root[i] = root[root[i]]
                i = root[i]
            return i
        
        def union(i, j):
            if rank[i] < rank[j]:
                root[i] = j
            elif rank[i] > rank[j]:
                root[j] = i
            else:
                root[j] = i
                rank[i] += 1
            
        n = len(points)
        graph = [] 
        for i in range(n):
            for j in range(i+1, n):
                distance = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]) 
                graph.append((distance, i, j))
        graph.sort()
        
        min_cost = 0
        root = list(range(n))
        rank = [0] * n
        for distance, i, j in graph:
            root1, root2 = find(i), find(j)
            if root1 != root2:
                union(root1, root2)
                min_cost += distance

        return min_cost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        graph = collections.defaultdict(list)
        
        for node1, points1 in enumerate(points):
            for node2, points2 in enumerate(points):
                graph[node1].append(( abs(points1[0] - points2[0]) + abs(points1[1] - points2[1]), node2 ))
                
        pq = [(0,0)]
        res = 0
        visited = set()
        
        while pq:
            d, node = heapq.heappop(pq)
            if node in visited:
                continue
            visited.add(node)
            res += d
            if len(visited) == len(points):
                return res
            for distance,nei in graph[node]:
                if nei not in visited:
                    heapq.heappush(pq, (distance,nei))
                    
        return res

# Solve Leetcode 1584. Min Cost to Connect All Points using the boilerplate code below, and then implement Kruskal's algorithm to solve the problem. Use self.distance(pointA, pointB) to find distance (weight of edge) between two nodes.

class DisjointSet:
    def __init__(self, points):
        self.parent = {}
        self.rank = {}
        for point in points:
            self.parent[point] = point
            self.rank[point] = 1

    def find(self, x):
        if self.parent[x] == x:
            return x
        self.parent[x] = self.find(self.parent[x])
        return self.parent[x]

    def union(self, x, y):
        x_set = self.find(x)
        y_set = self.find(y)

        if self.rank[x_set] < self.rank[y_set]:
            self.parent[x_set] = y_set
        elif self.rank[x_set] > self.rank[y_set]:
            self.parent[y_set] = x_set
        else:
            self.parent[x_set] = y_set
            self.rank[y_set] += 1

        
from collections import defaultdict
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        points = [tuple(point) for point in points]
        disjoint_set = DisjointSet(points)

        for i in range(len(points)):
            for j in range(i+1, len(points)):
                distance = self.distance(points[i], points[j])
                edges.append([distance, points[i], points[j]])
        
        edges.sort()
        answer = 0
        i = 0
        times = 0
        while times < len(points)-1:
            if times == len(points) - 1:
                return answer
            distance, nodeA, nodeB = edges[i]
            if disjoint_set.find(nodeA) != disjoint_set.find(nodeB):
                times += 1
                answer += distance
                disjoint_set.union(nodeA, nodeB)
            i += 1
                
        return answer
        
        


    def distance(self, pointA, pointB):
        return abs(pointA[0] - pointB[0]) + abs(pointA[1] - pointB[1])

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        edges = []
        
        for i in range(N):
            a = tuple(points[i])
            
            for j in range(N):
                if i == j:
                    continue
                b = tuple(points[j])
                cost = abs(a[0] - b[0]) + abs(a[1] - b[1])
                edges.append((cost, i, j))
                
        edges.sort()
        
        dsu = DSU(N)
        mst = 0
        count = 0
        
        for cost, a, b in edges:
            if count >= N - 1:
                break
            if dsu.union(a, b):
                mst += cost
                count += 1
                
        return mst
            
class DSU():
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.size = [1 for _ in range(n)]

    def union(self, a, b):
        roota = self.find(a)
        rootb = self.find(b)
        if roota == rootb:
            return False
        if self.size[roota] < self.size[rootb]:
            self.size[rootb] += self.size[roota]
            self.parent[roota] = rootb
        else:
            self.size[roota] += self.size[rootb]
            self.parent[rootb] = roota
        return True

    def find(self, a):
        root = self.parent[a]
        while root != self.parent[root]:
            root = self.parent[root]
        curr = a

        # path compression
        while curr != root:
            after = self.parent[curr]
            self.parent[curr] = root
            curr = after

        return root


class UnionFind:
    def __init__(self, n):
        self.parent = collections.defaultdict(int)
        for i in range(1, n + 1):
            self.parent[i] = i

    def find(self, i):
        if i != self.parent[i]:
            self.parent[i] = self.find(self.parent[i])
        return self.parent[i]

    def union(self, u, v):
        u_parent, v_parent = self.find(u), self.find(v)
        if u_parent == v_parent: return False
        self.parent[u_parent] = v_parent
        return True

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        connections = list()
        for i in range(n - 1):
            for j in range(i+1, n):
                # get distance
                connections.append((i, j, abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])))
        res = 0
        connections_sorted = sorted(connections, key=lambda arr: arr[2])
        UF = UnionFind(n)
        for connection in connections_sorted:
            a, b, cost = connection
            if UF.find(a) != UF.find(b):
                UF.union(a, b)
                res += cost
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def md(p1, p2):
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        q = [md(points[0], p) for p in points]
        print(q)
        res = 0
        for _ in range(len(points) - 1):
            d, j = min((d, j) for j, d in enumerate(q) if d > 0)
            res += d
            q = [min(q[i], md(points[i], points[j])) for i in range(len(q))]
        return res


#|xi - xj| + |yi - yj|

from collections import defaultdict

class UnionFind:
    
    def __init__(self, n: int):
        
        self.n = list(range(n))
    
    def root(self, element: int):
        root = self.n[element]
        
        while root != self.n[root]:
            root = self.n[root]
        
        temp = self.n[element]
        
        while temp != self.n[temp]:
            
            self.n[temp] = root
            temp = self.n[temp]
        
        return root
        
    
    def union(self, a: int, b: int):
        
        rootA = self.root(a)
        rootB = self.root(b)
        
        self.n[rootB] = rootA
        
    
    def find(self, a: int, b: int):
        return self.root(a) == self.root(b)

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        if len(points) < 2:
            return 0
        
        graph = defaultdict(list)
        edges = []
        
        for i in range(len(points)):
            
            xi, yi = points[i]
            
            for j in range(i + 1, len(points)):
                
                xj, yj = points[j]
                
                edges.append((abs(xi - xj) + abs(yi - yj), i, j))
        
        edges.sort()
        total = 0
        
        uf = UnionFind(len(points))
        
        for distance, origin, destination in edges:
            if not uf.find(origin, destination):
                uf.union(origin, destination)
                total += distance
        
        return total
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # MST search algorithm Prim
        G = collections.defaultdict(list)
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                dis = abs(points[i][0]-points[j][0]) + abs(points[i][1] - points[j][1])
                G[i].append((dis, j))
                G[j].append((dis, i))
        # print(G)
        visited = {0}
        pq = G[0]
        heapq.heapify(pq)
        res = 0
        while len(visited) < len(points) and pq:
            w, v = heapq.heappop(pq)
            if v not in visited:
                res += w
                visited.add(v)
                for w, nei in G[v]:
                    if nei not in visited:
                        heapq.heappush(pq, (w,nei))
        return res
        
        
        
        # MST search algorithm Kruskal
        # create MST over a created graph
#         q = []
#         for i in range(len(points)):
#             for j in range(i+1, len(points)):
#                 dis = abs(points[i][0]-points[j][0]) + abs(points[i][1] - points[j][1])
#                 q.append((dis, i, j))
        
#         def find(x):
#             if (x != parent[x]):
#                 parent[x] = find(parent[x])
#             return parent[x]
#         def union(x, y):
#             if size[x] > size[y]:
#                 size[x] += size[y]
#                 parent[y] = x
#             else:
#                 size[y] += size[x]
#                 parent[x] = y
                
#         n = len(points)
#         parent = [i for i in range(n+1)]
#         size = [1 for _ in range(n+1)]  
#         q.sort()  # sort edges
#         res = 0
#         count = 0
#         for w, u, v in q:
#             rA, rB = find(u), find(v)
#             if rA == rB:
#                 continue
#             union(rA, rB)
#             res += w
#             # Optimize so that we don't traverse all edges
#             count += 1
#             if count == n:
#                 return res
#         return res 


#Build weighted graph and then use Union-Find to get MST
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N, g = len(points), []
        res = 0
        
        #build the weighted graph
        for i in range(N - 1):
            x0, y0 = points[i]
            for j in range(i + 1, N):                
                x1, y1 = points[j]
                dist = abs(x0 - x1) + abs(y0 - y1)
                g.append((dist, (i, j)))
                
        #sort by weight
        g.sort()
        
        #Union-Find to get MST
        parents = [None] * N
        for i in range(N): parents[i] = i
            
        def findParent(x):
            if parents[x] != x:
                parents[x] = findParent(parents[x])
            
            return parents[x]
        
        used_edges = 0
        for w, (a, b) in g:
            pa = findParent(a)
            pb = findParent(b)
            
            #union sub-graphs if not connected yet
            if pa != pb:
                res += w
                parents[pa] = pb
                used_edges += 1
                if used_edges == N - 1:
                    #we find all edges
                    break
        
        return res


class Solution:
    def minCostConnectPoints(self, points):
        distance = lambda p1, p2: abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        points.sort(key = lambda p: p[0] + p[1])
        total_cost = 0
        points = [[p, distance(p, points[0])] for p in points]
        while points:
            minIdx, mindist = None, float('inf')
            for i, (p1, dist) in enumerate(points):
                if dist < mindist:
                    minIdx, mindist = i, dist
            p1, cost = points.pop(minIdx)
            total_cost += cost
            for i, (p2, dist) in enumerate(points):
                points[i][1] = min(points[i][1], distance(p1, p2))
                #newdist = distance(p1, p2)
                #if newdist < dist:
                #    points[i][1] = newdist
        return total_cost        

class UnionFind(object):
    def __init__(self, n):
        self.par = [i for i in range(n)]
        self.rnk = [0]*n
        
    def find(self,x):
        if self.par[x] != x:
            self.par[x] = self.find(self.par[x])
        return self.par[x]
    
    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        if xr == yr:
            return False
        elif self.rnk[xr] < self.rnk[yr]:
            self.par[xr] = yr
        elif self.rnk[xr] > self.rnk[yr]:
            self.par[yr] = xr
        else:
            self.par[yr] = xr
            self.rnk[xr] += 1
        return True
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        distances = []
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                distances.append([i, j, abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])])
                
        distances.sort(key = lambda x: x[2])
        res = 0
        uf = UnionFind(n)
        for i, j, d in distances:
            if uf.find(i) == uf.find(j):
                continue
            res += d
            uf.union(i, j)
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def cost(a,b): 
            return abs(a[0]-b[0]) + abs(a[1] - b[1])
        
        #LC copy from JerryJin2905
        
        edges = [[] for _ in points]
        
        # Build edge cost list
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                dist = cost(points[i], points[j])
                edges[i].append([dist, j])
                edges[j].append([dist, i])
                                
        # choose first point as root
        cost = 0
        tree = {0}
        pq = []
        for c,v in edges[0]:
            pq.append([c,v])
            
        heapify(pq)
            
        while len(tree) < len(points):

            c,v = heappop(pq)
            if v in tree:
                continue
            tree.add(v)
            cost += c
                                
            for d,u in edges[v]:
                if not u in tree:
                    heappush(pq, [d,u])
    
        return cost


class DisjoinSet:
  def __init__(self, n):
    self.parent = [i for i in range(n)]
  
  def find(self, x):
    if self.parent[x] != x:
      self.parent[x] = self.find(self.parent[x])
    return self.parent[x]
  
  def union(self, x, y):
    xr = self.find(x)
    yr = self.find(y)
    if xr != yr:
      self.parent[yr] = xr
      return True
    return False

class Solution:
    def minCostConnectPoints(self, points):
      n = len(points)
      graph = []
      ds = DisjoinSet(n)

      for i in range(n):
        for j in range(i + 1, n):
          dist = self.getDist(points[i], points[j])
          graph.append((dist, i, j))    

      graph.sort()

      res = 0

      for dist, u, v in graph:
        if ds.union(u, v):
          res += dist
      return res

    def getDist(self, x, y):
      return abs(x[0] - y[0]) + abs(x[1] - y[1])

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        manhattan = lambda u, v: abs(u[0] - v[0]) + abs(u[1] - v[1])
        from collections import defaultdict
        n = len(points)

        graph = defaultdict(list)
        for i in range(n - 1):
            for j in range(i + 1, n):
                w = manhattan(points[i], points[j])
                graph[i].append((w, j))
                graph[j].append((w, i))

        k = 1                       # keep track of vertices
        costs = 0
        seen = [False] * n

        seen[0] = True
        heap = graph[0]
        heapq.heapify(heap)
        while heap:
            w, u = heapq.heappop(heap)
            if not seen[u]:
                seen[u] = True
                costs += w
                k += 1
                
                for ew, v in graph[u]:
                    heapq.heappush(heap, (ew, v))
                    
            if k == n: break
        return costs


class DSU:
    def __init__(self, size):
        self.indexes = {i:i for i in range(size)}
        
        
    def root(self, i):
        node = i
        while i!=self.indexes[i]:
            i = self.indexes[i]
        
        while node!=i:
            nnode = self.indexes[node]
            self.indexes[node] = i
            node = nnode
        return i
    
    def unite(self, i, j):
        ri, rj = self.root(i), self.root(j)
        if ri==rj: return
        self.indexes[rj] = ri
        
        
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        edges = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                x,y = points[i][0], points[i][1]
                u,v = points[j][0], points[j][1]
                edges.append((abs(u-x)+abs(v-y), i, j))
        
        edges.sort()
        
        dsu = DSU(len(points))
        
        ans = 0
        for dis, u, v in edges:
            if dsu.root(u)==dsu.root(v):
                continue
            
            dsu.unite(u, v)
            ans += dis
        return ans
    
        
        
        
        
        
        
        
        
        
        
        
        
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        if len(points) <= 1:
            return 0
        
        def dist(a,b):
            return abs(a[1]-b[1]) + abs(a[0]-b[0])
        
        A = {i:{i} for i in range(len(points))}
        edges = [(dist(p1,p2), i, j) for i, p1 in enumerate(points) for j, p2 in enumerate(points) if p1 != p2]
        import heapq
        heapq.heapify(edges)
        
        tot = 0
        n = len(points)-1
        while n:
            w, a, b = heapq.heappop(edges)
            if not A[a].intersection(A[b]):
                # print(\"edge:\",points[a],points[b])
                # print(\"a's set:\" ,A[a])
                # print(\"b's set:\", A[b])
                B = A[a].union(A[b])
                for b in B:
                    A[b] = B
                tot += w
                n -= 1
        print((A[0], len(points)))
        return tot


from heapq import heappush,heappop
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def calcCost(i,j):
            return abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
        totalCost,visited,q=0,set(),[(0,0)]
        while len(visited)!=len(points):
            cost,point=heappop(q)
            if point not in visited:
                visited.add(point)
                totalCost+=cost
                for i in range(len(points)):
                    if i!=point:
                        heappush(q,(calcCost(point,i),i))
        return totalCost

from heapq import *
class Solution:
    def minCostConnectPoints(self, points):
        N = len(points)
        dist = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        edges = [[] * N for _ in range(N)]
        for i1, p1 in enumerate(points):
            for i2, p2 in enumerate(points[i1+1:], start = i1+1):
                distance = dist(p1, p2)
                edges[i1].append([distance, i2])
                edges[i2].append([distance, i1])
        heap = edges[0]
        heapify(heap)
        total_cost, seen = 0, {0}
        while len(seen) < N:
            cost, node = heappop(heap)
            if node in seen:
                continue
            seen.add(node)
            total_cost += cost
            for dist, next_ in edges[node]:
                if next_ not in seen:
                    heappush(heap, [dist, next_])
        return total_cost

# alright, whatever, time to solve it again in Python3 \\U0001f40d  whoo!

# ok silly mistake, but that's A ok :)

# alright! cool, well time for C++ then i'm done upsolving this one, it was fun :)

# class Solution:
#     def minCostConnectPoints(self, A: List[List[int]]) -> int:
#         N = len(A)
#         P = [i for i in range(N)]                       # \\U0001f642 parent representatives of N disjoint sets
#         E = []
#         for u in range(N):
#             x1, y1 = A[u]
#             for v in range(u + 1, N):
#                 x2, y2 = A[v]
#                 w = abs(x1 - x2) + abs(y1 - y2)
#                 E.append([ u, v, w ])                   # \\U0001f5fa edge u, v with weight w \\U0001f4b0
#         E.sort(key = lambda edge: edge[2])              # ⭐️ sort edges by weight w \\U0001f4b0
#         def find(x):
#             P[x] = P[x] if P[x] == x else find(P[x])
#             return P[x]
#         def union(a, b):
#             a = find(a)
#             b = find(b)
#             if a == b:
#                 return False
#             P[a] = b                                     # \\U0001f3b2 arbitrary choice
#             return True
#         return sum([w for u, v, w in E if union(u, v)])  # \\U0001f3af sum of minimum edge weights w \\U0001f4b0 to construct Kruskal's MST \\U0001f332

# create the edge cost lookups E
# create adjacency list adj
# create winner/best for each v



class Solution:
    def minCostConnectPoints(self, A: List[List[int]], total = 0) -> int:
        N = len(A)
        cand = set([i for i in range(1, N)])
        E = [[float('inf')] * N for _ in range(N)]
        for u in range(N):
            x1, y1 = A[u]
            for v in range(u + 1, N):
                x2, y2 = A[v]
                cost = abs(x1 - x2) + abs(y1 - y2)
                E[u][v] = cost
                E[v][u] = cost
        s = 0
        q = []
        best = [float('inf')] * N
        for v in range(1, N):
            if best[v] > E[s][v]:
                best[v] = E[s][v]
                heappush(q, [best[v], v])
        while len(cand):
            cost, u = heappop(q)
            if u not in cand:
                continue
            cand.remove(u)
            total += cost
            for v in range(N):
                if v not in cand:
                    continue
                if best[v] > E[u][v]:
                    best[v] = E[u][v]
                    heappush(q, [best[v], v])
        return total
    
    
    


from heapq import heapify, heappush, heappop
from collections import defaultdict
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # helper function to calculate the manhatten distance 
        # between two points
        def distance(point1, point2):
            x1, y1 = point1
            x2, y2 = point2
            return abs(x1-x2) + abs(y1-y2)
        
        n = len(points)
        if n == 1:
            return 0
        
        # convert all the points to tuples so they are hashable
        points = [tuple(p) for p in points]
        
        # build the graph
        # key: vertex
        # value: list of neighbors and their edge weights
        cost = defaultdict(list)
        for i in range(n):
            point1 = points[i]
            for j in range(i+1, n):
                point2 = points[j]
                d = distance(point1, point2)
                cost[point1].append((d, point2))
                cost[point2].append((d, point1))
                
        
        ans = 0
        # we start at the first point in the input
        visited = {points[0]}
        # add all the neighbors of point 0 to PQ
        heap = cost[points[0]]
        heapify(heap)
        
        # we loop until all the points have been visited
        while len(visited) != n:
            # remove the vertex with the smallest edge weight
            d, v = heappop(heap)
            # check if this vertex is unvisited
            if v not in visited:
                # move this vertex to the visited set
                visited.add(v)
                # this edge is part of the MST
                ans += d
                # add all the neighbors of v into priority queue
                for record in cost[v]:
                    heappush(heap, record)
        
        return ans
                    
                       
                        
                    
            
            
        
        
        


class DSU:
    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 x!=self.parent[x]:
            self.parent[x]=self.find(self.parent[x])
        return self.parent[x]
    
    def union(self,x,y):
        px = self.find(x)
        py = self.find(y)
        rx = self.rank[x]
        ry = self.rank[y]
        if px==py:
            return False
        if rx>ry:
            self.parent[py]=px
            self.rank[px]+=self.rank[py]
        else:
            self.parent[px]=py
            self.rank[py]+=self.rank[px]
        return True
                
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        edges = []
        for i in range(n):
            for j in range(i+1, n):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((dist, i, j))
    
        edges.sort()
        res = 0
        ds = DSU(n)
        for cost, u, v in edges:
            if ds.union(u,v):
                res += cost
        return res

from heapq import heappush,heappop
class Solution:
    
    def manhattan(self,point1,point2):
        return abs(point1[0]-point2[0]) + abs(point1[1]-point2[1])
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        graph = defaultdict(list)
        n = len(points)
        for i in range(n):
            for j in range(n):
                if i != j:
                    graph[i].append([self.manhattan(points[i],points[j]),j])
        
        
        heap = [(0,0)]
        visited = set()
        answer = 0
        while len(visited)<n:
            distance,node = heappop(heap)
            if node in visited:
                continue
            
            visited.add(node)
            answer+=distance
            for weight,nei in graph[node]:
                if nei not in visited:
                    heappush(heap,(weight,nei))
        
        return answer


class DisjointSet:
    def __init__(self, size):
        self.size = size
        self.parents = list(range(size))
    def find(self, node):
        if node != self.parents[node]:
            self.parents[node] = self.find(self.parents[node])
        return self.parents[node]
    def union(self, node1, node2):
        parent1 = self.find(node1)
        parent2 = self.find(node2)
        if parent1 != parent2:
            self.parents[parent1] = parent2
            return True
        return False


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        is_connected = [False]*N
        edges = []
        for i in range(N):
            for j in range(i+1, N):
                distance = abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                edges.append((distance, i, j))
        edges.sort()
        cost = 0
        disjoint_set = DisjointSet(N)
        for distance, i, j in edges:
            if disjoint_set.union(i, j):
                cost += distance
        return cost

class UnionFind:
    def __init__(self, n):
        self.parents = [i for i in range(n)]
        
    def union(self, index1, index2):
        root1 = self.find(index1)
        root2 = self.find(index2)
        if root1 == root2:
            return 0
        elif root1 > root2:
            self.parents[root2] = root1
        else:
            self.parents[root1] = root2
        return 1
    
    def find(self, index):
        if self.parents[index] != index:
            self.parents[index] = self.find(self.parents[index])
        return self.parents[index]

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) <= 1:
            return 0
        
        edges = []
        for i, point1 in enumerate(points):
            for j in range(i + 1, len(points)):
                point2 = points[j]
                distance = abs(point1[0] - point2[0]) + abs(point1[1] - point2[1])
                edges.append((distance, i, j))
        edges.sort()
        
        uf = UnionFind(len(points))
        total = 0
        for i, (weight, node1, node2) in enumerate(edges):
            is_union = uf.union(node1, node2)
            if is_union:
                total += weight
        return total
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        cache = []
        l = len(points)
        if l == 1:
            return 0

        for i in range(l-1):
            for j in range(i+1, l):
                start = points[i]
                end = points[j]
                length = abs(start[0]-end[0])+abs(start[1]-end[1])
                cache.append([length, i, j])
        cache.sort()
        #print(cache)

        res = 0
        t = len(cache)
        count = 0
        group = []
        for i in range(t):
            #print(group)
            
            curr = cache[i]
            g = len(group)
            a = None
            b = None
            for j in range(g):
                if curr[1] in group[j]:
                    a = j
                if curr[2] in group[j]:
                    b = j
            #print(a,b)

            if a == None and b == None:
                group.append({curr[1], curr[2]})
            elif a == None:
                group[b].add(curr[1])
            elif b == None:
                group[a].add(curr[2])
            else:
                if a == b:
                    continue
                else:
                    group[a] = group[a] | group[b]
                    group.pop(b)
            count += 1
            res += curr[0]   
            if count == l-1:
                #print(group)
                return res


from heapq import *

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if not points:
            return 0
        
        adjList = self.buildAdjList(points)

        heap = [(0, 0, 0)]
        visited = set()
        minCost = 0
        while heap and len(visited) != len(adjList):
            cost, i, j = heappop(heap)
            if j in visited:
                continue
                
            visited.add(j)
            minCost += cost
                
            for nj, cost in adjList[j]:
                if nj not in visited:
                    heappush(heap, (cost, j, nj))
        return minCost
        
    def buildAdjList(self, points):
        adjList = {}
        
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                x1, y1 = points[i]
                x2, y2 = points[j]
                if i not in adjList:
                    adjList[i] = []
                if j not in adjList:
                    adjList[j] = []

                weight = abs(x1-x2) + abs(y1-y2)
                adjList[i].append((j, weight))
                adjList[j].append((i, weight))
        return adjList

class UnionFind:
    def __init__(self, n):
        self.parents = [i for i in range(n)]
        
    def union(self, x, y):
        a, b = self.find(x), self.find(y)
        self.parents[a] = self.parents[b]
    
    def find(self, x):
        if self.parents[x] != x:
            self.parents[x] = self.find(self.parents[x])
        return self.parents[x]

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        UF = UnionFind(len(points))
        cost = 0
        for i in range(len(points)-1):
            for j in range(i+1, len(points)):
                edges.append([abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1]), i, j])
        edges.sort(key = lambda x: x[0])
        for i in range(len(edges)):
            dist, j, k = edges[i]
            if UF.find(j) != UF.find(k):
                cost += dist
                UF.union(j, k)
        return cost

import math
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        edges = []
        
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                edges.append(( abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]), i, j))
                
        edges.sort()
        # print(edges)
        union_find = UnionFind(len(points))
        
        min_sum = 0
        for d, i, j in edges:
            if union_find.union(i, j):
                min_sum += d
                
        return min_sum
                
class UnionFind:
    def __init__(self, n):
        
        self.parent = [i for i in range(n)]
        self.size = [1 for i in range(n)]
        
    def find(self, p):
        root = p
        while(root != self.parent[root]):
            root = self.parent[root]
            
        node = p
        while(node != self.parent[node]):
            
            nextNode = self.parent[node]
            self.parent[node] = root
            node = nextNode
            
        return root
            
    def union(self, p, q):
        
        p_root = self.find(p)
        q_root = self.find(q)
        
        if p_root == q_root:
            return False
        
        if self.size[p_root] < self.size[q_root]:
            self.parent[p_root] = q_root
            self.size[q_root] += self.size[p_root]
        else:
            self.parent[q_root] = p_root
            self.size[p_root] += self.size[q_root]
            
        return True

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # prim
        from collections import defaultdict
        import heapq
        manhattan = lambda a, b:abs(a[0]-b[0]) + abs(a[1]-b[1])
        n, c = len(points), defaultdict(list)
        if n==0:
            return 0
        for i in range(n):
            for j in range(i+1, n):
                dis = manhattan(points[i], points[j])
                c[i].append((dis, j))
                c[j].append((dis, i))
        cnt, ans, visited, heap = 1, 0, [0]*n, c[0]
        visited[0] = 1
        heapq.heapify(heap)
        while cnt<n:
            dis, p = heapq.heappop(heap)
            if not visited[p]:
                visited[p], cnt, ans = 1, cnt+1, ans+dis
                for record in c[p]:
                    heapq.heappush(heap, record)
        return ans 

# alright, whatever, time to solve it again in Python3 \\U0001f40d  whoo!

# ok silly mistake, but that's A ok :)

# alright! cool, well time for C++ then i'm done upsolving this one, it was fun :)

# class Solution:
#     def minCostConnectPoints(self, A: List[List[int]]) -> int:
#         N = len(A)
#         P = [i for i in range(N)]                       # \\U0001f642 parent representatives of N disjoint sets
#         E = []
#         for u in range(N):
#             x1, y1 = A[u]
#             for v in range(u + 1, N):
#                 x2, y2 = A[v]
#                 w = abs(x1 - x2) + abs(y1 - y2)
#                 E.append([ u, v, w ])                   # \\U0001f5fa edge u, v with weight w \\U0001f4b0
#         E.sort(key = lambda edge: edge[2])              # ⭐️ sort edges by weight w \\U0001f4b0
#         def find(x):
#             P[x] = P[x] if P[x] == x else find(P[x])
#             return P[x]
#         def union(a, b):
#             a = find(a)
#             b = find(b)
#             if a == b:
#                 return False
#             P[a] = b                                     # \\U0001f3b2 arbitrary choice
#             return True
#         return sum([w for u, v, w in E if union(u, v)])  # \\U0001f3af sum of minimum edge weights w \\U0001f4b0 to construct Kruskal's MST \\U0001f332

# create the edge cost lookups E
# create adjacency list adj
# create winner/best for each v



class Solution:
    def minCostConnectPoints(self, A: List[List[int]], total = 0) -> int:
        N = len(A)
        # 1.
        cand = set([i for i in range(N)])
        E = [[float('inf')] * N for _ in range(N)]
        for u in range(N):
            x1, y1 = A[u]
            for v in range(u + 1, N):
                x2, y2 = A[v]
                cost = abs(x1 - x2) + abs(y1 - y2)
                E[u][v] = cost
                E[v][u] = cost
        # 2.
        q = []
        best = [float('inf') for _ in range(N)]
        winner = [-1 for _ in range(N)]
        s = 0
        cand.remove(0)
        for v in range(1, N):
            if best[v] > E[s][v]:
                best[v] = E[s][v]
                winner[v] = s
                heappush(q, [best[v], v])
        # 3.
        while len(cand):
            cost, u = heappop(q)
            if u not in cand:
                continue
            cand.remove(u)
            total += cost
            for v in range(N):
                if v not in cand:
                    continue
                if best[v] > E[u][v]:
                    best[v] = E[u][v]
                    winner[v] = u
                    heappush(q, [best[v], v])
        return total
    
    
    


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:

        graph = defaultdict(list)
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                cost = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                graph[i].append((cost, j))
                graph[j].append((cost, i))
        
        seen = [0] * (len(points)+1)
        seen[0] = 1
        q = graph[0]
        minimumCost = 0
        connectedNodes = 1
        heapq.heapify(q)
        while q:
            cost, point = heapq.heappop(q)
            if not seen[point]:
                seen[point] = 1
                minimumCost += cost
                connectedNodes += 1
                for connectingCost, neighbour in graph[point]:
                    heapq.heappush(q, (connectingCost, neighbour))
            if connectedNodes >= len(points):
                break
        return minimumCost

class DSU:
    def __init__(self, n):
        self.n = n
        self.fa = list(range(n))

    def find(self, x):
        r = x
        while self.fa[r] != r:
            r = self.fa[r]
        i = x
        while i != r:
            i, self.fa[i] = self.fa[i], r
        return r
    
    def join(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x != y:
            self.fa[x] = y

class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:
        n = len(p)
        e = []
        for i in range(n):
            for j in range(n):
                if i == j:
                    continue
                d = abs(p[i][0] - p[j][0]) + abs(p[i][1] - p[j][1])
                e.append((d, i, j))
        
        e.sort()
        
        dsu = DSU(n)
        had = 0
        ans = 0
        for (d, i, j) in e:
            if dsu.find(i) != dsu.find(j):
                ans += d
                dsu.join(i, j)
                had += 1
            if had == n - 1:
                break
        return ans


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) < 2:
            return 0
        e = [[] for _ in points]
        n = len(points)
        for i, u in enumerate(points):
            for j in range(i + 1, n):
                v = points[j]
                d = abs(u[0] - v[0]) + abs(u[1] - v[1])
                e[i].append((d, j))
                e[j].append((d, i))
        
        tree = { 0 }
        
        pq = []
        for v in e[0]:
            pq.append(v)
        heapify(pq)
        
        c = 0
        while len(tree) < n:
            try:
                d, v = heappop(pq)
            except IndexError:
                break
            if v in tree:
                continue
            c += d
            tree.add(v)
            for u in e[v]:
                heappush(pq, u)
        
        return c


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        n, dic = len(points), collections.defaultdict(list)
        
        for i in range(n):
            for j in range(i+1, n):
                d = manhattan(points[i], points[j])
                dic[i].append((d, j))
                dic[j].append((d, i))
                
        cnt, ans, visited, heap = 1, 0, [0] * n, dic[0]
        visited[0] = 1
        heapq.heapify(heap)
        while heap:
            d, j = heapq.heappop(heap)
            if not visited[j]:
                visited[j], cnt, ans = 1, cnt+1, ans+d
                for record in dic[j]: 
                    heapq.heappush(heap, record)
            if cnt >= n: break        
        return ans

class Union_Find:
    def __init__(self, n):
        self.father = {i:i for i in range(n)}
        self.count = n
        # 可以查看 某一个node 有几个联通
        self.rank = [1] * n

    def find(self, x):
        if self.father[x] == x:
            return x
        self.father[x] = self.find(self.father[x])
        return self.father[x]

    def union(self, x, y):
        if self.rank[x] < self.rank[y]:
            x, y = y, x
        self.father[y] = x
        self.rank[x] += self.rank[y]
        self.count -= 1

    def find_union(self, x, y):
        father_x, father_y = self.find(x), self.find(y)
        if father_x != father_y:
            self.union(father_x, father_y)
            # 表示，如果本来不是联通 return true
            return True
        return False
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        mst = collections.defaultdict(set)
        n = len(points)
        graph = []
        uf = Union_Find(n)
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                cost = cost = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                graph.append([i,j,cost])
        
        result = 0
        for a, b, c in sorted(graph, key = lambda x:x[2]):
            if uf.find_union(a,b):
                result += c
        return result
        
                
                
                
            
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        from queue import PriorityQueue
        q = PriorityQueue()
        
        # adj = {}
        # for point in points:
        #     s = point[]
        l = len(points)
        visited = set()
        
        for j in range(1, l):
            q.put((abs(points[0][0] - points[j][0]) + abs(points[0][1] - points[j][1]), j))
        
        visited.add(0)
        count = 1
        ans = 0
        while count < l:
            dis, point = q.get()
            if point not in visited:
                visited.add(point)
                for j in range(l):
                    if j not in visited:
                        q.put((abs(points[point][0] - points[j][0]) + abs(points[point][1] - points[j][1]), j))
                ans += dis
                count += 1
            # print(dis, point)
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def union(g, u, v):
            p = g[u]
            o = g[v]
            for i in g.keys():
                if g[i] == o:
                    g[i] = p                    

        N = len(points)
        matrix = [[float('inf')]*N for _ in range(N)]
        ans = 0
        edges = []
        for node in range(N):
            for neighbor in range(N):
                if node == neighbor: continue
                if matrix[node][neighbor] != float('inf'): continue
                u, v = points[node], points[neighbor]
                d = abs(u[0] - v[0]) + abs(u[1] - v[1])
                matrix[node][neighbor] = d
                matrix[neighbor][node] = d
                edges.append((node, neighbor, d))
                edges.append((neighbor, node, d))
        P = {_: _ for _ in range(N)}
        edges.sort(key=lambda x: x[2])
        for u, v, w in edges:
            if P[u] != P[v]:
                union(P, u, v)
                ans += w
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points)<=1:return 0
        ans=0
        par={}
        def find(x):
            if x not in par:return x
            res=find(par[x])
            par[x]=res
            return res
        def union(a,b):
            n1=find(a)
            n2=find(b)
            if n1!=n2:
                if n1<n2:
                    par[n2]=n1
                else:
                    par[n1]=n2
                return True
            else:return False
        arr=[]
        for i in range(len(points)):
            _min=10e9
            ix=-1
            for j in range(i+1,len(points)):
                n=abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                arr.append((n,(i,j)))
##        print(ans)
##        arr=list(arr)
        arr.sort()
        for x in arr:
            i=x[1][0]
            j=x[1][1]
            n1=find(i)
            n2=find(j)
            if n1!=n2:
                if n1<n2:
                    par[n2]=n1
                else:
                    par[n1]=n2
                ans+=x[0]
        return ans  

from heapq import *
from collections import defaultdict
class Solution:
    def minCostConnectPoints(self, points):
        N = len(points)
        dist = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        edges = defaultdict(list)
        for i1, p1 in enumerate(points):
            for i2, p2 in enumerate(points[i1+1:], start = i1+1):
                distance = dist(p1, p2)
                edges[i1].append([distance, i2])
                edges[i2].append([distance, i1])
        heap = edges[0]
        heapify(heap)
        total_cost, seen = 0, {0}
        while len(seen) < N:
            cost, node = heappop(heap)
            if node in seen:
                continue
            seen.add(node)
            total_cost += cost
            for dist, next_ in edges[node]:
                if next_ not in seen:
                    heappush(heap, [dist, next_])
        return total_cost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        ## minimal spam tree
        length = len(points)
        if length < 2: return 0
        
        dist = [[0] * len(points) for _ in range(len(points))]
        value = float('inf')        
                
        for i in range(length):
            dist[i][i] = float('inf')
            for j in range(length):
                if i!=j:
                    dist[i][j] = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                if dist[i][j] < value:
                    value = dist[i][j]
                    idx_i, idx_j = i, j
                                
        connected, result = set([idx_i, idx_j]), dist[idx_i][idx_j]
       
        heap_q = []   
        def increaseQ(heap_q: List[int], idx:int, connected:Set[int]):
            for j in range(length):
                if j not in connected:
                    heapq.heappush(heap_q, (dist[idx][j], idx, j))
            
        increaseQ(heap_q, idx_i, connected)
        increaseQ(heap_q, idx_j, connected)
        
        while len(connected) < length:
                v, idx_i, idx_j = heapq.heappop(heap_q)
                if idx_i not in connected:
                    connected.add(idx_i)
                    increaseQ(heap_q, idx_i, connected)
                    result +=v
                if idx_j not in connected:
                    connected.add(idx_j)
                    increaseQ(heap_q, idx_j, connected)
                    result +=v
        return result
        
                
        


class Solution:
    def minCostConnectPoints(self, points):
        helper = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        points.sort(key = lambda p: p[0] + p[1])
        points = [[p, helper(p, points[0])] for p in points]
        total_cost = 0
        while points:
            minI, minD = None, float('inf')
            for i, (p, d) in enumerate(points):
                if d < minD:
                    minI, minD = i, d
            p1, cost = points.pop(minI)
            total_cost += cost
            for i, (p2, _) in enumerate(points):
                points[i][1] = min(points[i][1], helper(p1, p2))
        return total_cost

class DSU:
    def __init__(self, n):
        self.par = [i for i in range(n)]
    
    def find(self, x):
        if self.par[x] == x:
            return x
        self.par[x] = self.find(self.par[x])
        return self.par[x]
    
    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        if px == py:
            return
        self.par[px] = py
        return

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def dist(x, y):
            return abs(x[0]-y[0]) + abs(x[1]-y[1])
        
        cnt = 0
        n = len(points)
        needs = n-1
        dsu = DSU(n)
        
        dists = [(dist(points[i], points[j]), i, j) for i in range(n) for j in range(n) if i != j]
        dists.sort()
        
        i = 0
        while i < len(dists) and needs:
            d, x, y = dists[i]
            px, py = dsu.find(x), dsu.find(y)
            if px == py:
                i += 1
            else:
                # print(points[x], points[y])
                cnt += d
                dsu.union(x, y)
                needs -= 1
        return cnt
        


from heapq import heappush, heappop

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        points.sort()
        visited = set()
        n = len(points)
        cnt = 0
        q = []

        heappush(q, (0,0))
        while len(q):
            weight, source = heappop(q)
            if source in visited:
                continue
            cnt += weight
            visited.add(source)

            for i in range(n):
                if i not in visited:
                    weight = abs(points[i][0] - points[source][0]) + abs(points[i][1] - points[source][1])
                    heappush(q, (weight, i))
        
        return cnt


class Solution:
    def minCostConnectPoints(self, a: List[List[int]]) -> int:                
        n = len(a)
        if n <= 1: return 0
        d, cur, min_d = dict(), set(), float('inf')
        for i in range(n-1):            
            for j in range(n):                
                d[i, j] = d[j, i] = abs(a[i][0]-a[j][0]) + abs(a[i][1]-a[j][1])                 
                if min_d > d[i, j]: min_d = d[i, j]; cur = set([i, j])
                                        
        rem, cand = set(range(n)) - cur, []
        for x in cur:
            for y in rem:                
                cand.append((d[(x, y)], x, y))
        
        heapify(cand); ans = min_d       
        while len(cur) < n:
            val, x, y = heappop(cand)
            if y not in cur: 
                cur.add(y)  
                rem.discard(y)
                ans += val
                for z in rem:
                    heappush(cand, (d[(y, z)], y, z))
        return ans
                
        
        


class UnionFind:
    
    def __init__(self, n):
        self.count = n
        self.id = list(range(n))
        
    def connected(self, p, q):
        return self.find(p) == self.find(q)

    def find(self, p):
        if p == self.id[p]:
            return p
        return self.find(self.id[p])
    
    def union(self, p, q):
        idp = self.find(p)
        idq = self.find(q)
        if not self.connected(p,q):
            self.id[idp]=idq
        
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        distance = lambda i, j: abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
        graph = collections.defaultdict(list)
        hp = []
        n = len(points)
        for i in range(n):
            for j in range(n):
                if i != j:
                    graph[i].append((distance(i, j), j))
        start, cost = 0, 0
        visited = {0}

        for to in graph[0]:
            heapq.heappush(hp, to)
        
        while len(visited) != n and len(hp):
            dist, to = heapq.heappop(hp)
            if to not in visited:
                visited.add(to)
                cost += dist
                for t in graph[to]:
                    heapq.heappush(hp, t)
        return cost

class DSU:
    def __init__(self,n):
        self.p = list(range(n))
    def find(self,x):
        if self.p[x]!=x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]
    def union(self,x,y):
        r1 = self.find(x)
        r2 = self.find(y)
        if r1!=r2:
            self.p[r1] = r2
            return True
        return False
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        dsu = DSU(len(points))
        def getDistance(point1,point2):
            x1,y1 = point1
            x2,y2 = point2
            return abs(x1-x2)+abs(y1-y2)
        paths = []
        for i in range(len(points)):
            for j in range(i+1,len(points)):
                dis = getDistance(points[i],points[j])
                paths.append((dis,i,j))
        paths.sort()
        cost = 0
        for dis,i,j in paths:
            if dsu.union(i,j):
                cost+=dis
        return cost
                
                
        
                    
                    
                    
                    


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # create MST over a created graph
        # G = collections.defaultdict(list)
        q = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                dis = abs(points[i][0]-points[j][0]) + abs(points[i][1] - points[j][1])
                q.append((dis, i, j))
                # G[i].append((dis,j))  # can sort based on dis
        
        # MST search algorithm: Prim and Kruskal
        # Kruskal
        # path compression
        def find(x):
            if (x != parent[x]):
                parent[x] = find(parent[x])
            return parent[x]
        # union by rank
        def union(x, y):
            if size[x] > size[y]:
                size[x] += size[y]
                parent[y] = x
            else:
                size[y] += size[x]
                parent[x] = y
                
        n = len(points)
        parent = [i for i in range(n+1)]
        size = [1 for _ in range(n+1)]  
        q.sort()  # sort edges
        res = 0
        count = 0
        for w, u, v in q:
            rA, rB = find(u), find(v)
            if rA == rB:
                continue
            union(rA, rB)
            res += w
            # Optimize so that we don't traverse all edges
            count += 1
            if count == n:
                return res
        return res 

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n == 1:
            return 0
        
        mapper = collections.defaultdict(dict)
        for ind1, point1 in enumerate(points):
            for ind2, point2 in enumerate(points):
                dis = abs(point1[0] - point2[0]) + abs(point1[1] - point2[1])
                mapper[ind1][ind2] = dis
                mapper[ind2][ind1] = dis
        
        cost = 0
        c = set()
        unc = set(range(n))
        
        min_i, min_j = None, None
        min_d = math.inf
        for i in range(n):
            for j in range(n):
                if i != j and mapper[i][j] < min_d:
                    min_i, min_j = i, j
                    min_d = mapper[i][j]
        cost += min_d
        c.add(min_i)
        c.add(min_j)
        unc.remove(min_i)
        unc.remove(min_j)
        
        mins = dict()
        for i in unc:
            mins[i] = min(mapper[i][min_i], mapper[i][min_j])
        
        while unc:
            min_i = None
            min_d = math.inf
            for i in unc:
                if mins[i] < min_d:
                    min_i = i
                    min_d = mins[i]
                # for j in c:
                    # if mapper[i][j] < min_d:
                    #     min_i = i
                    #     min_d = mapper[i][j]
            cost += min_d
            c.add(min_i)
            unc.remove(min_i)
            
            for i in unc:
                mins[i] = min(mins[i], mapper[i][min_i])
            
        return cost


import bisect

class Union:
    
    def __init__(self, n):
        self.parents = [-1 for _ in range(n)]
        self.ranks = [0 for _ in range(n)]
        self.n = n
    
    def join(self, i, j):
        i = self.find(i)
        j = self.find(j)
        if self.ranks[i] > self.ranks[j]:
            self.parents[j] = i
        elif self.ranks[j] > self.ranks[i]:
            self.parents[i] = j
        else:
            self.parents[j] = i
            self.ranks[i] += 1
    
    def find(self, i):
        i_ori = i
        while self.parents[i] != -1:
            i = self.parents[i]
        if i != i_ori:
            self.parents[i_ori] = i
        return i

from collections import defaultdict


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def calc_distance(p1, p2):
            x1, y1 = p1
            x2, y2 = p2
            return abs(x1 - x2) + abs(y1 - y2)
        
        def find_best_node(min_dists, mst_set):
            min_dist = float('inf')
            for i, dist in enumerate(min_dists):
                if i not in mst_set and dist < min_dist:
                    best_node = i
                    min_dist = dist
            return best_node, min_dist
        
        def update_min_dists(node, min_dists, graph):
            for i, dist in graph[node]:
                min_dists[i] = min(min_dists[i], dist)            
        
        
        n = len(points)
        if n <= 1:
            return 0
        
        graph = defaultdict(list)
        for i in range(n):
            for j in range(i+1, n):
                p1, p2 = points[i], points[j]
                dist = calc_distance(p1, p2)
                graph[i].append((j, dist))
                graph[j].append((i, dist))
                
        min_dists = [float('inf') for _ in range(n)]
        mst_set = {0}
        for i, dist in graph[0]:
            min_dists[i] = min(min_dists[i], dist)
        
        total_dist = 0
        for _ in range(n-1):
            best_node, min_dist = find_best_node(min_dists, mst_set)
            mst_set.add(best_node)
            update_min_dists(best_node, min_dists, graph)
            total_dist += min_dist
        
        return total_dist
            
            
            
        
        
        
        
            
        
        


class Union:
    def __init__(self, n):
        self.components = n
        self.parent = [i for i in range(n)]
    
    def find(self, i):
        if(i != self.parent[i]):
            self.parent[i] = self.find(self.parent[i])
        return self.parent[i]

    def _union(self, i, j):
        x = self.find(i)
        y = self.find(j)
        if(x != y):
            self.parent[x] = y
            self.components -= 1;
            return True
        return False
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        graph = []
        for i in range(n):
            for j in range(i + 1, n):
                d = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]) 
                graph.append([i, j, d])
        

        # sort by distance
        graph = sorted(graph, key=lambda x: x[2])
        
        k = len(graph)
        if k == 0: 
            return 0
        elif k == 1:
            return graph[0][2]

        # MST via Kruskal
        x = Union(k)
        result = 0
        for i in range(k):
            if x._union(graph[i][0], graph[i][1]):
                result += graph[i][2]
            if x.components == 1:
                return result
        return result

from heapq import *
class Solution:
    def minCostConnectPoints(self, points):
        N = len(points)
        parent = [i for i in range(N)]
        def find(v):
            while parent[v] != parent[parent[v]]:
                parent[v] = parent[parent[v]]
            return parent[v]
        dist = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        heap, total_cost = [], 0
        for u in range(N-1):
            for v in range(u+1, N):
                heappush(heap, [dist(points[u], points[v]), u, v])
        while heap:
            cost, u, v = heappop(heap)
            pu, pv = find(u), find(v)
            if pu != pv:
                parent[pu] = pv
                N -= 1
                total_cost += cost
                if N == 0:
                    break
        return total_cost

    
    
    
    
    
    
    
    
from heapq import *
class Solution:
    def minCostConnectPoints(self, points):
        dist = lambda p1, p2: abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        N = len(points)
        parent = [i for i in range(N)]
        def find(v):
            while parent[v] != parent[parent[v]]:
                parent[v] = parent[parent[v]]
            return parent[v]
        heap = []
        for i in range(N-1):
            for j in range(i+1, N):
                heappush(heap, (dist(points[i], points[j]), i, j))
        res = 0
        while heap:
            d, u, v = heappop(heap)
            pu, pv = find(u), find(v)
            if pu != pv:
                parent[pu] = pv
                res += d
                N -= 1
                if N == 0:
                    break
        return res
            


class Solution:
    def minCostConnectPoints(self, points):
        manhattan = lambda a, b, x, y: abs(a-x)+abs(b-y)
        points = sorted(points, key=lambda x: abs(x[0])+abs(x[1]))
        connected = [points[0]]
        cost = 0
        points = list([[x[0], x[1], manhattan(connected[0][0], connected[0][1], x[0], x[1])] for x in points])
        while points:
            minidx = None
            mindist = float('inf')
            for i in range(len(points)):
                x, y, dist = points[i]
                if dist < mindist:
                    mindist = dist
                    minidx = i
            mx, my, mdist = points.pop(minidx)
            cost += mdist
            for i in range(len(points)):
                x, y, dist = points[i]
                newdist = manhattan(x, y, mx, my)
                if newdist < dist:
                    points[i][2] = newdist
        return cost


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
    #没有现成的edge list，想到当遍历到某一个点才现算它与其他点的权重值并压进pqueue，故考虑首选Prim算法而不是Krusal
    # N = len(points)
    # dsu = list(range(N))
    # def find(i):
    #     if dsu[i] != i: dsu[i] = find(dsu[i])
    #     return dsu[i]
    # def union(i, j):
    #     dsu[find(j)] = find(i)
    
        N = len(points)
        seen = set()
        cost = 0
        cnt = 0
        pq = [(0, 0)]
        while pq:
            c, i = heapq.heappop(pq)
            if i in seen: continue
            cost += c
            cnt += 1
            if cnt == N: return cost    #early termination. another advantage of using Prim over Krusal
            seen.add(i)
            pt_x, pt_y = points[i]
            for j in range(N):
                if j in seen: continue
                nei_x, nei_y = points[j]
                nei_c = abs(pt_x - nei_x) + abs(pt_y - nei_y)
                heapq.heappush(pq, (nei_c, j))
        return cost
        
        
        
        
        
        
        
        
        
        
        
        
#         res = 0
#         N = len(points)
#         visited = [[0] * N for _ in range(N)]
#         if len(points) == 1: return 0
#         DP = [[float('inf')] * N for _ in range(N)]
        
#         for i in range(N):
#             # min_dist = float('inf')
#             for j in range(i+1, N):
#                 # print(i, i, j)
#                 x, y = points[i], points[j]
#                 curr_dist = DP[i][j] = DP[j][i] = abs(x[0] - y[0]) + abs(x[1] - y[1])
#                 # if curr_dist < min_dist: 
#                 #     min_dist = curr_dist
#             min_dist = min(DP[i])
#             j = DP[i].index(min_dist) 
#             if not visited[i][j]:
#                 res += min_dist
#                 visited[i][j] = visited[j][i] = 1
#                 DP[i][j] = DP[j][i] = float('inf')
#             print(min_dist, DP)
#             # res += min_dist
#         return res
                


import sys
input=sys.stdin.readline

        
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:

        import math as mt
        
        re=lambda x,y:abs(x[0]-y[0])+abs(x[1]-y[1])
        ar=[]
        n=len(points)
        par=[i for i in range(len(points)+1)]
        def find(i):
            while i!=par[i]:
                i=par[i]
            return par[i]
            
            
        def join(i,j):
            a=find(i)
            b=find(j)
            if a!=b:
                par[a]=par[b]=min(a,b)
        for i in range(n):
            for j in range(i+1,n):
                    temp=re(points[i],points[j])
                    ar.append([temp,i,j])            
        ans=0
        cnt=0
        ar.sort()
        for a,b,c in ar:
            if find(b)!=find(c):
                join(b,c)
                ans+=a
                cnt+=1
            if cnt==n-1:
                break
        return ans
                
            


from collections import defaultdict
import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:

        graph = defaultdict(list)
        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                cost = manhattan(points[i], points[j])
                graph[i].append((cost, j))
                graph[j].append((cost, i))
        
        seen = [0] * (len(points)+1)
        seen[0] = 1
        q = graph[0]
        minimumCost = 0
        connectedNodes = 1
        heapq.heapify(q)
        while q:
            cost, city = heapq.heappop(q)
            if not seen[city]:
                seen[city] = 1
                minimumCost += cost
                connectedNodes += 1
                for connectingCost, neighbour in graph[city]:
                    heapq.heappush(q, (connectingCost, neighbour))
            if connectedNodes >= len(points):
                break
        return minimumCost


from typing import List
from heapq import heappop, heappush

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        visited = [False] * len(points) 
        cost = 0
        pq = [(0, 0)] #(dist, node)
        get_dist = lambda i, j : abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
        while pq:
            dist, node = heappop(pq)
            if visited[node]: continue
            else: visited[node] = True
            cost += dist
            for adj in range(len(points)):
                if not visited[adj]:
                    heappush(pq, (get_dist(node, adj), adj))                
        return cost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        cache = {}
        for i, coord in enumerate(points):
            cache[i] = coord
        
        # print(cache)

            
        def compute(p1, p2):
            x1, y1 = cache[p1]
            x2, y2 = cache[p2]
            return abs(x1-x2) + abs(y1-y2)
        
        edges = []
        for x, y in combinations(list(cache.items()), 2):
            edges.append((compute(x[0], y[0]), x[0], y[0]))
        
        # print(edges)
        
        edges.sort(reverse=True)
        
        # print(edges)
        
        ans = 0
        L = len(cache)
        
        parents = list(range(L))
        
        def union(x, y):
            parents[find(x)] = find(y)
        
        def find(x):
            if parents[x] != x:
                parents[x] = find(parents[x])
            
            return parents[x]
        
        if L == 1:
            return 0

        while edges:
            cost, n1, n2 = edges.pop()
            
            if find(n1) != find(n2):
                union(n1, n2)
                ans += cost
            
        return ans
            
            
            

#         for n, coord in cache.items():
#             print(n, parents)

#             closest_point = None
#             closest_cost = float('inf')
#             for i in range(L):
#                 if n == i:
#                     continue  # skip self

#                 dist = compute(n, i)

#                 # print('checking cost to', i, '...', dist)
#                 if dist < closest_cost:
#                     closest_cost = dist
#                     closest_point = i

#             if find(n) != find(closest_point):
#                 union(n, closest_point)
#                 cost += closest_cost
#                 print('connecting', n, 'and', closest_point)
        
#         # print(parents)
        
#         return cost


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        uf = UF(len(points))
        n = len(points)
        for i, ps in enumerate(points):
            # for j in range(i+1,):
            j = i+1
            while j < n:
                pt = points[j]
                dist = abs(ps[0]-pt[0]) + abs(ps[1]-pt[1])
                uf.addEdge(i, j, dist)
                
                j += 1
                
            # for j, pt in enumerate(points):
            #     if ps != pt:
            #         dist = abs(ps[0]-pt[0]) + abs(ps[1]-pt[1])
            #         uf.addEdge(i, j, dist)
                    
        # print(uf.g) 
        # uf.exec()
        return uf.exec()
                    
                    
class UF:
    def __init__(self, n):
        self.n = n
        self.g = []
        
    def addEdge(self, s, t, cost):
        self.g.append((s, t, cost))
        
    def find(self, x, parent):
        if parent[x] == x:
            return x
        
        return self.find(parent[x], parent)
    
    def union(self, x, y, parent, rank):
        xroot, yroot = self.find(x, parent), self.find(y, parent)
        if xroot != yroot:
            if rank[xroot] > rank[yroot]:
                parent[yroot] = xroot
                return xroot
            elif rank[xroot] < rank[yroot]:
                parent[xroot] = yroot
                return yroot
            
            else:
                parent[yroot] = xroot
                rank[xroot] += 1
                return xroot
                
        else:
            return xroot
        
    def exec(self):
        parent = [_ for _ in range(self.n)]
        rank = [0]*self.n
        # print(self.find(1, parent))
        # print(self.union(1,2, parent, rank))
        # print(self.union(1,3, parent, rank))
        # print(parent, rank)
        # print(self.g)
        self.g.sort(key = lambda edge: edge[2])
        # print(self.g)
        totalans = 0
        for edge in self.g:
            x = edge[0]
            y = edge[1]
            xroot = self.find(x, parent)
            yroot = self.find(y, parent)
            
            if xroot != yroot:
                self.union(x, y, parent, rank)
                totalans += edge[2]
                
                
        return(totalans)
                    
        

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        costs = []
        for i in range(len(points)):
            xi, yi = points[i]
            for j in range(i + 1, len(points)):
                xj, yj = points[j]
                costs.append([abs(xi - xj) + abs(yi - yj), i, j])
        costs = sorted(costs)
        
        fathers = [t for t in range(len(points))]
        def get_father(n) :
            while not fathers[n] == fathers[fathers[n]]:
                fathers[n] = fathers[fathers[n]]
            return fathers[n]
        
        res = 0
        for t in costs:
            dist, i, j = t
            if get_father(i) == get_father(j):
                continue
            fathers[get_father(j)] = get_father(i)
            res += dist
        return res

class UnionFind:
    def __init__(self,size):
        self.size = size
        self.components = size
        self.parent = [0] * size
        self.sizeArray = [0] * size
        for i in range(size):
            self.parent[i] = i
            self.sizeArray[i] = 1
        
    def find(self,a):
        while a != self.parent[a]:
            a = self.parent[a]    
        return a
    
    def unify(self, a, b):
        p_a = self.find(a)
        p_b = self.find(b)
        if p_a == p_b:
            return
        if self.sizeArray[p_a] < self.sizeArray[p_b]:
            self.sizeArray[p_b] += self.sizeArray[p_a]
            self.parent[p_a] = p_b
        else:
            self.sizeArray[p_a] += self.sizeArray[p_b]
            self.parent[p_b] = p_a
        
        self.components -= 1
        
    def num_components(self):
        return self.components
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        n = len(points)
        
        _map = {}
        k = 0
        for p in points:
            _map[(p[0], p[1])] = k
            k += 1
        
        for i in range(n):
            for j in range(i + 1, n):
                u = points[i]
                v = points[j]
                dist = abs(u[0] - v[0]) + abs(u[1] - v[1])
                edges.append((u, v, dist))
                
        edges.sort(key=lambda x:x[2])
        #print(edges)
        
        ds = UnionFind(n)
        
        min_cost = 0
        
        for edge in edges:
            u = _map[(edge[0][0], edge[0][1])]
            v = _map[(edge[1][0], edge[1][1])]
            d = edge[2]
            
            if ds.find(u) != ds.find(v):
                ds.unify(u, v)
                min_cost += d
        
        return min_cost

class Solution:
    def minCostConnectPoints(self, points):
        helper = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        points = [[p, helper(p, points[0])] for p in points]
        total_cost = 0
        while points:
            minI, minD = None, float('inf')
            for i, (p, d) in enumerate(points):
                if d < minD:
                    minI, minD = i, d
            p1, cost = points.pop(minI)
            total_cost += cost
            for i, (p2, _) in enumerate(points):
                points[i][1] = min(points[i][1], helper(p1, p2))
        return total_cost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # minimum spanning tree?
        n = len(points)
        
        cost = []
        for i in range(n):
            for j in range(i + 1, n):
                if i != j:
                    x1, y1 = points[i]
                    x2, y2 = points[j]
                    cost.append([abs(x1-x2) + abs(y1-y2), i, j])
        cost.sort()
    
        parent = [i for i in range(n)]
        rank = [1 for _ in range(n)]
        def find(parent, i): 
            if parent[i] == i: 
                return i 
            return find(parent, parent[i]) 

        def union(parent, rank, x, y): 
            xroot = find(parent, x) 
            yroot = find(parent, y) 

            if rank[xroot] < rank[yroot]: 
                parent[xroot] = yroot 
            elif rank[xroot] > rank[yroot]: 
                parent[yroot] = xroot 
            else : 
                parent[yroot] = xroot 
                rank[xroot] += 1
         
        i, e = 0, 0
        ans = 0
        while e < n - 1:
            w, u, v = cost[i]
            i += 1
            x = find(parent, u)
            y = find(parent, v)
            
            if x != y:
                e = e + 1
                ans += w
                union(parent, rank, x, y)
    
        return ans


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        for i in range(len(points)):
            for j in range(i+1,len(points)):
                d = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((d, i, j))            
        edges.sort()
        parent={i : i for i in range(len(points))}
        def find(x):
            if not parent[x]== x:
                parent[x] =find(parent[x])
            return parent[x]    
            
            
        def union(x,y):
            par_x=find(x)
            par_y=find(y)
            if not par_x == par_y:
                parent[par_x] =parent[par_y]
                return True
            return False
        res = 0
        for d, u, v in edges:
            if union(u, v):
                res += d
        return res


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points)==1:
            return 0
        d=collections.defaultdict(int)
        dmn=collections.defaultdict(int)
        n=len(points)
        def distance(a,b):
            return abs(a[0]-b[0])+abs(a[1]-b[1])
        res=0
        start=[0,float(\"inf\")]
        for i in range(n):
            dmn[i]=0
            for j in range(i+1,n):
                d[(i,j)]=distance(points[i],points[j])
                if d[(i,j)]<start[1]:
                    start[1]=d[(i,j)]
                    start[0]=(i,j)
        a=start[0][0]
        b=start[0][1]
        del dmn[a]
        del dmn[b]
        res+=start[1]
        
        for k in dmn.keys():
            dmn[k]=min(d[(min(k,a),max(k,a))],d[(min(k,b),max(k,b))])
        n-=2
        
        while n>0:
            nxDistance=float(\"inf\")
            for k in dmn.keys():
                if dmn[k]<nxDistance:
                    nx=k
                    nxDistance=dmn[k]
            res+=nxDistance
            del dmn[nx]
            for k in dmn.keys():
                dmn[k]=min(dmn[k],d[(min(k,nx),max(k,nx))])
            n-=1
        return res
                        

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        import heapq
        stack = []
        ans = 0
        used = set([0])
        ps = set([0])
        
        while ps:
            i = ps.pop()
            for j in range(len(points)):
                if i!=j and j not in used:
                    dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                    heappush(stack, (dist, i, j))
                    

            while stack:
                dist,x,y = heappop(stack)

                if x in used and y not in used:
                    ans += dist
                    used.add(y)
                    ps.add(y)
                    break

                elif y in used and x not in used:
                    ans += dist
                    used.add(x)
                    ps.add(x)
                    break

        return ans



import heapq

class Solution:
    def minCostConnectPoints(self, P: List[List[int]]) -> int:
        p = P[0]
        q = []
        for x, y in P[1:]:
            d = abs(x - p[0]) + abs(y - p[1])
            heapq.heappush(q, (d, x, y))
            
        seen = {(p[0], p[1])}
        res = 0
        while q:
            d, x, y = heapq.heappop(q)
            if (x, y) in seen:
                continue
            res += d
            seen.add((x, y))
            for x1, y1 in P:
                if (x1, y1) not in seen:
                    d = abs(x1 - x) + abs(y1 - y)
                    heapq.heappush(q, (d, x1, y1))
                    
        return res


class UnionFind:
    def __init__(self, n):
        self.sets = {i : i for i in range(n)}
        self.n_sets = n
    def find(self, s):
        if self.sets[s] != s:
            self.sets[s] = self.find(self.sets[s])
        return self.sets[s]
    def union(self, s1, s2):
        a, b = self.find(s1), self.find(s2)
        if a == b:
            return False
        self.sets[a] = b
        self.n_sets -= 1
        return True
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        N = len(points)
        for i in range(N):
            for j in range(i + 1, N):
                p1, p2 = points[i], points[j]
                edges.append((abs(p1[0] - p2[0]) + abs(p1[1] - p2[1]), i, j))
        edges.sort()
        uf = UnionFind(N)
        res = 0
        for w, u, v in edges:
            if uf.union(u, v):
                res += w
            # if uf.n_sets == 1:
            #     break
        return res

class DJSet:
    def __init__ (self, n):
        self.par = [i for i in range(n)]
        self.size = [1 for i in range(n)]
        
    def find(self, x):
        if self.par[x] != x:
            self.par[x] = self.find(self.par[x])
        return self.par[x]
    
    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        if px == py:
            return False
        if self.size[px] < self.size[py]:
            px, py = py, px
        self.par[py] = px
        self.size[px] += self.size[py]
        return True

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        a = []
        
        for i in range(n):
            for j in range(i+1, n):
                a.append((abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1]), i, j))
        
        a.sort()
        
        ans = 0
        djSet = DJSet(n)
        for (v, i, j) in a:
            if djSet.union(i, j):
                ans += v
        
        return ans
        
        
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) <= 1: 
            return 0
        res = 0
        seen = set()
        seen.add((points[0][0],points[0][1]))
        minD = []
        for i in range(len(points)):
            if (points[i][0],points[i][1]) not in seen:
                heapq.heappush(minD,(abs(points[i][0]-points[0][0]) + 
                                     abs(points[i][1]-points[0][1]),
                                     [points[i][0],points[i][1]]
                                    )
                              )
        while len(seen) < len(points):
            while minD:
                curMinD = heapq.heappop(minD)
                if (curMinD[1][0],curMinD[1][1]) not in seen:
                    break
            
            res += curMinD[0]
            seen.add((curMinD[1][0],curMinD[1][1]))
            for i in range(len(points)):
                if (points[i][0],points[i][1]) not in seen:
                    heapq.heappush(minD,(abs(points[i][0]-curMinD[1][0]) + 
                                         abs(points[i][1]-curMinD[1][1]),
                                         [points[i][0],points[i][1]]
                                        )
                                   )
                
        
        
        
        return res
                            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        edges = []
        parent = [x for x in range(N)]

        def ufind(x):
            if parent[x] != x:
                parent[x] = ufind(parent[x])
            return parent[x]
        
        def uunion(x, y):
            ux = ufind(x)
            uy = ufind(y)
            
            parent[ux] = uy
        
        def dist(a, b):
            return abs(points[a][0] - points[b][0]) + abs(points[a][1] - points[b][1])
        
        for i in range(N):
            for j in range(i + 1, N):
                edges.append((dist(i,j), i, j))

        edges.sort()

        total = 0
        for cost, x, y in edges:
            if ufind(x) != ufind(y):
                uunion(x, y)
                total += cost
        return total

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
    #没有现成的edge list，想到当遍历到某一个点才现算它与其他点的权重值并压进pqueue，故考虑首选Prim算法而不是Krusal
    # N = len(points)
    # dsu = list(range(N))
    # def find(i):
    #     if dsu[i] != i: dsu[i] = find(dsu[i])
    #     return dsu[i]
    # def union(i, j):
    #     dsu[find(j)] = find(i)
    
        N = len(points)
        seen = set()
        cost = 0
        cnt = 0
        pq = [(0, 0)]
        while pq:
            c, i = heapq.heappop(pq)
            if i in seen: continue
            cost += c
            cnt += 1
            if cnt == N: return cost
            seen.add(i)
            pt_x, pt_y = points[i]
            for j in range(N):
                if j in seen: continue
                nei_x, nei_y = points[j]
                nei_c = abs(pt_x - nei_x) + abs(pt_y - nei_y)
                heapq.heappush(pq, (nei_c, j))
        return cost
        
        
        
        
        
        
        
        
        
        
        
        
#         res = 0
#         N = len(points)
#         visited = [[0] * N for _ in range(N)]
#         if len(points) == 1: return 0
#         DP = [[float('inf')] * N for _ in range(N)]
        
#         for i in range(N):
#             # min_dist = float('inf')
#             for j in range(i+1, N):
#                 # print(i, i, j)
#                 x, y = points[i], points[j]
#                 curr_dist = DP[i][j] = DP[j][i] = abs(x[0] - y[0]) + abs(x[1] - y[1])
#                 # if curr_dist < min_dist: 
#                 #     min_dist = curr_dist
#             min_dist = min(DP[i])
#             j = DP[i].index(min_dist) 
#             if not visited[i][j]:
#                 res += min_dist
#                 visited[i][j] = visited[j][i] = 1
#                 DP[i][j] = DP[j][i] = float('inf')
#             print(min_dist, DP)
#             # res += min_dist
#         return res
                


import math
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        edges = set()
        for i in range(n):
            p = points[i]
            for j in range(n):
                if i!=j:
                    w = abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                    e = (min(i,j),max(i,j),w)
                    edges.add(e)
        edges = sorted(edges, key = lambda x: x[2])
        tree_id = [0]*n
        for i in range(n):
            tree_id[i] = i
        cost = 0
        for i in edges:
            v1 = i[0]
            v2 = i[1]
            w = i[2]
            if tree_id[v1] != tree_id[v2]:
                cost += w
                old_tree = tree_id[v1]
                new_tree = tree_id[v2]
                for j in range(n):
                    if tree_id[j] == old_tree:
                        tree_id[j] = new_tree
        return cost
            
        
        
        
                    


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)

        edges = []
        for i in range(n - 1):
            for j in range(i + 1, n):
                u, v = points[i]
                p, q = points[j]
                w = abs(u - p) + abs(v - q)
                edges.append([w, i, j])

        path = [u for u in range(n)]

        def find(u: int) -> int:
            if path[u] != u:
                path[u] = find(path[u])
            return path[u]

        def union(u: int, v: int) -> bool:
            i, j = find(u), find(v)
            if i == j: return False
            if j > i:
                i, j = j, i
            path[j] = i
            return True

        costs = 0
        edges.sort()
        for w, u, v in edges:
            if find(u) != find(v):
                costs += w
                union(u, v)
        return costs


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        mst = set()
        mst.add(0)
        md = 0
        pq = []
        for i in range(n):
            if i not in mst:
                distance = abs(points[0][0] - points[i][0]) + abs(points[0][1] - points[i][1])
                heapq.heappush(pq, (distance, 0, i))
        
        while pq:
            distance, a, b = heapq.heappop(pq)
            if b not in mst:
                mst.add(b)
                md += distance
                for i in range(n):
                    if i not in mst:
                        distance = abs(points[b][0] - points[i][0]) + abs(points[b][1] - points[i][1])
                        heapq.heappush(pq, (distance, b, i))
        
        return md

class DSU:
    def __init__(self,N):
        self.sz = [1]*N
        self.par = list(range(N))
        
    def find(self,v):
        if self.par[v] != v:
            self.par[v] = self.find(self.par[v])
        return self.par[v]

    def union(self,u,v):
        px = self.find(u)
        py = self.find(v)
        if px == py:
            return False
        if self.sz[px] < self.sz[py]:
            px,py = py,px
        self.par[py] = px
        self.sz[px] += self.sz[py]
        return True
    
    def size(self,x):
        return self.sz[self.find(x)]
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        edges = []
        dsu = DSU(N)
        for i in range(N):
            for j in range(i+1,N):
                d = abs(points[i][0] - points[j][0])
                d += abs(points[i][1] - points[j][1])
                edges.append([i,j,d])
        edges.sort(key = lambda key :key[2])
        ans = 0
        for u,v,d in edges:
            if dsu.union(u,v):
                ans += d
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        graph=[]

        def getDistance(p1,p2):
            return abs(p1[0]-p2[0])+abs(p1[1]-p2[1])
        
        for i in range(len(points)):
            for j in range(i+1,len(points)):
                graph.append((i,j,getDistance(points[i],points[j])))
            
        
        graph.sort(key = lambda x: x[2])
        
        rank=[1]*len(points)
        parent=list(range(len(points)))
        
        def getParent(parent, n):
            if parent[n]==n:
                return n
            value=getParent(parent,parent[n])
            parent[n]=value
            return value
        
        def union(parent,rank,n1,n2):
            if rank[n1]>=rank[n2]:
                parent[n2]=n1
                rank[n1]+=rank[n2]
            else:
                parent[n1]=n2
                rank[n2]+=rank[n1]
                
        min_cost=0
        
        for edge in graph:
            
            u,v,cost=edge
            
            paru=getParent(parent,u)
            parv=getParent(parent,v)
            
            if parv!=paru:
                min_cost+=cost
                union(parent,rank,paru,parv)
        return min_cost
            
            


from queue import PriorityQueue

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        graph = [[-1] * n for _ in range(n)]
        for u in range(n):
            for v in range(n):
                graph[u][v] = abs(points[u][0]-points[v][0]) + abs(points[u][1]-points[v][1])
        
        res = 0
        dists = [float(\"inf\")] * n
        parents = [-1] * n
        mst = set()
        pq = PriorityQueue()
        dists[0] = 0
        pq.put([0, 0])
        while len(mst) < n:
            dist, u = pq.get()
            if u not in mst:
                res += dist
                mst.add(u)
            for v in range(n):
                if dists[v] > graph[u][v]:
                    dists[v] = graph[u][v]
                    parents[v] = u
                    pq.put([dists[v], v])
        return res
        
        

class UF:
  def __init__(self, n):
    self.parent = {i:i for i in range(n)}
  
  def find(self, a):
    if a != self.parent[a]:
      self.parent[a] = self.find(self.parent[a])
    return self.parent[a]
  
  def union(self, a, b):
    r_a = self.find(a)
    r_b = self.find(b)
    if r_a == r_b:
      return False
    self.parent[r_a] = r_b
    return True
  
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        n = len(points)
        for i in range(n):
          for j in range(i):
            dis = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
            edges.append((dis, i, j))
        edges.sort()
        cost = 0
        uf = UF(n)
        for dis, i, j in edges:
          if uf.union(i,j):
            cost += dis
        return cost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def get_dist(p1, p2):
            x1, y1 = p1
            x2, y2 = p2
            return abs(x1 - x2) + abs(y1 - y2)

        N = len(points)
        res = 0
        minheap = [(0, 0)]
        seen = set()
        while minheap:
            dist, p = heapq.heappop(minheap)
            if p in seen:
                continue
            res += dist
            seen.add(p)
            for i in range(N):
                if i not in seen:
                    heapq.heappush(minheap, (get_dist(points[p], points[i]), i))
        return res


from heapq import *
class Solution:
    def minCostConnectPoints(self, points):
        n = len(points)
        dist = lambda p0, p1: abs(p1[0] - p0[0]) + abs(p1[1] - p0[1])
        q = [(0, 0)]
        nodes = set(range(len(points)))
        res = 0
        while q:
            d, u = heappop(q)
            if u not in nodes:
                continue
            nodes.remove(u)
            res = res + d
            if len(nodes) == 0:
                return res
            for v in nodes:
                w = dist(points[u], points[v])
                heappush(q, (w, v))

class DSU: 
    def __init__(self, n): 
        self.p = list(range(n))
        self.r = [0] * n
    def find(self, i): 
        if self.p[i] != i:
            self.p[i] = self.find(self.p[i])
        return self.p[i]
    def union(self, i, j): 
        pi, pj = self.find(i), self.find(j)
        if pi != pj: 
            if self.r[pi] >= self.r[pj]: 
                self.p[pj] = pi
                self.r[pi] += (self.r[pi] == self.r[pj])
            else: 
                self.p[pi] = pj
            return True
        return False

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # try minimum spanning treee
        
        to_visit = set(range(1, len(points)))
        pq = [(abs(points[0][0] - points[x][0]) + abs(points[0][1] - points[x][1]), x) for x in range(1, len(points))]
        heapq.heapify(pq)
        ans = 0
        while pq:
            cost, to = heapq.heappop(pq)
            if to in to_visit:
                to_visit.remove(to)
                ans += cost
                for nei in to_visit:
                    x, y = points[nei]
                    heapq.heappush(pq, (abs(x-points[to][0]) + abs(y-points[to][1]), nei))

        return ans
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges, ans = [], 0
        for i in range(len(points)):
            for j in range(i+1, len(points)): 
                edges.append((abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]), i, j))
                
        edges.sort()
        uf = DSU(len(points))
        for cost, i, j in edges: 
            if uf.find(i) != uf.find(j): 
                uf.union(i, j)
                ans += cost
        return ans
        
                
        
            
            



class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n=len(points)
        uf=list(range(n))
        def find(x):
            if uf[x]!=x:
                uf[x]=find(uf[x])
            return uf[x]
        def union(x,y):
            uf[find(x)]=find(y)
        costs=[]
        for i in range(n-1):
            for j in range(i+1,n):
                x1,y1=points[i]
                x2,y2=points[j]
                cost=abs(x1-x2)+abs(y1-y2)
                costs.append([cost,i,j])
        costs.sort()
        res=0
        for cost,i,j in costs:
            if find(i)!=find(j):
                union(i,j)
                res+=cost
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        diss = [[0] * n for _ in range(len(points))]
        res = 0
        
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                length = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                diss[i][j] = diss[j][i] = length
        
        disinfo = []
        for info in diss:
            tmp = []
            for i, l in enumerate(info):
                tmp.append((l, i))
            tmp.sort(reverse=True)
            disinfo.append(tmp)
        
        not_linked = set(range(1, len(points)))
        min_dis = diss[0].copy()
        min_dis[0] = math.inf
        
        while not_linked:
            nxt_dis = min(min_dis)
            res += nxt_dis
            nxt = min_dis.index(nxt_dis)
            not_linked.remove(nxt)
            min_dis[nxt] = math.inf

            for i in range(len(points)):
                if min_dis[i] < math.inf:
                    min_dis[i] = min(diss[nxt][i], min_dis[i])
                    
        return res
                
            


# mst
# sort edge->union find
# choose min that is not connected
def distance(u,v):
    return abs(u[0]-v[0])+abs(u[1]-v[1])
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        distances = []
        n = len(points)
        mini = 0
        parent = [i for i in range(n)]
        for i in range(n):
            for j in range(i+1,n):
                u,v = points[i], points[j]
                dis = distance(u,v)
                distances.append((dis,i,j))
        distances.sort() # distance, u, v
        
        def find(i):
            while i!=parent[i]:
                parent[i] = parent[parent[i]]
                i = parent[i]
            return i
        
        def union(i,j):
            a,b = find(i),find(j)
            if a==b:
                return False
            else:
                parent[a] = b
                return True
            
        for cost,i,j in distances:
            if union(i,j):
                mini+=cost
            else:
                mini+=0
            
        return mini
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def dist(e1, e2):
            return abs(e1[0]-e2[0])+abs(e1[1]-e2[1])
        
        def find(x):
            while x in uf:
                # path compress
                while uf[x] in uf:
                    uf[x] = uf[uf[x]]
                x = uf[x]
            return x
        
        def union(x,y):
            px,py = find(x), find(y)
            if px==py: return False
            uf[px] = py
            return True
        
        n = len(points)
        res = 0
        uf = {}
        edges = []
        for i in range(n):
            for j in range(i+1,n):
                edges.append([dist(points[i],points[j]),i,j])
                
        edges.sort()
        for cost,x,y in edges:
            if union(x,y):
                res += cost
                
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        uf = UF(len(points))
        n = len(points)
        for i, ps in enumerate(points):
            j = i+1
            while j < n:
                pt = points[j]
                dist = abs(ps[0]-pt[0]) + abs(ps[1]-pt[1])
                uf.addEdge(i, j, dist)
                j += 1
                
        return uf.KruskalMST()
                    
                    
class UF:
    def __init__(self, n):
        self.n = n
        self.g = []
        
    def addEdge(self, s, t, cost):
        self.g.append((s, t, cost))
        
    def find(self, x, parent):
        if parent[x] == x:
            return x
        
        return self.find(parent[x], parent)
    
    def union(self, x, y, parent, rank):
        xroot, yroot = self.find(x, parent), self.find(y, parent)
        if xroot != yroot:
            if rank[xroot] > rank[yroot]:
                parent[yroot] = xroot
                return xroot
            elif rank[xroot] < rank[yroot]:
                parent[xroot] = yroot
                return yroot
            
            else:
                parent[yroot] = xroot
                rank[xroot] += 1
                return xroot
                
        else:
            return xroot
        
    def KruskalMST(self):
        parent = [_ for _ in range(self.n)]
        rank = [0]*self.n
        # print(self.find(1, parent))
        # print(self.union(1,2, parent, rank))
        # print(self.union(1,3, parent, rank))
        # print(parent, rank)
        # print(self.g)
        self.g.sort(key = lambda edge: edge[2])
        # print(self.g)
        totalans = 0
        for edge in self.g:
            x = edge[0]
            y = edge[1]
            xroot = self.find(x, parent)
            yroot = self.find(y, parent)
            
            if xroot != yroot:
                self.union(x, y, parent, rank)
                totalans += edge[2]
                
                
        return(totalans)
                    


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        return self.minCost(points)
    
    
    def minCost(self, points):
        \"\"\"
        
        mst approach
        
        \"\"\"
        n=len(points)
        mst = {0}
        nodes = {idx:cod for idx, cod in enumerate(points)}
        dist = lambda x,y: abs(x[0]-y[0])+abs(x[1]-y[1])
        edges =[]
        for u in range(n): # outdegree of u -- outdegree*heappush time
            heapq.heappush(edges, (dist(nodes[0], nodes[u]), u))
        
        minCostConnect = 0
        while edges:
            far, v = heapq.heappop(edges)
            if v in mst:
                continue
            minCostConnect+=far
            mst.add(v)
            for v_ in range(n):
                if v_ not in mst:
                    heapq.heappush(edges, (dist(nodes[v], nodes[v_]), v_))
        return minCostConnect

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n==1:
            return 0
        vis = set()
        points = list(map(tuple, points))
        q = [(0, points[0])]
        res = 0
        def get_dist(pointa, pointb):
            return abs(pointa[0]-pointb[0]) + abs(pointa[1]-pointb[1])
        while q:
            top, curr_pt = heappop(q)
            if curr_pt in vis:
                continue
            vis.add(curr_pt)
            res += top
            for point in set(points) - vis:
                heappush(q, (get_dist(curr_pt, point), point))
        
        return res


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        ln=len(points)
        if ln<=1:return 0
        ans=0
        par={}
        def find(x):
            if x not in par:return x
            res=find(par[x])
            par[x]=res
            return res
        def union(a,b):
            n1=find(a)
            n2=find(b)
            if n1!=n2:
                if n1<n2:
                    par[n2]=n1
                else:
                    par[n1]=n2
        arr=[]
        for i in range(ln-1):
            for j in range(i+1,ln):
                n=abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                arr.append((n,i,j))
        arr.sort()
        for x in arr:
            i=x[1]
            j=x[2]
            n1=find(i)
            n2=find(j)
            if n1!=n2:
                if n1<n2:
                    par[n2]=n1
                else:
                    par[n1]=n2
                ans+=x[0]
        return ans 

class Solution:
    def _dist(self, a, b):
        return abs(a[0] - b[0]) + abs(a[1] - b[1])
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        result = 0
        comp = [points[0]]
        h = []
        
        for i in range(1, len(points)):
            heapq.heappush( h, [self._dist(points[0], points[i]), points[i]] )
        
        while h:
            dist, p = heapq.heappop(h)
            result += dist
            
            for i in range(len(h)):
                h[i][0] = min( h[i][0], self._dist(p, h[i][1]) )
            heapq.heapify(h)
        return result

from collections import deque, defaultdict
from heapq import heappush, heappop

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        n, c = len(points), collections.defaultdict(list)
        for i in range(n):
            for j in range(i+1, n):
                d = manhattan(points[i], points[j])
                c[i].append((d, j))
                c[j].append((d, i))
        cnt, ans, visited, heap = 1, 0, [0] * n, c[0]
        visited[0] = 1
        heapq.heapify(heap)
        while heap:
            d, j = heapq.heappop(heap)
            if not visited[j]:
                visited[j], cnt, ans = 1, cnt+1, ans+d
                for record in c[j]: heapq.heappush(heap, record)
            if cnt >= n: break        
        return ans
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) <= 1:
            return 0
        
        def find(x):
            if x != parent[x]:
                parent[x] = find(parent[x])
                return parent[x]
            
            return x
                
        n = len(points)
                
        parent = list(range(n))
        
        dists = []
        
        for i in range(n - 1):
            for j in range(i + 1, n):
                mand = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                dists.append((mand, i, j))
                
        dists.sort(key=lambda item: item[0])
        
        res = 0
        
        for w, a, b in dists:
            pa = find(a)
            pb = find(b)
            
            if pa != pb:
                res += w
                parent[pa] = parent[pb]
                    
        return res

def manhattan(coor1, coor2):
        return abs(coor1[0] - coor2[0]) + abs(coor1[1] - coor2[1])

def find(C, u):
    if C[u] != u:
        C[u] = find(C, C[u])
    return C[u]

def naive_union(C, u, v):
    u, v = find(C, u), find(C, v)
    C[u] = v

class Solution(object):
    def minCostConnectPoints(self, points):
        \"\"\"
        :type points: List[List[int]]
        :rtype: int
        \"\"\"
        edges = [(manhattan(points[u], points[v]), u, v) for u in range(len(points) - 1) for v in range(u + 1, len(points))]
        edges = sorted(edges)
        C = {u: u for u in range(len(points))}
        res = 0
        for dis, u, v in edges:
            if find(C, u) != find(C, v):
                naive_union(C, u, v)
                res += dis
        return res

class dsu:
    def __init__(self, n):
        self.ranks = [0] * n
        self.ids = list(range(n))
        pass
    
    def find(self, x):
        if x != self.ids[x]:
            self.ids[x] = self.find(self.ids[x])
            pass
        return self.ids[x]
    
    def union(self, x, y):
        rx = self.find(x)
        ry = self.find(y)
        if rx == ry:
            return False
        elif self.ranks[rx] == self.ranks[ry]:
            self.ids[ry] = rx
            self.ranks[rx] += 1
            pass
        elif self.ranks[rx] < self.ranks[ry]:
            self.ids[rx] = ry
            pass
        else:
            self.ids[ry] = rx
            pass
        return True
        

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        d = dsu(len(points))
        lst = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1]-points[j][1])
                t = (dist, i, j)
                lst.append(t)
                pass
            pass
        lst.sort()
        cost = 0
        for i in range(len(lst)):
            success = d.union(lst[i][1], lst[i][2])
            if success:
                cost += lst[i][0]
                pass
            pass
        return cost


class Union:
    def __init__(self,vertices):
        self.parent = [i for i in range(vertices)]
    
    def find(self,i):
        if self.parent[i]!=i:
            return self.find(self.parent[i])
        return self.parent[i]
    
    def union(self,i,j):
        x=self.find(i)
        y=self.find(j)
        self.parent[x]=y
        
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n=len(points)
        uf = Union(n)
        def dist(x,y):
            return abs(x[0]-y[0])+abs(x[1]-y[1])
        costs=[]
        for i in range(n):
            for j in range(n):
                costs.append([i,j,dist(points[i],points[j])])
        costs=sorted(costs,key=lambda x:x[2])
        ans=0
        i=0
        s=0
        while s<n-1:
            u,v,cost=costs[i]
            i+=1
            x=uf.find(u)
            y=uf.find(v)
            if x!=y:
                uf.union(x,y)
                s+=1
                ans+=cost
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def find(x):
            if x==parent[x]:
                return x
            return find(parent[x])
        def union(p,q):
            x=find(p)
            y=find(q)
            if rank[x]<rank[y]:
                parent[x]=y
            elif rank[y]<rank[x]:
                parent[y]=x
            else:
                parent[y]=x
                rank[x]+=1
        n=len(points)
        graph=[]
        parent={}
        rank={}
        for i in range(n):
            for j in range(i+1,n):
                w=abs(points[j][1]-points[i][1])+abs(points[j][0]-points[i][0])
                graph.append([i,j,w])
        edges=sorted(graph,key=lambda k:k[2])
        for i in range(n):
            parent[i]=i
            rank[i]=0
        ans=0
        #print(edges,parent,rank)
        for x,y,w in edges:
            if find(x)!=find(y):
                #print(x,y,w)
                ans+=w
                union(x,y)
        return ans 
                


class Solution:
    def find(self, parent, i): 
        if parent[i] == i: 
            return i 
        return self.find(parent, parent[i]) 

    def union(self, parent, rank, x, y): 
        xroot = self.find(parent, x) 
        yroot = self.find(parent, y) 
        if rank[xroot] < rank[yroot]: 
            parent[xroot] = yroot 
        elif rank[xroot] > rank[yroot]: 
            parent[yroot] = xroot 
        else : 
            parent[yroot] = xroot 
            rank[xroot] += 1

    def KruskalMST(self, V, graph): 
        wts = 0
        i = 0 
        e=0
        graph = sorted(graph,key=lambda item: item[2]) 
        parent, rank = [], [] 

        for node in range(V): 
            parent.append(node) 
            rank.append(0) 

        while e < V -1 : 
            u,v,w = graph[i] 
            i = i + 1
            x = self.find(parent, u) 
            y = self.find(parent ,v) 

            if x != y: 
                e+=1
                wts += w
                self.union(parent, rank, x, y)\t\t\t 
        return wts
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        v = len(points)
        edges = []
        for e1, i in enumerate(points):
            for e2, j in enumerate(points):
                if e1!=e2:
                    edges.append([e1, e2, (abs(i[0]-j[0])+abs(i[1]-j[1]))])
        return (self.KruskalMST(v, edges))





class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        n, c = len(points), collections.defaultdict(list)
        for i in range(n):
            for j in range(i+1, n):
                d = manhattan(points[i], points[j])
                c[i].append((d, j))
                c[j].append((d, i))
        cnt, ans, visited, heap = 1, 0, [0] * n, c[0]
        visited[0] = 1
        heapq.heapify(heap)
      
        while heap:
            d, j = heapq.heappop(heap)
            if not visited[j]:
                visited[j], cnt, ans = 1, cnt+1, ans+d
                for record in c[j]: heapq.heappush(heap, record)
            if cnt >= n: break        
        return ans

class UFDS:
    def __init__(self, n):
        self.p = list(range(n))
    
    def find(self, k):
        if self.p[k] == k: return k
        self.p[k] = self.find(self.p[k])
        return self.p[k]
    
    def issame(self, i, j):
        return self.find(i) == self.find(j)
    
    def union(self, i, j):
        pi, pj = self.find(i), self.find(j)
        if pi == pj: return
        if pi < pj:
            self.p[pj] = pi
        else:
            self.p[pi] = pj
    

class Solution:
    def minCostConnectPoints(self, A: List[List[int]]) -> int:
        
        def dist(a, b):
            return abs(a[0] - b[0]) + abs(a[1] - b[1])
        
        n = len(A)
        
        dists = []
        
        for i in range(n):
            for j in range(i+1, n):
                dists.append((dist(A[i], A[j]), (i, j)))
        
        dists.sort()
        ufds = UFDS(n)
        
        total = 0
        for d, (i, j) in dists:
            if not ufds.issame(i, j):
                total += d
                ufds.union(i, j)
        
        
        return total
        
        


class Solution:
    
    class UnionFinder:
        def __init__(self, n):
            self.parents = list(range(n))
            self.ranks = [0] * n
        
        def find(self, x):
            if self.parents[x] != x:
                self.parents[x] = self.find(self.parents[x])
            return self.parents[x]
        
        def join(self, x, y):
            p1 = self.find(x)
            p2 = self.find(y)
            
            if p1 == p2:
                return False
            
            r1 = self.ranks[p1]
            r2 = self.ranks[p2]
            
            if r1 < r2:
                self.parents[p1] = p2
            elif r2 < r1:
                self.parents[p2] = p1
            else:
                self.parents[p1] = p2
                self.ranks[p2] += 1
            return True
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        heap = list()
        cnt = 0
        
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                heapq.heappush(heap, (abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]), i, j))
                
        union_finder = Solution.UnionFinder(len(points))
        ans = 0
        while heap:
            d, i, j = heapq.heappop(heap)
            if union_finder.join(i, j):
                ans += d
                cnt += 1
                if cnt == len(points) - 1:
                    break
        return ans


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def hamin(a, b):
            return abs(a[0] - b[0]) + abs(a[1] - b[1])
        # dist_list = []
        # for i in range(len(points)):
        #     for j in range(i+1, len(points)):
        #         dist_list.append([hamin(points[i], points[j]), i, j])
        # dist_list = sorted(dist_list, key=lambda x:(x[0]))
        # group_set_list = [set()]
        # answer = 0
        # for dis, x, y in dist_list:
        #     if x not in group_set_list[0] or y not in group_set_list[0]:
        #         answer += dis
        #         group_set_list.append(set([x, y]))
        #     new_group_set_list = [group_set_list[0]]
        #     for i in range(1, len(group_set_list)):
        #         if new_group_set_list[0] & group_set_list[i]:
        #             new_group_set_list[0] |= group_set_list[i]
        #         else:
        #             new_group_set_list.append(group_set_list[i])
        #     group_set_list = new_group_set_list
        #     if len(group_set_list[0]) == len(points):
        #         break
        # return answer
        dist_list = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                dist_list.append([hamin(points[i], points[j]), i, j])
        dist_list = sorted(dist_list, key=lambda x:(x[0]))
        #print(dist_list)
        group_set = set()
        group_set.add(0)
        answer = 0
        while(True):
            i = 0
            while(i < len(dist_list)):
                [dis, x, y] = dist_list[i]
                if x in group_set and y in group_set:
                    dist_list.pop(i)
                    continue
                if x in group_set:
                    group_set.add(y)
                    answer += dis
                    break
                if y in group_set:
                    group_set.add(x)
                    answer += dis
                    break
                i += 1
            if len(group_set) == len(points):
                break
        return answer

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N=len(points)
        edges=[]
        res=0
        for i in range(N):
            for j in range(i+1, N):
                distance=abs(points[i][0]-points[j][0])
                distance +=abs(points[i][1]-points[j][1])
                edges.append((distance, i, j))
        edges.sort()
        unionfind=UnionFind(N)
        for edge in edges:
            dis, i, j=edge
            if unionfind.union(i, j):
                res +=dis
        return res
        

class UnionFind:
    def __init__(self, n: int):
        self.parent=list(range(n))
        self.size=[1]*n
    def find(self, x):
        if self.parent[x]!=x:
            self.parent[x]=self.find(self.parent[x])
        return self.parent[x]
    def union(self, x, y):
        rx,ry =self.find(x), self.find(y)
        if rx==ry: return False
        if self.size[rx]<self.size[y]:
            rx, ry=ry, rx
            
        self.parent[ry]=rx
        self.size[rx] +=self.size[ry]
        return True
        


from typing import List


class DSU:
    def __init__(self, N: int):
        self.par = list(range(N))
        self.sz = [1] * N
    
    def find(self, x: int) -> int:
        if self.par[x] != x:
            self.par[x] = self.find(self.par[x])
        return self.par[x]
    
    def union(self, x: int, y: int) -> bool:
        xr, yr = self.find(x), self.find(y)
        if xr == yr:
            return False
        
        if self.sz[xr] < self.sz[yr]:
            xr, yr = yr, xr
        
        self.par[yr] = xr
        self.sz[xr] += self.sz[yr]
        return True
    
    def size(self, x: int) -> int:
        return self.sz[self.find(x)]

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        \"\"\"
        Alex Wice's Solution

        DSU
        \"\"\"
        N = len(points)
        edges = []

        for i in range(N):
            for j in range(i + 1, N):
                d = abs(points[i][0] - points[j][0])
                d += abs(points[i][1] - points[j][1])
                edges.append((d, i, j))

        edges.sort()
        
        dsu = DSU(N)
        ans = 0
        for d, u, v in edges:
            if dsu.union(u, v):
                ans += d
        
        return ans

import queue 
class Solution:
    def minCostConnectPoints(self, points:List[List[int]]) -> int:
        \"\"\"
            @params:
                points: List of list of coordinates (in cartesian coordinates)
                where points[i] = [x_i, y_i]
                Are points sorted? Not necessary 
                Can there be negative integers? Yes 
                Can there be duplicate points? No 
                Points length: 1 <= len(points) <= 1000
        
                Test case 1: [[0,0], [1,2], [3,0]]
                expected_output = min((3+3), (3+4)) = 6
                y
                |     
                |
                |  1,2
                |_  _  _ _ _ x 
                0,0    3,0
                 
                Test case 2: [[0,0], [1,1], [2,2]]
                expected_output = min(4, 5) = 4 
                  y
                |     
                |      2,2
                |  1,1
                |   _    _    _ _ _ x 
                0,0           
        \"\"\"
        def manhattan(x,y):
            return abs(x[0]-y[0]) + abs(x[1]-y[1])
        
        ans = 0
        n = len(points)
        seen = set()
        minimum_distance = queue.PriorityQueue()
        minimum_distance.put((0, (0,0)))
        
        while len(seen) < n:
            w, (u,v) = minimum_distance.get()
            if u in seen and v in seen:
                continue 
            else:
                ans += w 
                seen.add(v)
                for j in range(n):
                    if j not in seen and j != v:
                        minimum_distance.put((manhattan(points[j], points[v]), (v,j)))
        return ans 
        

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        dist = lambda x, y: abs(x[0] - y[0]) + abs(x[1] - y[1])
        neighbors = collections.defaultdict(dict)
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                neighbors[i][j] = dist(points[i], points[j])
                neighbors[j][i] = dist(points[i], points[j])
        pq = [(0, 0)]
        visited = set()
        res = 0
        while len(visited) < len(points):
            d, u = heapq.heappop(pq)
            if u in visited:
                continue
            print(d, u)
            res += d
            visited.add(u)
            for v, d_ in neighbors[u].items():
                heapq.heappush(pq, (d_, v))
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # O(n^2) edges, sort them, select from low to high, and add edge to tree
        # if both sides are not in a same set.
        out= 0
        edges = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                edges += [(abs(points[i][0] - points[j][0])+ abs(points[i][1] - points[j][1]),i, j)]
        
        edges = sorted(edges, key = lambda x:x[0])
        
        p = [i for i in range(len(points))]
        
        def findparent(i):
            if i != p[i]:
                p[i] = findparent(p[i])
            return p[i]
        
        for e in edges:
            p1 = findparent(e[1])
            p2 = findparent(e[2])
            if p1 != p2:
                p[p2] = p1
                out += e[0]
        
        return out

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        ok=[-1 for i in range(len(points))]
        def union(x,y):
            x1=find(x)
            x2=find(y)
            ok[x1]=x2
        def find(x):
            if(ok[x]==-1):
                return x
            else:
                ok[x]=find(ok[x])
                return ok[x]
        d=[]
        for i in range(len(points)):
            for j in range(i+1,len(points)):
                d.append([abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1]),i,j])
        d.sort()
        ans=0
        for i in d:
            x=find(i[1])
            y=find(i[2])
            if(x!=y):
                union(i[1],i[2])
                ans+=i[0] 
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        visited = [False] * n
        
        # Prim Algo
        dist = collections.defaultdict(list)
        for i in range(n):
            p1, p2 = points[i]
            for j in range(n):
                x, y = points[j]
                dist[i].append((abs(p1-x) + abs(p2-y), j))
        visited[0] = True
        hp = dist[0]
        heapq.heapify(hp)
        res = count = 0
        while hp:
            cost, cur = heapq.heappop(hp)
            if visited[cur]: continue
            visited[cur] = True
            res += cost
            count += 1
            if count == n - 1:
                break
            for d in dist[cur]:
                heapq.heappush(hp, d)
        return res
        
        # dist = [math.inf] * n
        # cur = res = 0
        # for i in range(n-1):
        #     p1, p2 = points[cur]
        #     visited[cur] = True
        #     for j, (x, y) in enumerate(points):
        #         if not visited[j]:
        #             dist[j] = min(dist[j], abs(p1-x) + abs(p2-y))
        #     cost, cur = min([(v, k) for k, v in enumerate(dist)])
        #     dist[cur] = math.inf
        #     res += cost
        # return res



from heapq import *
class Solution:
    def minCostConnectPoints(self, points):
        n = len(points)
        dist = lambda p0, p1: abs(p1[0] - p0[0]) + abs(p1[1] - p0[1])
        q = [(0, 0)]
        nodes = set(range(n))
        res = 0
        while q:
            d, u = heappop(q)
            if u not in nodes:
                continue
            nodes.remove(u)
            res = res + d
            if len(nodes) == 0:
                return res
            for v in nodes:
                w = dist(points[u], points[v])
                heappush(q, (w, v))

import heapq

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) < 1:
          return 0
        def dist(point1, point2):
          return abs(point1[0] - point2[0]) + abs(point1[1] - point2[1])
        
        heap = []
        connected = set([0])
        for i, point in enumerate(points):
          if i == 0:
            continue
          heapq.heappush(
            heap,
            (
              dist(point, points[0]),
              i,
              0,
            )
          )
        res = 0
        while len(connected) != len(points):
          dis, p, f = heapq.heappop(heap)
          if p not in connected:
            res += dis
            connected.add(p)
            
          for i, point in enumerate(points):
            if i == p or i in connected:
              continue
            heapq.heappush(
              heap,
              (
                dist(point, points[p]),
                i,
                p,
              )
            )
        return res

class Solution:
    def minCostConnectPoints(self, points:List[List[int]]) -> int:
        \"\"\"
            @params:
                points: List of list of coordinates (in cartesian coordinates)
                where points[i] = [x_i, y_i]
                Are points sorted? Not necessary 
                Can there be negative integers? Yes 
                Can there be duplicate points? No 
                Points length: 1 <= len(points) <= 1000
        
                Test case 1: [[0,0], [1,2], [3,0]]
                expected_output = min((3+3), (3+4)) = 6
                y
                |     
                |
                |  1,2
                |_  _  _ _ _ x 
                0,0    3,0
                 
                Test case 2: [[0,0], [1,1], [2,2]]
                expected_output = min(4, 5) = 4 
                  y
                |     
                |      2,2
                |  1,1
                |   _    _    _ _ _ x 
                0,0           
        \"\"\"
        def manhattan(x, y):
            return abs(x[0]-y[0]) + abs(x[1]-y[1])
        ans, n = 0, len(points)
        seen = set()
        import queue
        q = queue.PriorityQueue()
        q.put((0, (0, 0)))
        
        while len(seen) < n:
            # print(vertices, seen)
            w, (u, v) = q.get()
            if u in seen and v in seen: continue
            ans += w
            seen.add(v)
            for j in range(n):
                if j not in seen and j!=v:
                    q.put((manhattan(points[j], points[v]), (v, j)))
        return ans

        

class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:
        
        def manhattan(x, y):
            return abs(x[0]-y[0]) + abs(x[1]-y[1])
        
        ans, n = 0, len(p)
        seen = set()
        import queue
        q = queue.PriorityQueue()
        q.put((0, (0, 0)))
        
        while len(seen) < n:
            # print(vertices, seen)
            w, (u, v) = q.get()
            if u in seen and v in seen: continue
            ans += w
            seen.add(v)
            for j in range(n):
                if j not in seen and j!=v:
                    q.put((manhattan(p[j], p[v]), (v, j)))
        return ans
                
            


class UF:
  def __init__(self, n):
    self.parent = {i:i for i in range(n)}

  def find(self, x):
    if self.parent[x] != x:
      self.parent[x] = self.find(self.parent[x])
    return self.parent[x]
  
  def union(self, a, b):
    r_a = self.find(a)
    r_b = self.find(b)
    if r_a == r_b:
      return False
    
    self.parent[r_a] = r_b
    return True
    
  
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
      n = len(points)
      edges = []
      for i in range(n):
        for j in range(i):
          dis = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
          edges.append((dis, i, j))
      edges.sort()
      count = 0
      uf = UF(n)
      
      for dis, u, v in edges:
        if uf.union(u, v):
          count += dis
      return count

class DisjointSet:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
    
    # return if parent is same, else update     
    def union(self, a, b):
        pa = self.find(a)
        pb = self.find(b)
        if pa == pb: return
        self.parent[pa] = pb
    
    # returning the parent
    def find(self, a):
        if self.parent[a] == a:
            return a
        
        self.parent[a] = self.find(self.parent[a])
        return self.parent[a]
    

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        n = len(points)
        edges = []
        for i in range(n):
            for j in range(i+1, n):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((dist, i, j))
        
        # sort based on cost (i.e. distance)
        edges.sort()
        
        # using Kruskal's algorithm to find the cost of Minimum Spanning Tree
        res = 0
        ds = DisjointSet(n)
        for cost, u, v in edges:
            if ds.find(u) != ds.find(v):
                ds.union(u, v)
                res += cost
        
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        hq = []
        in_mst = [False] * len(points)
        
        def d(i: int, j: int) -> int:
            return abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
        
        def add_to_hq(i: int):
            for j in range(len(points)):
                if i != j and not in_mst[j]:
                    heapq.heappush(hq, (d(i, j), j))
        
        heapq.heappush(hq, (0, 0))
        res = 0
        while hq:
            dist, i = heapq.heappop(hq)
            if not in_mst[i]:
                in_mst[i] = True
                res += dist
                add_to_hq(i)
        
        return res
                


from heapq import heappush, heappop
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        costs = sorted([(self.get_dist(points[i], points[j]), i, j) for i in range(n) for j in range(i)])
        groups = list(range(n))
        def find(node):
            while node != groups[node]:
                node = groups[node]
            return node
        
        res = 0
        for cost, u, v in costs:
            root1, root2 = find(u), find(v)
            if root1 != root2:
                res += cost
                groups[max(root1, root2)] = min(root1, root2)
                
        return res
        
    
    def get_dist(self, pt1, pt2):
        return abs(pt1[0] - pt2[0]) + abs(pt1[1] - pt2[1])

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        dis = collections.defaultdict(list)
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                d = abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                dis[i].append((d,j))
                dis[j].append((d,i))
                
        ans, seen, heap = 0, set(), [(0,0)]
        
        while len(seen)<len(points):
            d, j = heapq.heappop(heap)
            if j not in seen:
                seen.add(j)
                ans += d
                for d, i in dis[j]:
                    heapq.heappush(heap, (d,i))
        return ans


from heapq import heappop, heappush
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        heap = []
        self.parent = {}
        self.count = {}
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                heappush(heap, (dist, i, j))
                
        result = 0
        while heap:
            cur_dist, point1, point2 = heappop(heap)
            point1_parent = self.find(point1)
            point2_parent = self.find(point2)
            if point1_parent == point2_parent:
                continue
            self.parent[point1_parent] = point2_parent
            self.count[point2_parent] += self.count[point1_parent]
            result += cur_dist
            if self.count[point2_parent] == len(points):
                return result
        return 0
    
    def find(self, x):
        if x not in self.parent:
            self.parent[x] = x
            self.count[x] = 1
            return self.parent[x]
        if x == self.parent[x]:
            return self.parent[x]
        self.parent[x] = self.find(self.parent[x])
        return self.parent[x]

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        graph = collections.defaultdict(list)
        mh = lambda p1, p2: abs(p1[0]-p2[0])+abs(p1[1]-p2[1])
        for i in range(n):
            for j in range(i+1, n):
                d = mh(points[i], points[j])
                graph[i].append((d, j))
                graph[j].append((d, i))
        cnt = 1
        ans = 0
        visited = [False]*n
        heap = graph[0]
        visited[0]=True
        heapq.heapify(heap)
        while heap:
            d, j = heapq.heappop(heap)
            if not visited[j]:
                visited[j] = True
                ans+=d
                cnt+=1
                for nei in graph[j]: heapq.heappush(heap, nei)
            if cnt>=n: break
        return ans

class DisjointSet:
    def __init__(self, n):
        self.parent = list(range(n))
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    def union(self, x, y):
        parx, pary = self.find(x), self.find(y)
        if parx == pary:
            return False
        self.parent[pary] = parx
        return True

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def distance(a, b):
            return abs(a[0]-b[0]) + abs(a[1]-b[1])
        # build a list of edges in the form of (w, u, v)
        edges = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                edges.append([distance(points[i], points[j]), i, j])
        edges.sort()
        
        dset = DisjointSet(len(points))
        res = numOfEdges = idx = 0
        while numOfEdges < len(points) - 1:
            w, u, v = edges[idx]
            if dset.union(u, v):
                res += w
                numOfEdges += 1
            idx += 1
            
        return res


# alright, whatever, time to solve it again in Python3 \\U0001f40d  whoo!

# ok silly mistake, but that's A ok :)

# alright! cool, well time for C++ then i'm done upsolving this one, it was fun :)

class Solution:
    def minCostConnectPoints(self, A: List[List[int]]) -> int:
        N = len(A)
        P = [i for i in range(N)]  # parent representatives of disjoint sets
        E = []
        for u in range(N):
            x1, y1 = A[u]
            for v in range(u + 1, N):
                x2, y2 = A[v]
                w = abs(x1 - x2) + abs(y1 - y2)
                E.append([ u, v, w ])
        E.sort(key = lambda edge: edge[2])
        def find(x):
            P[x] = P[x] if P[x] == x else find(P[x])
            return P[x]
        def union(a, b):
            a = find(a)
            b = find(b)
            if a == b:
                return False
            P[a] = b   # arbitrary choice
            return True
        return sum([w for u, v, w in E if union(u, v)])


import queue 
class Solution:
    def minCostConnectPoints(self, points:List[List[int]]) -> int:
        \"\"\"
            @params:
                points: List of list of coordinates (in cartesian coordinates)
                where points[i] = [x_i, y_i]
                Are points sorted? Not necessary 
                Can there be negative integers? Yes 
                Can there be duplicate points? No 
                Points length: 1 <= len(points) <= 1000
        
                Test case 1: [[0,0], [1,2], [3,0]]
                expected_output = min((3+3), (3+4)) = 6
                y
                |     
                |
                |  1,2
                |_  _  _ _ _ x 
                0,0    3,0
                 
                Test case 2: [[0,0], [1,1], [2,2]]
                expected_output = min(4, 5) = 4 
                  y
                |     
                |      2,2
                |  1,1
                |   _    _    _ _ _ x 
                0,0           
        \"\"\"
        def manhattan(x, y):
            return abs(x[0]-y[0]) + abs(x[1]-y[1])
        ans, n = 0, len(points)
        seen = set()
        minimum_distance = queue.PriorityQueue()
        minimum_distance.put((0, (0, 0)))
        
        while len(seen) < n:
            w, (u,v) = minimum_distance.get()
            if u in seen and v in seen:
                continue 
            else:
                ans += w 
                seen.add(v)
                for j in range(n):
                    if j not in seen and j != v:
                        minimum_distance.put((manhattan(points[j], points[v]), (v, j)))
        return ans

        

class Solution:
    def minCostConnectPoints(self, a: List[List[int]]) -> int:                
        n = len(a)
        if n <= 1: return 0
        d = dict()
        q = []
        for i in range(n-1):
            xi, yi = a[i]
            for j in range(n):
                xj, yj = a[j]
                val = abs(xi-xj) + abs(yi-yj)
                d[(i, j)] = val
                d[(j, i)] = val                
                q.append((val, i, j))
        
        
        def union(u, v):
            UF[find(v)] = UF[find(u)]
        def find(u):
            if u != UF[u]:
                UF[u] = find(UF[u])
            return UF[u]                
        
        UF = {i: i for i in range(n)}
        ans = set()
        heapify(q)        
        cur = set([q[0][1], q[0][2]])
        cand = []
        for x in cur:
            for y in range(n):
                if y in cur: continue
                cand.append((d[(x, y)], x, y))
        heapify(cand)
        ans = q[0][0]
        while len(cur) < n:
            val, x, y = heappop(cand)
            if find(x) != find(y): 
                cur.add(y)
                union(x, y)
                ans += val
                for z in range(n):
                    if z in cur: continue
                    heappush(cand, (d[(y, z)], y, z))
        return ans
                
        
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        
        
        
        n = len(points)
        d = collections.defaultdict(list)
        for i in range(n):
            for j in range(i+1, n):
                dist = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                d[i].append((dist,i,j))
                d[j].append((dist,j,i))
        chosen = {0}
        between = d[0].copy()
        heapq.heapify(between)
        res = 0
        while len(chosen) < n:
            dist, i, j = heapq.heappop(between)
            if i in chosen and j in chosen:
                continue
            elif i in chosen and j not in chosen:
                chosen.add(j)
                res += abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                for jd,js,je in d[j]:
                    heapq.heappush(between, (jd,js,je))
                # dmin = float('inf')
                # for jd,js,je in d[j]:
                #     if not (js in chosen and je in chosen):
                #         dmin = min(dmin, jd)
                #         heapq.heappush(between, (jd,js,je))
                # chosen.add(j)
                # res += dmin
                # res.append((i,j,dmin))
            elif i not in chosen and j in chosen:
                chosen.add(i)
                res += abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                for iid,iis,iie in d[i]:
                    heapq.heappush(between, ((iid,iis,iie)))
                # dmin = float('inf')
                # for iid,iis,iie in d[i]:
                #     if not (iis in chosen and iie in chosen):
                #         dmin = min(dmin, iid)
                #         heapq.heappush(between, (iid,iis,iie))
                # chosen.add(i)
                # res += dmin
                # res.append((i,j,dmin))
        # print(res)
        # return sum(d for a,b,d in res)
        return res
        
        
        
        


import heapq

class Solution:
  def minCostConnectPoints(self, points: List[List[int]]) -> int:
    n = len(points)
    mst_nodes = [0 for i in range(n)]
    mst_nodes_cnt = 0
    #mst_edges = set() # (int,int)
    h = []  # heap of edges connected to MST (distance, source, dest)
    man_dist = lambda i,j: abs( points[i][0] - points[j][0] ) + abs( points[i][1] - points[j][1] )
    
    mst_nodes[0] = 1
    for p in range(1,n):
      h.append( (man_dist(0,p),0,p) )
    heapq.heapify(h)

    tot_dist = 0
    while h:
      dist, src_node, dst_node = heapq.heappop(h)
      if mst_nodes[dst_node]:
        continue
      tot_dist += dist
      mst_nodes[dst_node] = 1
      mst_nodes_cnt += 1
      if mst_nodes_cnt == n:
        break
      for next_dst in range(n):
        if mst_nodes[next_dst]==0:
          heapq.heappush( h, ((man_dist(dst_node,next_dst),dst_node,next_dst)) )

    return tot_dist

from collections import defaultdict
import heapq

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def manhattan(p1, p2):
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        n = len(points)
        c = defaultdict(list)
        for i in range(n):
            for j in range(i+1, n):
                dist = manhattan(points[i], points[j])
                c[i].append((dist, j))
                c[j].append((dist, i))
        
        pq = c[0]
        heapq.heapify(pq)
        visited = [False] * n
        visited[0] = True
        cnt = 1
        res = 0
        while pq:
            d, j = heapq.heappop(pq)
            if not visited[j]:
                cnt += 1
                res += d
                visited[j] = True
                for record in c[j]:
                    heapq.heappush(pq, record)
                if cnt >= n:
                    break
                    
        return res
                
            
                
        
        



class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:
        n=len(p)


        def find(x):
            if dp[x]!=x:
                dp[x]=find(dp[x])
            return dp[x]

        def uni(x,y):
            x,y=find(x),find(y)
            if x!=y:
                dp[x]=find(y)
                return False
            else:    
                return True

        dp=list(range(n))    

        pool=sorted((abs(p[i][0]-p[j][0])+abs(p[i][1]-p[j][1]),i,j) for i in range(n) for j in range(i+1,n))


        res=0

        for dis,u,v in pool:
            if not uni(u,v):
                res+=dis
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        ln=len(points)
        if ln<=1:return 0
        ans=0
        par={}
        def find(x):
            if x not in par:return x
            res=find(par[x])
            par[x]=res
            return res
        def union(a,b):
            n1=find(a)
            n2=find(b)
            if n1!=n2:
                if n1<n2:
                    par[n2]=n1
                else:
                    par[n1]=n2
        arr=[]
        for i in range(ln):
            for j in range(i+1,ln):
                n=abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                arr.append((n,i,j))
        arr.sort()
        for x in arr:
            n1=find(x[1])
            n2=find(x[2])
            if n1!=n2:
                if n1<n2:
                    par[n2]=n1
                else:
                    par[n1]=n2
                ans+=x[0]
        return ans    

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        edges = []
        connected = 1
        result = 0
        heapq.heapify(edges)
        visited = set()
        i = 0
        
        while connected < n:
            connected += 1
            visited.add(i)
            
            a = points[i]
            for j in range(n):
                b = points[j]
                if j not in visited:
                    heapq.heappush(edges, ((abs(a[0] - b[0]) + abs(a[1] - b[1]), j)))
            
            while edges[0][1] in visited:
                heapq.heappop(edges)
            
            result += edges[0][0]
            i = heapq.heappop(edges)[1]
        
        return result


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        edge_costs = []
        for i in range(n):
            for j in range(i + 1, n):
                p1, p2 = points[i], points[j]
                cost = abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
                edge_costs.append((cost, (i, j)))
        
        edge_costs.sort()
        
        total = 0
        parent = list(range(n)) # init with parent[i] = i
        
        def find_parent(v):
            if parent[v] == v:
                return v
            else:
                parent[v] = find_parent(parent[v])
                return parent[v]
        
        # def join(v1, v2):
        #     a = find_parent(v1)
        #     b = find_parent(v2)
        #     if a != b:
        #         parent[b] = a
        
        for cost, edge in edge_costs: # already sorted in increasing edge weight
            v1, v2 = edge
            v1_parent = find_parent(v1)
            v2_parent = find_parent(v2)
            if v1_parent != v2_parent:
                # print(v1, v2, cost)
                total += cost
                parent[v2_parent] = v1_parent
        
        return total

class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:
        n=len(p)


        def find(x):
            if dp[x]!=x:
                dp[x]=find(dp[x])
            return dp[x]

        def uni(x,y):
            x,y=find(x),find(y)
            if x!=y:
                dp[x]=find(y)
                return False
            else:    
                return True

        dp=list(range(n))    

        pool=sorted((abs(p[i][0]-p[j][0])+abs(p[i][1]-p[j][1]),i,j) for i in range(n) for j in range(i+1,n))




                
        return sum(dis for dis,u,v in pool if not uni(u,v))

class UF:
    def __init__(self, n):
        self.root = [i for i in range(n)]
    
    def find(self, a):
        if self.root[a] != a:
            self.root[a] = self.find(self.root[a])
        return self.root[a]
    
    def unite(self, a, b):
        self.root[self.find(a)] = self.find(b)
        
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        edges, res = [], 0
        for i in range(n):
            for j in range(i + 1, n):
                edges.append([abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]), i, j])
        edges.sort()
        uf = UF(n)
        for w, s, t in edges:
            if uf.find(s) != uf.find(t):
                uf.unite(s, t)
                res += w
        return res

class DSU:
    def __init__(self, N):
        self.parent = [i for i in range(N)]
        self.size = [1] * N
    def find(self, x):
        if self.parent[x] == x:
            return x
        return self.find(self.parent[x])
    
    def union(self, x, y):
        par_x, par_y = self.find(x), self.find(y)
        
        if par_x == par_y:
            return False
        
        if self.size[par_x] < self.size[par_y]:
            par_x, par_y = par_y, par_x
        
        
        self.parent[par_y] = par_x
        self.size[par_x] += self.size[par_y]
        self.size[par_y] = self.size[par_x]
        
        
        return True
        
        
        
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        ## Make edges
        edges = []
        N = len(points)
        
        if not points:
            return -1
        
        for i in range(N):
            for j in range(i+1, N):
                x1, y1 = points[i]
                x2, y2 = points[j]
                d = abs(x1 - x2) + abs(y1 - y2)
                edges.append([i, j, d])
        
        # Construct MST using Kruskal and DSU
        
        UF = DSU(N)
        
        total_cost = 0
        edges.sort(key = lambda x: x[2])
        
        for i, j, d in edges:
            if UF.union(i, j):
                total_cost += d
        
        
        return total_cost
        
        
        
        
        
        
        
                
                
                
                


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        G = collections.defaultdict(list)
        
        for i in range(N):
            for j in range(N):
                if i == j: continue
                cost_x = abs(points[i][0] - points[j][0])
                cost_y = abs(points[i][1] - points[j][1])
                
                cost = cost_x + cost_y
                
                G[i].append((cost, j))
                G[j].append((cost, i))
                
        PQ = []
        SEEN = set()
        
        def add(u):
            SEEN.add(u)
            
            for cost, v in G[u]:
                if v in SEEN:
                    continue
                heapq.heappush(PQ, (cost, v))
                
        mst = 0
        add(0)
        
        while PQ and len(SEEN) < N:
            cost, u = heapq.heappop(PQ)
            if u in SEEN:
                continue
            mst += cost
            add(u)
            
        return mst

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def cost(i, j):
            return abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
        n = len(points)
        dists = []
        for i in range(n):
            for j in range(i + 1, n):
                dists.append((cost(i, j), i, j))
        dists.sort()
        uf = UnionFind(n)
        ans = 0
        for c, i, j in dists:
            if uf.union(i, j):
                ans += c
        return ans
        
class UnionFind:
    def __init__(self, n):
        self.id = [i for i in range(n)]
        self.size = [1 for _ in range(n)]
    
    def find(self, i):
        root = i
        while root != self.id[root]:
            root = self.id[root]
        while root != i:
            j = self.id[i]
            self.id[i] = root
            i = j
        return root
    
    def union(self, i, j):
        root_i = self.find(i)
        root_j = self.find(j)
        if root_i == root_j:
            return False
        if self.size[root_i] < self.size[root_j]:
            self.id[root_i] = root_j
            self.size[root_j] += self.size[root_i]
        else:
            self.id[root_j] = root_i
            self.size[root_i] += self.size[root_j]
        return True

class UnionFind:
    def __init__(self):
        self.parent={}
        self.size={}
    def makeset(self,point):
        self.parent[point]=point
        self.size[point]=1
    def find(self,point):
        if self.parent[point]==point:
            return point
        self.parent[point]=self.find(self.parent[point])
        return self.parent[point]
    def union(self,point1,point2):
        point1=self.find(point1)
        point2=self.find(point2)
        if point1==point2:
            return False,self.size[point1]
        self.parent[point2]=point1
        self.size[point1]+=self.size[point2]
        return True,self.size[point1]
        
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        costmetrics=[]
        unionfind=UnionFind()
        for point in points:
            unionfind.makeset(tuple(point))
        # print(unionfind.parent,unionfind.size)
        for i in range(len(points)):
            for j in range(i+1,len(points)):
                cost=abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                costmetrics.append([cost,tuple(points[i]),tuple(points[j])])
        costmetrics.sort(key=lambda item:item[0])
        ans=0
        for i in range(len(costmetrics)):
            res,sz=unionfind.union(costmetrics[i][1],costmetrics[i][2])
            if res:
                ans+=costmetrics[i][0]
            if sz==len(points):
                break
        return ans
            
        
        
                


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        dis = []
        d = {}
        u = {}
        for i,x in enumerate(points):
            d[i] = 0
            u[i] = i
            for y in range(i+1,len(points)):
                z = points[y]
                m = abs(x[0]-z[0]) + abs(x[1]-z[1])
                dis.append([m,i,y])
        
        def merge(c1,c2):
            if u[c1] > u[c2]:
                c1,c2 = c2,c1
            t = u[c2]
            for k,v in u.items():
                if v == t:
                    u[k] = u[c1]
        
        dis = sorted(dis)
        c = 0
        result = 0
        count=0
        while count < len(points) - 1:
            while 1:
                c0,c1,c2 = dis[c]
                if u[c1] != u[c2]:
                    merge(c1,c2)
                    d[c1] += 1
                    d[c2] += 1
                    count += 1
                    result += c0
                    c += 1
                    break
                c += 1
        return result

class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:
        n=len(p)
        a=[i for i in range(n+1)]
        rank=[0 for i in range(n+1)]
        def find(i):
            if i==a[i]:
                return i
            a[i]=find(a[i])
            return a[i]
        def union(x,y):
            xs=find(x)
            ys=find(y)
            if xs!=ys:
                if rank[ys]>rank[xs]:
                    ys,xs=xs,ys
                a[ys]=xs
                rank[xs]+=1
                return 1
            return 0
        edge=[]
        for i in range(n):
            for j in range(i+1,n):
                dis=abs(p[i][0]-p[j][0])+abs(p[i][1]-p[j][1])
                edge.append([dis,i,j])
        ans=0
        edge.sort()
        for dis,i,j in edge:
            if union(i,j):
                ans+=dis
        return ans        
                


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def manhattan(p1, p2):
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        n, c = len(points), collections.defaultdict(list)
        for i in range(n):
            for j in range(i + 1, n):
                d = manhattan(points[i], points[j])
                c[i].append((d, j))
                c[j].append((d, i))
        cnt, ans, visited, heap = 1, 0, [0] * n, c[0]
        visited[0] = 1
        heapq.heapify(heap)
        while heap:
            d, j = heapq.heappop(heap)
            if not visited[j]:
                visited[j], cnt, ans = 1, cnt + 1, ans + d
                for record in c[j]:
                    heapq.heappush(heap, record)
            if cnt >= n:
                break
        return ans

from heapq import heappush

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        visited = set()
        minCost = 0
        minEdges = []
        # weight, idx 
        heappush(minEdges,(0,0))
             
        while(len(visited) < len(points)):  
            
            # pop to get the lowest weight edge possible
            # visit it and add cost to min cost spanning tree
            vertexDistance,vertexIdx = heappop(minEdges)
            if vertexIdx in visited: continue
            print(vertexIdx)
            visited.add(vertexIdx)
            minCost += vertexDistance
            
            # extract our currently visited x and y pos
            vertexX = points[vertexIdx][0]
            vertexY = points[vertexIdx][1]
            
            # for all nodes, if its not added to spanning tree already
            # calculate the distance to it. push it to heapq.
            for adjIdx, adjPos in enumerate(points):
                if adjIdx not in visited:
                    adjX = points[adjIdx][0]
                    adjY = points[adjIdx][1]
                    
                    distance = abs(vertexX - adjX) + abs(vertexY - adjY)
                    heappush(minEdges,(distance,adjIdx))
                             
        return minCost
                    
            
            
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        connections = []
        for i in range(N):
            for j in range(i+1, N):
                connections.append([i, j, abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])])
        
        if len(connections) < N - 1:
            return -1
        elif N == 1:
            return 0
        uf = {}
        def find(x):
            uf.setdefault(x, x)
            if uf[x] != x:
                uf[x] = find(uf[x])
            return uf[x]
        def union(x, y):
            uf[find(x)] = find(y)
        
        res = 0
        for start, end, cost in sorted(connections, key=lambda x : x[2]):
            if find(start) != find(end):
                res += cost
                union(start, end)
        if len({find(c) for c in uf}) == 1:
            return res
        return -1


import math

class DSU:
    def __init__(self, n):
        self.n = n
        self.parent = [i for i in range(n)]
    
    def find(self, x):
        while self.parent[x] != x:
            x_p = self.parent[x]
            self.parent[x] = self.parent[x_p]  # path compression
            x = self.parent[x]
        return x
    
    def union(self, x, y):
        x_p = self.find(x)
        y_p = self.find(y)
        if x_p != y_p:   # not in the same joint set
            self.parent[x_p] = y_p    # parent of y is the new root


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        for i in range(len(points)):
            for j in range(len(points)):
                dist = self.distance(points[i], points[j])
                edges.append((dist, i, j))
        edges = sorted(edges, key=lambda x:x[0])
        
        ans = 0
        n = len(points)
        dsu = DSU(n)
        i = 0
        j = 0 # inter through the edges
        while i < n-1:  # MST algo.
            dist, a, b = edges[j]
            a_p = dsu.find(a)
            b_p = dsu.find(b)
            if a_p != b_p:
                dsu.union(a, b)
                i += 1
                ans += dist
            j += 1
        return ans
                
    def distance(self, p1, p2):
        return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])

class Graph: 
  
    def __init__(self,vertices): 
        self.V= vertices #No. of vertices 
        self.graph = [] # default dictionary  
                                # to store graph 
    def addEdge(self,u,v,w): 
        self.graph.append([u,v,w]) 
  
    def find(self, parent, i): 
        if parent[i] == i: 
            return i 
        return self.find(parent, parent[i]) 
  
    def union(self, parent, rank, x, y): 
        xroot = self.find(parent, x) 
        yroot = self.find(parent, y) 
        if rank[xroot] < rank[yroot]: 
            parent[xroot] = yroot 
        elif rank[xroot] > rank[yroot]: 
            parent[yroot] = xroot 
        else : 
            parent[yroot] = xroot 
            rank[xroot] += 1
            
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        result = 0 
        i = 0
        e = 0 
        g = Graph(len(points))
        for i in range(len(points)-1):
            for j in range(i,len(points)):
                a = tuple(points[i])
                b = tuple(points[j])
                g.addEdge(a,b, abs(a[0]-b[0]) + abs(a[1]-b[1]))
        g.graph =  sorted(g.graph,key=lambda item: item[2]) 
       # print(g.graph,g.V)
        parent = [0] * g.V 
        rank = [0] * g.V 
  
        dic = {}
        for i,p in enumerate(points):
            dic[tuple(p)] = i

        for i in range(g.V): 
            parent[i] = i
        while e < g.V - 1 : 
            u,v,w =  g.graph[i] 
            i = i + 1
            x = g.find(parent, dic[u]) 
            y = g.find(parent ,dic[v]) 
            if x != y: 
                e = e + 1     
                result += w
                g.union(parent, rank, x, y)             
        return result


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def find(i):
            while i!=root[i]:
                root[i]=root[root[i]]
                i=root[i]
            return i
        
        res, n=0, len(points)
        conn, root=[], [i for i in range(n)]
        for i in range(n):
            for j in range(i+1, n):
                conn.append([i, j, abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])])     
                    
        conn.sort(key=lambda c: c[2])
        for c in conn:
            p1=find(c[0])
            p2=find(c[1])
            if p1!=p2:
                res+=c[2]
                root[p1]=p2
            
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        dis = lambda x,y,x1,y1: abs(x-x1) + abs(y-y1)
        distances = []
        for i, (x, y) in enumerate(points):
            for j in range(i+1, len(points)):
                x1, y1 = points[j]
                d = dis(x, y, x1, y1)
                distances.append((d, i, j))
        uf = UnionFind(len(points))
        distances.sort()
        ans = 0
        for d, i, j in distances:
            if uf.union(i, j):
                ans += d
        return ans
        
class UnionFind:
    def __init__(self, n):
        self.component_count = n
        self.parents = list(range(n))
        self.size = [1] * n

    def find(self, x):
        if self.parents[x] != x:
            self.parents[x] = self.find(self.parents[x])
        return self.parents[x]

    # return true if two are newly unioned, false if already unioned.
    def union(self, x, y):
        x0 = self.find(x)
        y0 = self.find(y)
        if x0 == y0:
            return False
        if self.size[x0] < self.size[y0]:
            x0, y0 = y0, x0
        self.parents[y0] = x0
        self.size[x0] += self.size[y0]
        self.component_count -= 1
        return True

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        ll = len(points)
        if ll == 1:
            return 0
        distances = []
        def get_distance(i, j):
            return abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
        
        for i in range(ll):
            for j in range(i + 1, ll):
                distances.append((get_distance(i, j), i, j))
        distances.sort()
        size = [1] * ll
        parents = list(range(ll))
    
        def ufind(x):
            if parents[x] != x:
                return ufind(parents[x])
            return x
        
        def uunion(x, y):
            ux = ufind(x)
            uy = ufind(y)
            if ux < uy:
                parents[ux] = uy
                size[uy] += ux
            else:
                parents[uy] = ux
                size[ux] += uy
            
        
        res = 0
        for d, x, y in distances:
            ux = ufind(x)
            uy = ufind(y)
            if ux != uy:
                uunion(ux, uy)
                res += d
        return res
                
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        parents = list(range(len(points)))
        
        def find(x):
            if parents[x] != x:
                parents[x] = find(parents[x])
            return parents[x]
        
        def union(x, y):
            px = find(x)
            py = find(y)
            if px != py:
                parents[py] = px
                return False
            return True
        
        edges = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                dist = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                edges.append((dist, i, j))
        
        edges.sort()
        
        ans = 0
        
        for w, x, y in edges:
            if not union(x, y):
                ans += w
        return ans

class DSU:
    def __init__(self, n):
        self.parents = list(range(n))
    
    def find(self, u):
        orig = u
        while u != self.parents[u]:
            u = self.parents[u]
        
        self.parents[orig] = u
        return u
    
    def union(self, u, v):
        u,v = sorted([self.find(u),self.find(v)])
        
        if u!=v:
            self.parents[v] = u
            return True
        return False
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        distances = {}
        
        def compute(p1,p2):
            x1,y1 = p1
            x2,y2 = p2
            return abs(x1-x2)+abs(y1-y2)
        
        for i,p1 in enumerate(points):
            for j in range(i+1,len(points)):
                p2 = points[j]
                
                distances[(i,j)] = compute(p1,p2)
        
        dsu = DSU(len(points))
        
        res = 0
        for (u,v),d in sorted(list(distances.items()), key=lambda x: x[1]):
            if dsu.union(u,v):
                res+=d
        return res


from collections import defaultdict
import heapq
class Solution:
    def minCostConnectPoints(self, points) -> int:
        edges = defaultdict(list)
        n = len(points)
        connected_pts = set([0])
        pending_edges = []
        for i in range(n):
            for j in range(i+1,n):
                w = abs(points[j][1] - points[i][1]) + abs(points[j][0] - points[i][0])
                edges[i].append((w, j))
                edges[j].append((w, i))
        # print(edges)
        for e in edges[0]:
            heapq.heappush(pending_edges, (e[0], e[1]))
            # pending_edges.append((e[0], e[1]))

        res = 0
        while len(connected_pts) < n:
            # pending_edges.sort()
            # print(pending_edges)
            found_edge = False
            while not found_edge:
                e = heapq.heappop(pending_edges)
                if e[1] in connected_pts:
                    continue
                found_edge = True
                connected_pts.add(e[1])
                res += e[0]
                for next_edge in edges[e[1]]:
                    if next_edge not in connected_pts:
                        heapq.heappush(pending_edges, (next_edge[0], next_edge[1]))
                        # pending_edges.append((next_edge[0], next_edge[1]))
        return res


from functools import cmp_to_key

def cmp(a,b):
    return a[2]-b[2]
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        edges = []
        points = [tuple(l) for l in points]
        N = len(points)
        if(N==1):
            return 0
        
        for i in range(N):
            x,y = points[i]
            for j in range(i+1,N):
                x1,y1 = points[j]
                edges.append((i,j,abs(x-x1)+abs(y-y1)))
        edges.sort(key=cmp_to_key(cmp))
        parent = {i:i for i in points}
        rank = {i:0 for i in points}
        val = 0
        ct = 0
        for i,j,v in edges:
            
            l = self.union(rank,parent,points[i],points[j])
            if(l!=0):
                ct += 1
                val += v
            if(ct==N-1):
                return val
    
    def find(self,parent,node):
        if(parent[node]==node):
            return node
        parent[node] = self.find(parent,parent[node])
        return parent[node]
    def union(self,rank,parent,node1,node2):
        
        x = self.find(parent,node1)
        y = self.find(parent,node2)
        if(x==y):
            return 0
        if(rank[x]>rank[y]):
            parent[y] = x
        elif(rank[x]<rank[y]):
            parent[x] = y
        else:
            rank[x] += 1
            parent[y] = x
        return 1


import heapq

class DisjointSet:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [1]*n
        self.maxRank = 1
    
    # make a and b part of the same component
    # union by rank optimization
    def union(self, a, b):
        pa = self.find(a)
        pb = self.find(b)
        if pa == pb: return
        if self.rank[pa] > self.rank[pb]:
            self.parent[pb] = pa
            self.rank[pa] += self.rank[pb]
            self.maxRank = max(self.maxRank, self.rank[pa])
        else:
            self.parent[pa] = pb
            self.rank[pb] += self.rank[pa]
            self.maxRank = max(self.maxRank, self.rank[pb])
    
    # find the representative of the 
    # path compression optimization
    def find(self, a):
        if self.parent[a] == a:
            return a
        
        self.parent[a] = self.find(self.parent[a])
        return self.parent[a]

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def distance(u, v):
            dx = abs(u[0] - v[0])
            dy = abs(u[1] - v[1])
            return dx+dy
        
        n = len(points)
        if n == 1:
            return 0
        if n == 2:
            return distance(points[0], points[1])
        
        # # Method 1: Prim's Alg with Heap
        # d = {i:[] for i in range(n)}
        # for i in range(n):
        #     for j in range(i+1, n):
        #         dist = distance(points[i], points[j])
        #         d[i].append((dist, j))
        #         d[j].append((dist, i))
        # cost = 0
        # connected = 1
        # check = [True] + [False]*(n-1)
        # heap = d[0]
        # heapq.heapify(heap)
        # while connected < n:
        #     (dist, p) = heapq.heappop(heap)
        #     if not check[p]:
        #         cost += dist
        #         connected += 1
        #         check[p] = True
        #         for pair in d[p]:
        #             heapq.heappush(heap, pair)
        # return cost
        
        # # Nethod 2: Another Implementation of Prim's Alg
        # cost = 0
        # curr = 0 # select a random point as the starting point
        # dist = [float('inf')] * n
        # explored = set()
        # explored.add(0)
        # cnt = 1
        # while cnt < n:
        #     u = points[curr]
        #     for j, v in enumerate(points):
        #         if j in explored: 
        #             continue
        #         else:
        #             dist[j] = min(dist[j], distance(u,v))
        #     min_d, curr = min((d, j) for j, d in enumerate(dist)) 
        #     explored.add(curr)
        #     cnt += 1
        #     dist[curr] = float('inf')
        #     cost += min_d
        # return cost
        
        # Method 3: Kruskal's Alg with Disjoint Set
        edges = []
        for i in range(n):
            for j in range(i+1, n):
                dist = distance(points[i], points[j])
                edges.append((dist, i, j))
        heapq.heapify(edges)
        cost = 0
        ds = DisjointSet(n)
        while ds.maxRank < n:
            dist, u, v = heapq.heappop(edges)
            if ds.find(u) != ds.find(v):
                cost += dist
                ds.union(u, v)
        return cost
            
        
        
        



from collections import defaultdict
from heapq import heappush, heappop
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        G = defaultdict(dict)
        for i, (xi, yi) in enumerate(points):
            for j, (xj, yj) in enumerate(points[i + 1:], i + 1):
                d = abs(xi - xj) + abs(yi - yj)
                G[i][j] = G[j][i] = d
        seen, pq, ans = {0}, [], 0
        for nb, d in G[0].items():
            heappush(pq, (d, nb))
        while len(seen) < len(G):
            while pq:
                cost, next_node = heappop(pq)
                if next_node in seen: continue
                seen.add(next_node)
                ans += cost
                for nb, d in G[next_node].items():
                    if nb in seen: continue
                    heappush(pq, (d, nb))
        return ans

class DSU:
    def __init__(self, N):
        self.parent = [i for i in range(N)]
        self.size = [1] * N
    def find(self, x):
        if self.parent[x] == x:
            return x
        return self.find(self.parent[x])
    
    def union(self, x, y):
        par_x, par_y = self.find(x), self.find(y)
        
        if par_x == par_y:
            return False
        
        if self.size[par_x] < self.size[par_y]:
            par_x, par_y = par_y, par_x
        
        
        self.parent[par_y] = par_x
        self.size[par_x] += self.size[par_y]
        self.size[par_y] = self.size[par_x]
        
        
        return True
        
        
        
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        ## Make edges
        edges = []
        N = len(points)
        
        if not points:
            return -1
        
        for i in range(N):
            for j in range(i+1, N):
                if points[i] == points[j]:
                    continue
                x1, y1 = points[i]
                x2, y2 = points[j]
                d = abs(x1 - x2) + abs(y1 - y2)
                edges.append([i, j, d])
        
        # Construct MST using Kruskal and DSU
        
        UF = DSU(N)
        
        total_cost = 0
        edges.sort(key = lambda x: x[2])
        
        for i, j, d in edges:
            if UF.union(i, j):
                total_cost += d
        
        
        return total_cost
        
        
        
        
        
        
        
                
                
                
                


class UnionFind:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [1 for _ in range(n)]

    def union(self, i, j):
        x = self.find(i)
        y = self.find(j)
        if x == y:
            return
        if self.rank[x] > self.rank[y]:
            self.parent[y] = x
            self.rank[x] += self.rank[y]
        else:
            self.parent[x] = y
            self.rank[y] += self.rank[x]

    def find(self, i):
        if self.parent[i] == i:
            return self.parent[i]
        return self.find(self.parent[i])




class Solution:
    def minCostConnectPoints(self, points) -> int:
        n = len(points)
        edges = []
        for i in range(n):
            for j in range(i + 1, n):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((dist, i, j))

        # sort based on cost (i.e. distance)
        edges.sort()
        # using Kruskal's algorithm to find the cost of Minimum Spanning Tree
        res = 0
        uf = UnionFind(n)
        for cost, u, v in edges:
            if uf.find(u) != uf.find(v):
                uf.union(u, v)
                res += cost
        return res



class uf(object):
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [1 for i in range(n)]
    def union(self, x, y):
        p1, p2 = self.find(x), self.find(y)
        if self.rank[p1] == self.rank[p2]:
            self.parent[p2] = p1
            self.rank[p1] += 1
        elif self.rank[p1] > self.rank[p2]:
            self.parent[p2] = p1
        else:
            self.parent[p1] = p2
        return
    
    def find(self, x):
        if self.parent[x] == x:
            return x
        return self.find(self.parent[x])
    

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        union_find = uf(len(points))
        ans = 0
        n = len(points)
        for i in range(n):
            for j in range(i + 1, n):
                edges.append((abs(points[j][0] - points[i][0]) + abs(points[j][1] - points[i][1]), i, j))
                
        edges = sorted(edges)
        for w, u, v in edges:
            if union_find.find(u) != union_find.find(v):
                union_find.union(u, v)
                ans += w
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        dist = []
        for i, p1 in enumerate(points):
            for j, p2 in enumerate(points):
                if i!=j:
                    d = abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
                    heapq.heappush(dist, (d,i,j))
        g = defaultdict(set)
        checked = set()
        def connected(a,b):
            if b in g[a]:
                return True
            if a in checked:
                return False
            checked.add(a)
            for p in g[a]:
                if connected(p,b):
                    return True
            return False
        conn = 0
        d = 0
        while conn < len(points)-1:
            p = heapq.heappop(dist)
            checked = set()
            if not connected(p[1],p[2]):
                g[p[2]].add(p[1])
                g[p[1]].add(p[2])
                d += p[0]
                conn += 1
        return d

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        all_edges = []
        for point1 in points:
            for point2 in points:
                if point1 != point2:
                    all_edges.append((abs(point1[0] - point2[0]) + abs(point1[1] - point2[1]), tuple(point1),tuple(point2)))
                    
        all_edges.sort(key=lambda x:(x[0]))
        
        parent = { tuple(point):tuple(point) for point in points }
        rank = {tuple(point):1 for point in points}
        children = {tuple(point):1 for point in points}
        def find(point1):
            if parent[point1] != point1:
                parent[point1] = find(parent[point1])
            return parent[point1]
        
        def union(point1, point2):
            parent1 = find(point1)
            parent2 = find(point2)
            if rank[parent1] > rank[parent2]:
                parent[parent2] = parent1
                rank[parent1] += 1
                children[parent1] +=children[parent2]
            else:
                parent[parent1] = parent2
                rank[parent2] += 1
                children[parent2] +=children[parent1]
            return
        cost = 0
        count = 0
        for edge in all_edges:
            if count == len(points)-1:
                break
            if find(edge[1]) != find(edge[2]):
                union(edge[1],edge[2])
                cost +=edge[0]
                count +=1
        return cost


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n=len(points)
        
        connections = []
        self.father={}
        self.size=n
        for i in range(n):
            self.father[(points[i][0],points[i][1])] = (points[i][0],points[i][1])
            for j in range(i+1,n):
                dist = abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                p1 = (points[i][0],points[i][1])
                p2 = (points[j][0],points[j][1])
                connections.append((p1,p2,dist))
        # print(self.father)
        connections = sorted(connections,key = lambda x: x[2])
        # print(connections)

        
        res=0
        def union(a,b):
            root_a = find(a)
            root_b = find(b)
            if root_a!=root_b:
                self.father[root_a] = root_b
                self.size-=1
                return True
            else:
                return False
        
        def find(node):
            path = []
            while node!=self.father[node]:
                path.append(node)
                node = self.father[node]
            
            for child in path:
                self.father[child] = node
            return node
        
        for c in connections:
            if union(c[0],c[1]):
                res+=c[2]
                if self.size==0:
                    return res
        return res
        
        
        
        
        
        


class DSU:
    def __init__(self,n):
        self.parent = [i for i in range(n)]
        self.rank = [1 for i in range(n)]
        self.count = n
    
    def find(self,x):
        if x!=self.parent[x]:
            self.parent[x]=self.find(self.parent[x])
        return self.parent[x]
    
    def union(self,x,y):
        px = self.find(x)
        py = self.find(y)
        if px==py:
            return False
        self.count-=1
        if self.rank[x]>self.rank[y]:
            self.parent[py]=px
            self.rank[px]+=self.rank[py]
        else:
            self.parent[px]=py
            self.rank[py]+=self.rank[px]
        return True
                
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        edges = []
        for i in range(n):
            for j in range(i+1, n):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                heapq.heappush(edges,(dist,i,j))
        res = 0
        ds = DSU(n)
        while edges and ds.count!=1:
            cost,u,v = heapq.heappop(edges)
            if ds.union(u,v):
                res += cost
        return res

class UnionFind:
    def __init__(self):
        self.roots = {}
        self.depth = {}
    
    def root(self, node):
        if node not in self.roots:
            self.roots[node] = node
            self.depth[node] = 1
        path = []
        while self.roots[node] != node:
            path.append(node)
            node = self.roots[node]
        for elem in path:
            self.roots[elem] = node
        return node

    def connect(self, x, y):
        x = self.root(x)
        y = self.root(y)
        if x == y:
            return
        if self.depth[x] > self.depth[y]:
            x, y = y, x
        if self.depth[x] == self.depth[y]:
            new_depth = self.depth[y] + 1
        else:
            new_depth = self.depth[y]
        del self.depth[x]
        self.roots[x] = y
        self.depth[y] = new_depth
        

class Solution:
        
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        min_span_tree = UnionFind()
        cost = 0
        edges = []
        for i in range(1, len(points)):
            for j in range(i):
                edge_cost = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append([edge_cost, i, j])
        edges.sort()
        to_connect = len(points) - 1
        for edge_cost, i, j in edges:
            if not to_connect:
                break
            if min_span_tree.root(i) != min_span_tree.root(j):
                cost += edge_cost
                min_span_tree.connect(i, j)
                to_connect -= 1
        return cost

class Graph:
    def __init__(self, v =0):
        self.v = v
        self.edge = []
class UnionFind:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [0]*n
        
    def find(self, i):
        if self.parent[i] != i:
            self.parent[i] = self.find(self.parent[i])
        return self.parent[i]
    
    def union(self, u, v):
        uroot, vroot = self.find(u), self.find(v)
        if uroot == vroot:
            return False
        elif self.rank[uroot] < self.rank[vroot]:
            self.parent[uroot] = vroot
            self.rank[vroot] += 1
        else:
            self.parent[vroot] = uroot
            self.rank[uroot] += 1
        return True
    
class Solution:
    def distance(self, point1: List[int], point2: List[int]):
        return abs(point1[0] - point2[0]) + abs(point1[1] - point2[1])
        
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if not points or len(points)<2:
            return 0
        n = len(points)
        graph = Graph(n)
        tot = 0
        for i in range(n):
            for j in range(i+1, n):
                d = self.distance(points[i], points[j])
                graph.edge.append([i,j,d])

        graph.edge = sorted(graph.edge, key=lambda item: item[2])
        
        uf = UnionFind(n)
        for u,v,w in graph.edge:
            if uf.union(u,v):
                tot += w
        return tot


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:

        cost_map = {}
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                cost = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                cost_map[(i, j)] = cost
        
        graph = []
        for key, value in cost_map.items():
            graph.append([key[0], key[1], value])        
        
        def find(city):
            if parent[city] != city:
                parent[city] = find(parent[city])
            return parent[city]
        
        def union(city1, city2):
            root1 = find(city1)
            root2 = find(city2)
            if root1 == root2:
                return False # Cycle
            parent[root2] = root1 # Join roots
            return True
            
        #Keep track of disjoint sets. Initially each city is its own set.
        parent = {city:city for city in range(0, len(points))}
        #Sort connections so we are always picking minimum cost edge.
        graph.sort(key=lambda x:x[2])
        totalCost = 0
        for city1, city2, cost in graph:
            if union(city1, city2):
                totalCost += cost
        
        # Check that all cities are connected
        root = find(len(points)-1)
        for i in range(0, len(points)):
            if find(i) == root:
                continue
            else:
                return -1
        return totalCost

from heapq import *
class Solution:
    def minCostConnectPoints(self, points):
        N = len(points)
        parent = [i for i in range(N)]
        def find(v):
            while parent[v] != parent[parent[v]]:
                parent[v] = parent[parent[v]]
            return parent[v]
        #dist = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        heap, total_cost = [], 0
        for i1, p1 in enumerate(points):
            for i2, p2 in enumerate(points[i1+1:], start = i1+1):
                #heappush(heap, (dist(p1, p2), i1, i2))
                heappush(heap, (abs(p1[0]-p2[0]) + abs(p1[1]-p2[1]), i1, i2))
        while heap:
            cost, u, v = heappop(heap)
            pu, pv = find(u), find(v)
            if pu != pv:
                parent[pu] = pv
                N -= 1
                total_cost += cost
                if N == 0:
                    break
        return total_cost


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        \"\"\"
        MST - minimum spanning tree
        
        Greedy solution
        1. random choose a start point
        2. each time we add the closest point
        \"\"\"
        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        n, c = len(points), collections.defaultdict(list)
        for i in range(n):
            for j in range(i+1, n):
                d = manhattan(points[i], points[j])
                c[i].append((d, j))
                c[j].append((d, i))
        cnt, ans, visited, heap = 1, 0, [0] * n, c[0]
        visited[0] = 1
        heapq.heapify(heap)
        while heap:
            d, j = heapq.heappop(heap)
            if not visited[j]:
                visited[j], cnt, ans = 1, cnt+1, ans+d
                for record in c[j]: heapq.heappush(heap, record)
            if cnt >= n: break        
        return ans

class UnionFind:
\t# uf = UnionFind(N)
\t# for i in range(N): uf.add(i)
\t# for x, y in pairs: uf.unite(x, y)
\t# ans = max([uf.size(i) for i in range(N)])
\tdef __init__(self, n):
\t\tself.n = n
\t\tself.sizes = [1]*n
\t\tself.parents = list(range(n))

\tdef find(self, x):
\t\twhile x != self.parents[x]:
\t\t\tself.parents[x] = self.parents[self.parents[x]]
\t\t\tx = self.parents[x]
\t\treturn self.parents[x]

\tdef unite(self, x, y):
\t\tx, y = self.find(x), self.find(y)
\t\tif x == y:
\t\t\treturn
\t\tif self.sizes[x] < self.sizes[y]:
\t\t\tx, y = y, x
\t\tself.parents[y] = x
\t\tself.sizes[x] += self.sizes[y]
\t
\tdef add(self, x):
\t\tself.sizes[x] = 1
\t\t
\tdef size(self, x):
\t\treturn self.sizes[self.find(x)]
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        dists = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                p1, p2 = points[i], points[j]
                d = abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
                dists.append((d, i, j))
        dists.sort()
        uf = UnionFind(len(points))
        ans = 0
        for d, i, j in dists:
            if uf.find(i) != uf.find(j):
                #print(i, j, d)
                uf.unite(i, j)
                ans += d
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
    
        edges = []
        nodes = set()
        # set up edges with (weight, u, v)
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                dis = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((dis, i, j))
                nodes.add(i)
                nodes.add(j)
        

        # set up union find
        class UnionFindSet:
            def __init__(self, nodes):
                self._parents = {}
                self._ranks = {}
                for n in nodes:
                    self._parents[n] = n
                    self._ranks[n] = 1

            def find(self, u):
                while u != self._parents[u]:
                    self._parents[u] = self.find(self._parents[u])
                    u = self._parents[u]
                return u

            def union(self, u, v):
                pu, pv = self.find(u), self.find(v)
                if pu == pv: return False

                if self._ranks[pu] < self._ranks[pv]:
                    self._parents[pu] = pv
                elif self._ranks[pu] > self._ranks[pv]:
                    self._parents[pv] = pu
                else:        
                    self._parents[pv] = pu
                    self._ranks[pu] += 1

                return True

        uf = UnionFindSet(nodes)
        
        # Kruskal Algorithm
        edges.sort()
        cost = 0
        for dis, u, v in edges:
            pu, pv = uf.find(u), uf.find(v)
            if pu == pv:
                continue
            else:
                cost += dis
                uf.union(u,v)

        return cost
            
    
                
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        dist = []
        
        for x in range(len(points)):
            [xi, yi] = points[x]
            for y in range(x+1, len(points)):
                [xj, yj] = points[y]
                manhattan_dist = abs(xi-xj) + abs(yi-yj)
                if x != y:
                    dist.append([x,y,manhattan_dist])
                
        dist.sort(key=lambda pt: pt[2])
        
        def detectCycle(adj):
            visited = set()
            
            def dfs(curr, parent):
                visited.add(curr)
                for neighbor in adj[curr]:
                    if neighbor == parent:
                        continue
                    elif neighbor in visited:
                        return True
                    elif dfs(neighbor, curr):
                        return True
                return False
            
            for node in range(len(points)):
                if node not in visited:
                    if dfs(node, -1):
                        return True
            return False
            
        
        adj = {x: set() for x in range(len(points))}
        ans = 0
        v = 0
        for distance in dist:
            [x, y, manhattan_dist] = distance
            adj[x].add(y)
            adj[y].add(x)
            if detectCycle(adj):
                adj[x].remove(y)
                adj[y].remove(x)
            else:
                ans += manhattan_dist
                v += 1
                
            if v == len(points)-1:
                break
            
        return ans
            
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def calc(x,y):
            return abs(x[0]-y[0]) + abs(x[1]-y[1])
        #d = collections.defaultdict(dict)
        connections = []
        #seen = set()
        for i in range(len(points)):
            for j in range(i+1,len(points)):
                if i != j:
                    #d[i][j]  = calc(points[i],points[j])
                    connections.append([i,j,calc(points[i],points[j])])
                    
        connections.sort(key = lambda x: x[2])  
        n = len(points)
        parent = [-1]*n
        size = [1]*n
        res = []
        
        def find(x):
            if parent[x] == -1:
                return x
            parent[x] = find(parent[x])
            return parent[x]
        
        def union(x,y):
            px = find(x)
            py = find(y)
            if px == py:
                return False
            if size[px] > size[py]:
                size[px] += size[py]
                parent[py] = px
            else:
                size[py] += size[px]
                parent[px] = py
            return True
        for s,d,w in connections:
            if union( s, d):
                res.append([s,d,w])
        ans = 0
        for a,b,c in res:
            ans += c
            
        
        
        #print(res)
        return ans
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        g = [[] for _ in range(n)]
        for i in range(n-1):
            x0, y0 = points[i]
            for j in range(i+1, n):
                x1, y1 = points[j]
                d = abs(x0-x1)+abs(y0-y1)
                g[i].append((d, j))
                g[j].append((d, i))
        import heapq
        def prim_heap(edge):
            used = [True]*n
            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
        res = prim_heap(g)
        return res
        


class Unifind:
    def __init__(self,n):
        self.arr = list(range(n))
        self.rank = [0]*n
    def union(self,a,b):
        a = self.find(a)
        b = self.find(b)
        
        if self.rank[a]<self.rank[b]:
            a,b = b,a
        
        if self.rank[a]==self.rank[b]:
            self.rank[a]+=1
        
        self.arr[b] = a
        
    def find(self,a):
        if self.arr[a]!=a:
            self.arr[a] = self.find(self.arr[a])
        return self.arr[a]

    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        
        manhatan = lambda x1,y1,x2,y2 : (x1-x2 if x1>x2 else x2-x1) + (y1-y2 if y1>y2 else y2-y1)
        edges = [(manhatan(points[i][0],points[i][1],points[j][0],points[j][1]),i,j) for i in range(len(points)) for j in range(i+1,len(points))]
        heapify(edges)
        #print(edges)
        uf = Unifind(len(points))
        count = 0
        cost = 0
        while count < len(points)-1:
            c,i,j = heappop(edges)
            #if edge adds a cycle(both ends are already in)
            if uf.find(i)!=uf.find(j):
                cost+=c
                count+=1
                uf.union(i,j)
                
        #print(uf.arr)
        return cost
                
                


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        all_edges = []
        for point1 in points:
            for point2 in points:
                if point1 != point2:
                    all_edges.append((abs(point1[0] - point2[0]) + abs(point1[1] - point2[1]), tuple(point1),tuple(point2)))
                    
        all_edges.sort(key=lambda x:(x[0]))
        
        parent = { tuple(point):tuple(point) for point in points }
        rank = {tuple(point):1 for point in points}
        def find(point1):
            if parent[point1] != point1:
                parent[point1] = find(parent[point1])
            return parent[point1]
        
        def union(point1, point2):
            parent1 = find(point1)
            parent2 = find(point2)
            if rank[parent1] > rank[parent2]:
                parent[parent2] = parent1
                rank[parent1] += 1
            else:
                parent[parent1] = parent2
                rank[parent2] += 1
            return
        cost = 0
        count = 0
        for edge in all_edges:
            if count == len(points)-1:
                break
            if find(edge[1]) != find(edge[2]):
                union(edge[1],edge[2])
                cost +=edge[0]
                count +=1
        return cost


class DSU:
    def __init__(self, N):
        self.par = list(range(N))
        self.sz = [1] * N

    def find(self, x):
        if self.par[x] != x:
            self.par[x] = self.find(self.par[x])
        return self.par[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        if xr == yr:
            return False
        if self.sz[xr] < self.sz[yr]:
            xr, yr = yr, xr
        self.par[yr] = xr
        self.sz[xr] += self.sz[yr]
        return True
    
class Solution:
    def minCostConnectPoints(self, points):
        N = len(points)
        
        edges = []
        for i in range(N):
            for j in range(i + 1, N):
                d = abs(points[i][0] - points[j][0])
                d += abs(points[i][1] - points[j][1])
                edges.append([d, i, j])
        edges.sort()

        ans = 0
        dsu = DSU(N)
        for d, u, v in edges:
            if dsu.union(u, v):
                ans += d
        return ans
    
        # n = len(points)
        # adj_matrix = [[0 for _ in range(n)] for _ in range(n)]
        # for i in range(n):
        #     for j in range(n):
        #         if i == j:
        #             continue
        #         adj_matrix[i][j] = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
        # visited = [False] * n
        # visited[0] = True
        # weight = [0] * n
        # for j in range(n):
        #     if j == 0:
        #         weight[j] = float('inf')
        #     else:
        #         weight[j] = adj_matrix[0][j]
        # total = 0
        # visit = 0
        # while not all(visited):
        #     visit = weight.index(min(weight))
        #     total += weight[visit]
        #     visited[visit] = True
        #     for j in range(n):
        #         if weight[j] == float('inf'):
        #             continue
        #         if j == visit:
        #             weight[j] = float('inf')
        #             continue
        #         weight[j] = min(weight[j], adj_matrix[visit][j])
        # return total


from heapq import *

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        result = 0
        if len(points) == 1:
            return result
        
        costHeap = []
        n = len(points)
        cur = 0
        distance = lambda p, np: abs(p[0] - np[0]) + abs(p[1] - np[1])
        visited = [False for _ in range(n)]
        visited[0] = True
        size = 1
        
        for i in range(1, n):
            heappush(costHeap, [distance(points[0], points[i]), i])
        
        while costHeap:
            cost, nextStart = heappop(costHeap)
            # print(cur, nextStart, cost)
            if not visited[nextStart]:
                result += cost
                visited[nextStart] = True
                size += 1
                cur = nextStart
                for i in range(n):
                    heappush(costHeap, [distance(points[cur], points[i]), i])
                if size == n:
                    break
                
        return result
                    


class DSU:
    def __init__(self, n):
        self.p = list(range(n))
    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]
    def union(self, x, y):
        p_x = self.find(x)
        p_y = self.find(y)
        if p_x != p_y:
            self.p[p_x] = p_y
            return True
        return False
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n < 2:
            return 0
        
        def dist(p1, p2):
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        
        dic = {}
        for i in range(n):
            for j in range(i + 1, n):
                dic[(i, j)] = dist(points[i], points[j])
                
        o = sorted(list(dic.items()), key = lambda v: v[1])
        dsu = DSU(n)
        res = 0
        for pts, cost in o:
            p1, p2 = pts
            if dsu.union(p1, p2):
                res += cost
        
        return res
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        edges = []
        for i in range(n):
            for j in range(i+1,n):
                d = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((d,i,j))
        edges.sort()
        
        root = [i for i in range(n)]
        def find(v):
            if root[v] != v:
                root[v] = find(root[v])
            return root[v]
            
        def union(u,v):
            p1 = find(u)
            p2 = find(v)
            if p1 != p2:
                root[p2] = root[p1]
                return True
            return False
        
        res = 0
        for d,u,v in edges:
            if union(u,v):
                res += d
        return res


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        n = len(points)
    
        edges = []
        nodes = set()
        # set up edges with (weight, u, v)
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                dis = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((dis, i, j))
                nodes.add(i)
                nodes.add(j)
        

        # set up union find
        class UnionFindSet:
            def __init__(self, nodes):
                self._parents = {n:n for n in nodes}
                self._ranks = {n:1 for n in nodes}

            def find(self, u):
                while u != self._parents[u]:
                    self._parents[u] = self.find(self._parents[u])
                    u = self._parents[u]
                return u

            def union(self, u, v):
                pu, pv = self.find(u), self.find(v)
                if pu == pv: return False

                if self._ranks[pu] < self._ranks[pv]:
                    self._parents[pu] = pv
                elif self._ranks[pu] > self._ranks[pv]:
                    self._parents[pv] = pu
                else:        
                    self._parents[pv] = pu
                    self._ranks[pu] += 1

                return True

        uf = UnionFindSet(nodes)
        
        # Kruskal Algorithm
        edges.sort()
        cost = 0
        for dis, u, v in edges:
            pu, pv = uf.find(u), uf.find(v)
            if pu == pv:
                continue
            else:
                cost += dis
                uf.union(u,v)

        return cost
            
    
                
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        sets = list(range(len(points)))
        
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                d = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                edges.append([d, i, j])
                
        edges.sort()
        n_edges = 0
        ans = 0
        cur = 0
        
        def find(i):
            while sets[i] != i:
                i = sets[i]
            return i
        
        while n_edges != len(sets) - 1:
            d, i, j = edges[cur]
            # print(i, j, sets)
            if find(i) != find(j):
                sets[find(i)] = find(j)
                ans += d
                n_edges += 1
            cur += 1
        return ans

class Solution:
    def minCostConnectPoints(self, points):
        N = len(points)
        
        edges = []
        for i in range(N):
            for j in range(i + 1, N):
                d = abs(points[i][0] - points[j][0])
                d += abs(points[i][1] - points[j][1])
                edges.append([d, i, j])
        edges.sort()

        ans = 0
        dsu = DSU(N)
        for d, u, v in edges:
            if dsu.union(u, v):
                ans += d
        return ans
    
class DSU:
    def __init__(self, N):
        self.par = list(range(N))
        self.sz = [1] * N

    def find(self, x):
        if self.par[x] != x:
            self.par[x] = self.find(self.par[x])
        return self.par[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        if xr == yr:
            return False
        if self.sz[xr] < self.sz[yr]:
            xr, yr = yr, xr
        self.par[yr] = xr
        self.sz[xr] += self.sz[yr]
        return True

import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def helper(a, b):
            return abs(a[0] - b[0]) + abs(a[1] - b[1])
        edges = []
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                heapq.heappush(edges, (helper(points[i], points[j]), i, j))
        tree = []
        res = 0
        # print(edges)
        while edges:
            dist, i, j = heapq.heappop(edges)
            flag = False
            for p in range(len(tree)):
                s = tree[p]
                if i in s or j in s:
                    q = j if i in s else i
                    if q not in s:
                        set_num = -1
                        for k in range(len(tree)):
                            st = tree[k]
                            if q in st:
                                set_num = k
                                break
                        if set_num != -1:
                            tree[p] = tree[p].union(tree[k])
                            tree.pop(k)
                        else:
                            s.add(q)
                        res += dist
                    flag = True
                    break
            if not flag:
                tree.append({i, j})
                res += dist
            # print(tree)
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        parent = list(range(n))
        rank = [0] * n
        def find(x):
            while parent[x] != x:
                x = parent[x]
            return x
        def union(x, y):
            id_x = find(x)
            id_y = find(y)
            if id_x == id_y:
                return 0
            if rank[id_x] == rank[id_y]:
                parent[id_y] = id_x
                rank[id_x] += 1
            elif rank[id_x] > rank[id_y]:
                parent[id_y] = id_x
            else:
                parent[id_x] = id_y
            return 1
        edges = []
        for i in range(n):
            for j in range(i + 1, n):
                edges.append((abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]), i, j))
        edges = sorted(edges, key=lambda x: x[0])
        cost = 0
        for edge in edges:
            if union(edge[1], edge[2]):
                cost += edge[0]
        return cost    


class Solution:
    def minCostConnectPoints(self, points):
        helper = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        points, res = [[p, helper(p, points[0])] for p in points], 0
        while points:
            minI = min(range(len(points)), key = lambda i: points[i][1])
            p1, cost = points.pop(minI)
            res += cost
            for i, (p2, _) in enumerate(points):
                points[i][1] = min(points[i][1], helper(p1, p2))
        return res

class dsu:
    def __init__(self,n):
        self.parent =[-1 for i in range(n)]
        self.size = [0 for i in range(n)]

    def make_set(self,node):
        self.parent[node] = node

    def find(self,a):
        if self.parent[a] == a:
            return self.parent[a]
        else:
            self.parent[a] = self.find(self.parent[a])
            return self.parent[a]

    def union(self,a,b):
        a = self.find(a)
        b = self.find(b)
        if a!=b:
            # if self.size[a] > self.size[b]:
            #     temp = a
            #     a = b
            #     b = temp
            self.parent[b] =self.parent[a]
            # self.size[a] = self.size[a] + self.size[b]


class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:
        n = len(p)
        if n<=1:
            return 0
        tree = dsu(n)
        edges = []
        for i in range(len( p)):
            for j in range(i+1,len(p)):
                edges.append([abs(p[i][0] - p[j][0]) + abs(p[i][1] -  p[j][1]),i,j])
        edges.sort()
        done = 0
        ans = 0
        for i in range(n):
            tree.make_set(i)
        # print(tree.parent)
        # print(edges)
        for i in edges:
            
            if tree.find(i[1]) != tree.find(i[2]):
                done = done + 1
                ans =ans + i[0]
                tree.union(i[1],i[2])
            # print(tree.parent)
        return ans
                
            


class DSU:
    def __init__(self, N):
        self.par = list(range(N))
        self.sz = [1]*N
        
    def find(self, x):
        if self.par[x] != x:
            self.par[x] = self.find(self.par[x])
        return self.par[x]
        
    def union(self, x, y):
        xr = self.find(x)
        yr = self.find(y)
        
        if xr == yr:
            return False
        if self.sz[xr] < self.sz[yr]:
            xr, yr = yr, xr
        
        self.par[yr] = xr
        self.sz[xr] += self.sz[yr]
        self.sz[yr] = self.sz[xr]
        return True
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        edges = []
        for i in range(N):
            for j in range(i+1,N):
                d = abs(points[i][0]-points[j][0])
                d += abs(points[i][1]-points[j][1])
                edges.append([d,i,j])
        edges.sort()
        
        dsu = DSU(N)
        ans = 0
        for d,u,v in edges:
            if dsu.union(u,v):
                ans += d
        
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        graph = defaultdict(list)
        
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                x1,y1 = points[i]
                x2,y2 = points[j]
                manhattan_dist = abs(x1-x2)+abs(y1-y2)

                graph[i].append((manhattan_dist, j))
                graph[j].append((manhattan_dist, i))
                    
        visited = set()
        heap = [(0, 0)]
        cost = 0
        
        while heap:
            distance, current_node = heapq.heappop(heap)
            
            if current_node not in visited:
                
                visited.add(current_node)
                cost += distance

                for dist, neigh in graph[current_node]:
                    if neigh not in visited:
                        heapq.heappush(heap, (dist,neigh))
                        
        return cost

class DSU:
    def __init__(self,n):
        self.par = [x for x in range(n)]
    
    def find(self,x):
        if self.par[x]!=x:
            self.par[x] = self.find(self.par[x])
        return self.par[x]
    
    def union(self,x,y):
        xp,yp = self.find(x),self.find(y)
        if xp == yp :return False
        self.par[yp] = xp
        return True

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        #MST
        n = len(points)
        edges = []
           
        dist = lambda a,b,c,d: abs(a-c)+abs(b-d)
        for i,p1 in enumerate(points):
            for j in range(i+1,n):
                if (i==j):continue
                p2 = points[j]
                edges.append([ dist(*p1,*p2),i,j])
            
        def MST():
            res = 0 
            dsu = DSU(n)
            for weight,p1,p2 in sorted(edges):
                if dsu.union(p1,p2):
                    res += weight
            return res
        
        return MST()


class DSU:
    def __init__(self, N):
        self.par = list(range(N))
        self.sz = [1] * N

    def find(self, x):
        if self.par[x] != x:
            self.par[x] = self.find(self.par[x])
        return self.par[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        if xr == yr:
            return False
        if self.sz[xr] < self.sz[yr]:
            xr, yr = yr, xr
        self.par[yr] = xr
        self.sz[xr] += self.sz[yr]
        self.sz[yr] = self.sz[xr]
        return True

    def size(self, x):
        return self.sz[self.find(x)]

class Solution:
    # Kruskal algorithm, union find, time O(n^2), space O(n^2)
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        edges = []
        for i in range(n - 1):
            for j in range(i + 1, n):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((dist, i, j))
        edges.sort()
        m = len(edges)
        dsu = DSU(n)
        res = 0
        for d, u, v in edges:
            if dsu.union(u, v):
                res += d
        return res
            
        
        


from heapq import heapify, heappush, heappop
from collections import defaultdict
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def distance(point1, point2):
            x1, y1 = point1
            x2, y2 = point2
            return abs(x1-x2) + abs(y1-y2)
        
        n = len(points)
        if n == 1:
            return 0
        
        cost = defaultdict(list)
        for i in range(n):
            point1 = points[i]
            for j in range(i+1, n):
                point2 = points[j]
                d = distance(point1, point2)
                cost[tuple(point1)].append((d, point2))
                cost[tuple(point2)].append((d, point1))
                
                
            
        ans = 0
        visited = {tuple(points[0])}
        heap = cost[tuple(points[0])]
        heapify(heap)
        
        while len(visited) != n:
            d, v = heappop(heap)
            if tuple(v) not in visited:
                visited.add(tuple(v))
                ans += d
                for record in cost[tuple(v)]:
                    heappush(heap, record)
        
        return ans
                    
                    
                
                
        
        
        
        
        
        
            
            
            
                        
                    
            
            
        
        
        


import heapq

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        manhattan = lambda p1, p2 : abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        pq = []
        p1 = points[0]
        seen = {0,}
        horizon = set(range(1, len(points)))
        for idx in horizon:
            p2 = points[idx]
            heapq.heappush(pq, (manhattan(p1, p2), idx))

                
        total_dist = 0
        while horizon:
            while pq[0][-1] in seen:
                heapq.heappop(pq)
            dist, min_idx = heapq.heappop(pq)
            
            
            total_dist += dist
            seen.add(min_idx)
            horizon.remove(min_idx)
            
            p1 = points[min_idx]
            
            for idx in horizon: 
                p2 = points[idx]
                heapq.heappush(pq, (manhattan(p1, p2), idx))
                    
        return total_dist
        
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        #compute cost:
        n=len(points)
        g=[]
        for i in range(n):
            for j in range(i+1,n):
                w=abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                g.append([i,j,w])
        g=sorted(g,key=lambda x:x[2])
        par=list(range(n))
        #print(par)
        #print(g)
        def root(i):
            while par[i]!=i:
                par[i]=par[par[i]]
                i=par[i]
            return i 
        def union(i,j):
            pi,pj=root(i),root(j)
            par[pi]=par[pj]
        cost=0
        for i,j,w in g:
            if root(i)!=root(j):
                cost+=w
                #union i and j:
                union(i,j)
                
        return cost
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        graph = defaultdict(list)
        
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                x1,y1 = points[i]
                x2,y2 = points[j]
                manhattan_dist = abs(x1-x2)+abs(y1-y2)

                graph[i].append((manhattan_dist, j))
                graph[j].append((manhattan_dist, i))
                    
        visited = set()
        heap = [(0, 0)]
        cost = 0
        
        while heap:
            distance, current_node = heapq.heappop(heap)
            
            if current_node not in visited:
                
                visited.add(current_node)
                cost += distance

                for dist, neigh in graph[current_node]:
                    if neigh not in visited:
                        heapq.heappush(heap, (dist,neigh))
                        
        return cost


class Solution:
    def minCostConnectPoints(self, points) -> int:
        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        n, c = len(points), collections.defaultdict(list)
        for i in range(n):
            for j in range(i+1, n):
                d = manhattan(points[i], points[j])
                c[i].append((d, j))
                c[j].append((d, i))
        cnt, ans, visited, heap = 1, 0, [0] * n, c[0]
        visited[0] = 1
        heapq.heapify(heap)
        while heap:
            d, j = heapq.heappop(heap)
            if not visited[j]:
                visited[j], cnt, ans = 1, cnt+1, ans+d
                for record in c[j]: heapq.heappush(heap, record)
            if cnt >= n: break        
        return ans

class Solution:
    
    def kruskal(self, n, edges):
        def find(x):
            if x != parent[x]:
                parent[x] = find(parent[x])
            return parent[x]
        def union(x, y):
            px, py = find(x), find(y)
            if px == py:
                return False
            parent[px] = py
            return True
        mst_cost = 0
        parent = list(range(n))
        for f, t, w in edges:
            if union(f, t):
                mst_cost += w
        return mst_cost
        
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        manhattan = lambda xx, yy: abs(xx[0] - yy[0]) + abs(xx[1] - yy[1])
        
        if (n := len(points)) == 1:
            return 0
        
        edges = []
        for i in range(n):
            for j in range(i + 1, n):
                x, y = points[i], points[j]
                edges.append([i, j, manhattan(x, y)])
        edges.sort(key = lambda x: x[2])
        return self.kruskal(n, edges)
        
        # graph = collections.defaultdict(list)
        # for i in range(n):
        #     for j in range(i + 1, n):
        #         x, y = points[i], points[j]
        #         graph[i].append((manhattan(x, y), j))
        #         graph[j].append((manhattan(x, y), i))
        # return prim(graph)
            
                
#         def prim(graph):
#             V = {0}
#             edges = graph[0]
#             heapify(edges)
#             sum_cost = 0
#             while edges:
#                 cost, p2 = heappop(edges)
#                 if p2 in V:
#                     continue
#                 sum_cost += cost
#                 V.add(p2)
#                 for new_edge in graph[p2]:
#                     if new_edge[1] not in V:
#                         heappush(edges, new_edge)
#                 if len(V) == len(graph):
#                     break
#             return sum_cost


from sortedcontainers import SortedList
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        ret, n = 0, len(points)
        
        uf = {}
        def find(x):
            uf.setdefault(x, x)
            if uf[x] != x: uf[x] = find(uf[x])
            return uf[x]
        def union(x, y): # x->y
            uf[find(x)] = find(y)
        
        def dis(a, b):
            return abs(a[0]-b[0])+abs(a[1]-b[1])
        
        edges = []
        for i in range(n):
            for j in range(i+1, n):
                edges.append((dis(points[i], points[j]), i, j))
        
        edges.sort()
        for cost, u, v in edges:
            if find(u) != find(v):
                ret += cost
                union(u, v)

        return ret

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) == 2:
            return abs(points[0][0] - points[1][0]) + abs(points[1][1] - points[0][1])
        if len(points) == 1:
            return 0
        connSet = set()
        unConnSet = set()
        for i in range(len(points)):
            unConnSet.add(i)
        #print(unConnSet)
        myHeap = []
        
        for i in range(len(points)):
            for j in range(i):
                lenCalc = abs(points[i][0] - points[j][0]) + abs(points[j][1] - points[i][1])
                if lenCalc>0:
                    myHeap.append([lenCalc,(i,j)])
        #print(myHeap)
        myHeap.sort(key = lambda x: x[0])
        #print(myHeap)
        
        p1 = myHeap[0][1][0]
        p2 = myHeap[0][1][1]
        connSet.add(p1)
        connSet.add(p2)
        #print(p2)
        unConnSet.remove(p1)
        unConnSet.remove(p2)
        itt =0
        res = myHeap[0][0]
        myHeap.pop(0)
        while(itt < len(myHeap) and len(unConnSet)>0):
            p1 = myHeap[itt][1][0]
            p2 = myHeap[itt][1][1]
            
            if p1 in connSet and p2 not in connSet:
                connSet.add(p2)
                unConnSet.remove(p2)
                res+=myHeap[itt][0]
                myHeap.pop(itt)
                itt = -1
            if p2 in connSet and p1 not in connSet:
                connSet.add(p1)
                unConnSet.remove(p1)
                res+=myHeap[itt][0]
                myHeap.pop(itt)
                itt = -1
            itt+=1
        return res
            
            
            
            
            
    
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        uf = list(range(n))
        def find(x):
            if uf[x] != x:
                uf[x] = find(uf[x])
            return uf[x]
        def union(x, y):
            tx = find(x)
            ty = find(y)
            if tx != ty:
                uf[tx] = ty

        def l1dist(x, y):
            return abs(x[0]-y[0])+abs(x[1]-y[1])
        
        dist = []
        for i in range(n):
            for j in range(i+1, n):
                dist.append((l1dist(points[i], points[j]), i, j))

        dist.sort()
        ans = 0
        cnt = 0
        for d, x, y in dist:
            if cnt == n:
                break
            if find(x) != find(y):
                union(x, y)
                ans += d
                cnt += 1
        return ans
            
                
            


import heapq
from collections import defaultdict

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def manhattan(x,y):
            return abs(x[0] - y[0]) + abs(x[1] - y[1])
        
        dist_dict = defaultdict(list)
        n_points = len(points)
        
        for i in range(n_points):
            for j in range(i+1, n_points):
                dist_curr = manhattan(points[i], points[j])
                dist_dict[i].append((dist_curr, j))
                dist_dict[j].append((dist_curr, i))
        
        counter, visited, answer, heap = 1, [0] * n_points, 0, dist_dict[0]
        heapq.heapify(heap)
        visited[0] = 1
        
        while heap:
            dist_curr, point_curr = heapq.heappop(heap)
            
            if not visited[point_curr]:
                counter += 1
                visited[point_curr] = 1
                answer += dist_curr
                
                for candidate in dist_dict[point_curr]:
                    heapq.heappush(heap, candidate)
            
            if counter >= n_points:
                break
        return answer

        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        conn = [points[0]]
        if len(points) == 1:
            return 0
        points = points[1:]
        res = 0
        dists = {str(p):abs(p[0]-conn[0][0])+abs(p[1]-conn[0][1]) for p in points}
        print(dists)
        while len(points) > 0:
            best = 1e8
            bestc = -1
            bestp = -1
            for j, p in enumerate(points):
                if dists[str(p)] < best:
                        bestp = j
                        best = dists[str(p)]
            res += best
            conn.append(points[bestp])
            np = points[bestp]
            del points[bestp]
            for p in points:
                dists[str(p)] = min(dists[str(p)], abs(p[0]-np[0]) + abs(p[1]-np[1]))
            
        return res

class Solution:
    def minCostConnectPoints(self, points):
        helper = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        points = [[p, helper(p, points[0])] for p in points]
        total_cost = 0
        while points:
            minI = min(range(len(points)), key = lambda i: points[i][1])
            p1, cost = points.pop(minI)
            total_cost += cost
            for i, (p2, _) in enumerate(points):
                points[i][1] = min(points[i][1], helper(p1, p2))
        return total_cost

class DisjointSet:
    def __init__(self, points):
        self.parent = {}
        self.rank = {}
        for point in points:
            self.parent[point] = point
            self.rank[point] = 1

    def find(self, x):
        if self.parent[x] == x:
            return x
        self.parent[x] = self.find(self.parent[x])
        return self.parent[x]

    def union(self, x, y):
        x_set = self.find(x)
        y_set = self.find(y)

        if self.rank[x_set] < self.rank[y_set]:
            self.parent[x_set] = y_set
        elif self.rank[x_set] > self.rank[y_set]:
            self.parent[y_set] = x_set
        else:
            self.parent[x_set] = y_set
            self.rank[y_set] += 1

        
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        points = [tuple(point) for point in points]
        disjoint_set = DisjointSet(points)
        
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                distance = self.distance(points[i], points[j])
                edges.append([distance, points[i], points[j]])
        
        edges.sort()
        
        answer = 0
        i = 0
        times = 0
        while times < len(points)-1:
            if times == len(points) - 1:
                return answer
            distance, nodeA, nodeB = edges[i][0], edges[i][1], edges[i][2]
            if disjoint_set.find(nodeA) != disjoint_set.find(nodeB):
                times += 1
                answer += distance
                disjoint_set.union(nodeA, nodeB)
            i += 1
                
        return answer
                
    def distance(self, pointA, pointB):
        return abs(pointA[0] - pointB[0]) + abs(pointA[1] - pointB[1])


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # seems dijkstra with all the neighbors connected? 
        # try minimum spanning treee
        node = 0
        # build the graph first
        seen = set([0])
        edges = [(abs(points[0][0] - points[x][0]) + abs(points[0][1] - points[x][1]), 0, x) for x in range(1, len(points))]
        heapq.heapify(edges)
        ans = 0
        while edges:
            cost, frm, to = heapq.heappop(edges)
            if to not in seen:
                seen.add(to)
                ans += cost
                for to_next, (x, y) in enumerate(points):
                    if to_next not in seen:
                        heapq.heappush(edges, (abs(x-points[to][0]) + abs(y-points[to][1]), to, to_next))

        return ans
        
        
        
            
            



class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def distance(p1, p2):
            return abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        
        ans = 0
        h = []
        heappush(h, (0, points[0]))
        visited = set()
        
        while h:
            d, p = heappop(h)
            if (p[0], p[1]) in visited:
                continue
            visited.add((p[0], p[1]))
            ans += d
            
            for point in points:
                if (point[0], point[1]) not in visited:
                    heappush(h, (distance(p, point), point))
                    
        return ans
                    
        
                
        


# class Solution:
#     def minCostConnectPoints(self, points: List[List[int]]) -> int:
#         manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
#         n, c = len(points), collections.defaultdict(list)
#         for i in range(n):
#             for j in range(i+1, n):
#                 d = manhattan(points[i], points[j])
#                 c[i].append((d, j))
#                 c[j].append((d, i))
#         cnt, ans, visited, heap = 1, 0, [0] * n, c[0]
#         visited[0] = 1
#         heapq.heapify(heap)
#         while heap:
#             d, j = heapq.heappop(heap)
#             if not visited[j]:
#                 visited[j], cnt, ans = 1, cnt+1, ans+d
#                 for record in c[j]: heapq.heappush(heap, record)
#             if cnt >= n: break        
#         return ans

class DisjointSet:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [1 for _ in range(n)]
    
    # make a and b part of the same component
    # union by rank optimization
    def union(self, a, b):
        pa = self.find(a)
        pb = self.find(b)
        if pa == pb: return
        if self.rank[pa] > self.rank[pb]:
            self.parent[pb] = pa
            self.rank[pa] += self.rank[pb]
        else:
            self.parent[pa] = pb
            self.rank[pb] += self.rank[pa]
    
    # find the representative of the 
    # path compression optimization
    def find(self, a):
        if self.parent[a] == a:
            return a
        
        self.parent[a] = self.find(self.parent[a])
        return self.parent[a]
    

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        n = len(points)
        edges = []
        for i in range(n):
            for j in range(i+1, n):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((dist, i, j))
        
        # sort based on cost (i.e. distance)
        edges.sort()
        
        # using Kruskal's algorithm to find the cost of Minimum Spanning Tree
        res = 0
        ds = DisjointSet(n)
        for cost, u, v in edges:
            if ds.find(u) != ds.find(v):
                ds.union(u, v)
                res += cost
        
        return res

# kruskal 
class Solution:
    def minCostConnectPoints(self, a: List[List[int]]) -> int:                        
        n, q = len(a), []
        for i in range(n-1):
            for j in range(i+1, n):
                q.append((abs(a[i][0]-a[j][0]) + abs(a[i][1]-a[j][1]), i, j))
                        
        def union(u, v):
            UF[find(v)] = UF[find(u)]
        def find(u):
            if u != UF[u]: UF[u] = find(UF[u])
            return UF[u]
        
        heapify(q)
        ans, vis, UF = 0, set(), {i: i for i in range(n)}
        while q and len(set(find(u) for u in UF)) != 1:
            val, i, j = heappop(q)
            if find(i) != find(j):
                union(i, j)
                vis |= set([i, j])
                ans += val
        return ans                        

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        dist = collections.defaultdict(list)
        n = len(points)
        for i in range(n):
            for j in range(i+1,n):
                d = abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                dist[i].append((j,d))
                dist[j].append((i,d))
        # print(dist)
        ret = 0
        visited = set([])
        pq = [(0,0)] # dist to s, index, dist to neighbour
        while pq:
            w,u = heapq.heappop(pq)
            if u not in visited:
                ret += w
                visited.add(u)
                for v,d in dist[u]:
                    if v not in visited: heapq.heappush(pq,(d,v))
        return ret
                
                


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # spaning tree
        n = len(points)
        hq = [(0, points[0][0], points[0][1])]
        seen = set()
        total = 0
        while hq:
            dist, x, y = heappop(hq)
            if (x, y) in seen: continue
            total += dist
            seen.add((x, y))
            for nx, ny in points:
                if (nx,ny) not in seen:
                    dist = abs(nx - x) + abs(ny - y)
                    heappush(hq, (dist, nx, ny))
        return total

class UF:
    def __init__(self):
        self.ranks = {}
        self.pnts = {}
        self.sz = {}

    def find_make_set(self, x):
        if not x in self.pnts:
            self.pnts[x] = None
            self.ranks[x] = 0
            self.sz[x] = 1

        if self.pnts[x] is None:
            return x

        self.pnts[x] = self.find_make_set(self.pnts[x])
        return self.pnts[x]

    def union(self, x, y):
        ra = self.find_make_set(x)
        rb = self.find_make_set(y)

        if ra == rb:
            return ra

        if self.ranks[ra] > self.ranks[rb]:
            self.pnts[rb] = ra
            self.sz[ra] += self.sz[rb]
            return ra

        self.pnts[ra] = rb
        self.sz[rb] += self.sz[ra]
        if self.ranks[ra] == self.ranks[rb]:
            self.ranks[rb] += 1

        return rb


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:

        base = 10 ** 7

        n = len(points)

        egs = []
        for i in range(n):
            for j in range(n):
                if i == j:
                    continue

                u = points[i]
                v = points[j]

                ua = points[i][0] + base * points[i][1]
                va = points[j][0] + base * points[j][1]

                t = (ua, va), abs(u[0] - v[0])  + abs(u[1] - v[1])
                egs.append(t)

        egs.sort(key=lambda x: x[1])

        uf = UF()
        ans = 0

        for e, w in egs:
            u, v = e
            ru = uf.find_make_set(u)
            rv = uf.find_make_set(v)
            if ru != rv:
                uf.union(u, v)
                ans += w
            else:
                if uf.sz[ru] == n:
                    break

        return ans



class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        uf = [i for i in range(n)]
        
        def union(a,b):
            a,b = find(a),find(b)
            uf[a] = b
        
        def find(a):
            if uf[a] != a:
                uf[a] = find(uf[a])
            return uf[a]
        
        edges = []
        
        for i in range(n):
            for j in range(i+1,n):
                edges.append((abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1]),i,j))
        
        edges = sorted(edges)
        c = 0
        for a,x,y in edges:
            if find(x) != find(y):
                c += a
                union(x,y)
        return c


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def dist(u, v):
            x, y = points[u]
            x2, y2 = points[v]
            return abs(x - x2) + abs(y - y2)
        
        n = len(points)
        visited = [False] * (n)
        distto = [0] + [10 ** 7] * (n - 1)
        
        ans = 0
        for _ in range(n):
            best, idx = 10 ** 7, -1
            for u in range(n):
                if not visited[u] and distto[u] < best:
                    best, idx = distto[u], u
            visited[idx] = True
            ans += best
            for v in range(n):
                if not visited[v]:
                    distto[v] = min(distto[v], dist(idx, v))
                
        return ans


# int find(vector<int> &ds, int i) {
#     return ds[i] < 0 ? i : ds[i] = find(ds, ds[i]);
# }
# int minCostConnectPoints(vector<vector<int>>& ps) {
#     int n = ps.size(), res = 0;
#     vector<int> ds(n, -1);
#     vector<array<int, 3>> arr;
#     for (auto i = 0; i < n; ++i)
#         for (auto j = i + 1; j < n; ++j) {
#             arr.push_back({abs(ps[i][0] - ps[j][0]) + abs(ps[i][1] - ps[j][1]), i, j});
#         }
#     make_heap(begin(arr), end(arr), greater<array<int, 3>>());
#     while (!arr.empty()) {
#         pop_heap(begin(arr), end(arr), greater<array<int, 3>>());
#         auto [dist, i, j] = arr.back();
#         arr.pop_back();
#         i = find(ds, i), j = find(ds, j);
#         if (i != j) {
#             res += dist;
#             ds[i] += ds[j];
#             ds[j] = i;
#             if (ds[i] == -n)
#                 break;
#         }
#     }
#     return res;
# }

class Solution:
    def minCostConnectPoints(self, a: List[List[int]]) -> int:                        
        n, q = len(a), []
        for i in range(n-1):
            for j in range(i+1, n):
                q.append((abs(a[i][0]-a[j][0]) + abs(a[i][1]-a[j][1]), i, j))
        UF = {i: i for i in range(n)}
        def union(u, v):
            UF[find(v)] = UF[find(u)]
        def find(u):
            if u != UF[u]: UF[u] = find(UF[u])
            return UF[u]
        heapify(q)
        ans, vis = 0, set()
        while q and len(set(find(u) for u in UF)) != 1:
            val, i, j = heappop(q)
            if find(i) != find(j):
                union(i, j)
                vis |= set([i, j])
                ans += val
                # print(ans, i, j, q)
        return ans
            


class Solution:
    def minCostConnectPoints(self, pt: List[List[int]]) -> int:
        if len(pt)==1:
            return 0
        l = []
        for i in range(len(pt)):
            for j in range(len(pt)):
                l.append((i,j,abs(pt[i][0]-pt[j][0])+abs(pt[i][1]-pt[j][1])))
        
        parents = list(range(len(pt)))
        wt = [0 for i in range(len(pt))]
        # print(l)
        def find(p):
            if p!=parents[p]:
                parents[p] = find(parents[p])
            return parents[p]
        
        cost = 0
        for u,v,dist in sorted(l, key=lambda x:x[2]):#sorted(l, key = lamda x:x[2]):
            pu,pv=find(u),find(v)
            if pu==pv:
                continue
            print((pu,pv,dist))
            cost+=dist
            if wt[pu]>=wt[pv]:
                parents[pu]=pv
                wt[pu] +=1
            else:
                parents[pv]=pu
                wt[pv] +=1
        return cost


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        heap=[]
        n=len(points)
        for i in range(n-1):
            x1,y1=points[i]
            for j in range(i+1,n):
                x2,y2=points[j]
                heapq.heappush(heap, (abs(x1-x2)+abs(y1-y2), i, j))
        ancient=list(range(n))
        def find(x):
            if x!=ancient[x]:
                ancient[x]=find(ancient[x])
            return ancient[x]
        ans=0
        while heap:
            d,i,j=heapq.heappop(heap)
            ai,aj=find(i), find(j)
            if ai!=aj:
                ancient[ai]=aj
                ans+=d
        return ans

from heapq import *
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def get_distance(p1,p2):
            return abs(p2[1]-p1[1]) + abs(p2[0] - p1[0])
        
        # edges
        edges = []
        
        for i in range(0,len(points)):
            for j in range(i+1,len(points)):
                # edge = (distance, idx of point 1, idx of point 2)
                
                # sort edges
                heappush(edges, (get_distance(points[i],points[j]), i, j))
        
        # store all the parents for each point
        parents = [i for i in range(len(points))]
        
        # find the original parent of this element i.e. if its part of the currently beimg built MST
        def find(point):
            nonlocal parents
            if parents[point] != point:
                parents[point] = find(parents[point])
            return parents[point]
            
        # add a new point to the union
        def union(x,y):
            nonlocal parents
            parents[find(x)] = find(y)
        
        cost = 0
        while edges:
            dist, p1, p2 = heappop(edges)
            # if p1 and p2 aren't part of the same set, add p2 to the set.
            if find(p1) != find(p2):
                union(p1,p2)
                cost += dist
            
        return cost
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        L = len(points)
        res = 0
        con = {}
        father = {i:i for i in range(L)}
        def find(pidx):
            if father[pidx] == pidx:
                return pidx
            return find(father[pidx])
        def union(p,q):
            if p != q:
                if p < q:
                    father[q] = p
                else:
                    father[p] = q
        for i,p in enumerate(points):
            for j,p2 in enumerate(points):
                if i!=j and (j,i) not in list(con.keys()):
                    d = self.dis(p,p2)
                    con[(i,j)] = d
        k = sorted(con, key = lambda x :con[x])
        for e in k:
            x,y = e[0],e[1]
            fx, fy= find(x), find(y)
            if fx!=fy:
                union(fx,fy)
                res += con[e]
        return res
            
    def dis(self, p, x):
        d = abs(x[1]-p[1]) + abs(x[0]-p[0])
        return d


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        heap = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                x1, y1 = points[i]
                x2, y2 = points[j]
            
                dist = abs(x1-x2) + abs(y1-y2)
                heap.append((dist, i, j))
        
        heapify(heap)
        uf = UnionFind(len(points))
        res = 0
        
        while heap:
            dist, x, y = heappop(heap)
            if uf.union(x, y):
                res += dist
                
        return res
    
class UnionFind:
    def __init__(self, n):
        self.parent = list(range(n))
        self.rank = [0]*n
        
    def union(self, x, y):
        root_x = self.find(x)
        root_y = self.find(y)
        
        if root_x == root_y:
            return False
        
        if self.rank[root_x] > self.rank[root_y]:
            self.parent[root_y] = root_x
        
        else:
            self.parent[root_x] = root_y
            if self.rank[root_x] == self.rank[root_y]:
                self.rank[root_y] += 1
        
        return True
    
    def find(self, x):
        while x != self.parent[x]:
            self.parent[x] = self.parent[self.parent[x]]
            x = self.parent[x]
        return x
                
        
        
        
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        edges = [[] for _ in range(n)]
        for i in range(n):
            for j in range(i + 1, n):
                x1, y1 = points[i]
                x2, y2 = points[j]
                dist = abs(x1 - x2) + abs(y1 - y2)
                edges[i].append([dist, j])
                edges[j].append([dist, i])
        
        cost = 0
        tree = {0}
        
        pq = []
        for c, v in edges[0]:
            pq.append([c, v])
        heapify(pq)
        
        while len(tree) < n:
            c, v = heappop(pq)
            if v in tree: continue
            tree.add(v)
            cost += c
            for d, u in edges[v]:
                if not u in tree:
                    heappush(pq, [d, u])
        return cost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        import heapq

        visited = [False] * len(points)
        heap = [(0, 0)]
        res = 0

        while heap:
            dist, node = heapq.heappop(heap)
            if not visited[node]:
                res += dist
                visited[node] = True
                for neighbor in range(len(points)):
                    if not visited[neighbor]:
                        heapq.heappush(heap,
                                       (sum([abs(points[node][i] - points[neighbor][i]) for i in range(2)]), neighbor))

        return res

# kruskal 
class Solution:
    def minCostConnectPoints(self, a: List[List[int]]) -> int:                        
        n, q = len(a), []
        for i in range(n-1):
            for j in range(i+1, n):
                q.append((abs(a[i][0]-a[j][0]) + abs(a[i][1]-a[j][1]), i, j))
                
        UF = {i: i for i in range(n)}
        def union(u, v):
            UF[find(v)] = UF[find(u)]
        def find(u):
            if u != UF[u]: UF[u] = find(UF[u])
            return UF[u]
        
        heapify(q)
        ans, vis = 0, set()        
        while q and len(set(find(u) for u in UF)) != 1:
            val, i, j = heappop(q)
            if find(i) != find(j):
                union(i, j)
                vis |= set([i, j])
                ans += val
        return ans                        

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        
        from collections import defaultdict
        
        import heapq
        
        def find(x):
            if G[x] != x:
                G[x] = find(G[x])
            return G[x]
        
        def union(x, y):
            x, y = find(x), find(y)
            if x == y:
                return False
            G[y] = x
            return True
        
        G = list(range(len(points)))
        HQ = []
        for i in range(len(points) - 1):
            for j in range(i + 1, len(points)):
                x1, y1 = points[i]
                x2, y2 = points[j]
                dist = abs(x1 - x2) + abs(y1 - y2)
                heapq.heappush(HQ, (dist, i, j))
        
        res = 0
        while HQ:
            d, i, j = heapq.heappop(HQ)
            if union(i, j):
                res += d
        
        return res

from heapq import *
class Solution:
    def minCostConnectPoints(self, points):
        N = len(points)
        parent = [i for i in range(N)]
        def find(v):
            while parent[v] != parent[parent[v]]:
                parent[v] = parent[parent[v]]
            return parent[v]
        dist = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        heap, total_cost = [], 0
        for i1, p1 in enumerate(points):
            for i2, p2 in enumerate(points[i1+1:], start = i1+1):
                heappush(heap, (dist(p1, p2), i1, i2))
        while heap:
            cost, u, v = heappop(heap)
            pu, pv = find(u), find(v)
            if pu != pv:
                parent[pu] = pv
                N -= 1
                total_cost += cost
                if N == 0:
                    break
        return total_cost


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        
        edges = []
        for i in range(n - 1):
            for j in range(i + 1, n):
                u, v = points[i]
                p, q = points[j]
                w = abs(p - u) + abs(q - v)
                edges.append((w, i, j))

        path = {u:u for u in range(n)}
        rank = {u:0 for u in range(n)}
        
        def find(u: int) -> int:
            if u != path[u]:
                path[u] = find(path[u])
            return path[u]

        def union(u: int, v: int) -> None:
            i, j = find(u), find(v)
            if rank[i] > rank[j]:
                path[j] = i
            else:
                path[i] = j
                if rank[i] == rank[j]:
                    rank[i] += 1

        costs = 0
        edges.sort()
        for w, u, v in edges:
            if find(u) != find(v):
                costs += w
                union(u, v)
        return costs


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        all_edges = []
        for point1 in points:
            for point2 in points:
                if point1 != point2:
                    all_edges.append((abs(point1[0] - point2[0]) + abs(point1[1] - point2[1]), tuple(point1),tuple(point2)))
                    
        all_edges.sort(key=lambda x:(x[0]))
        
        parent = { tuple(point):tuple(point) for point in points }
        rank = {tuple(point):1 for point in points}
        children = {tuple(point):1 for point in points}
        def find(point1):
            if parent[point1] != point1:
                parent[point1] = find(parent[point1])
            return parent[point1]
        finish = False
        def union(point1, point2):
            parent1 = find(point1)
            parent2 = find(point2)
            if rank[parent1] > rank[parent2]:
                parent[parent2] = parent1
                rank[parent1] += 1
                children[parent1] +=children[parent2]
            else:
                parent[parent1] = parent2
                rank[parent2] += 1
                children[parent2] +=children[parent1]
            return
        cost = 0
        count = 0
        for edge in all_edges:
            if count == len(points)-1:
                break
            if find(edge[1]) != find(edge[2]):
                union(edge[1],edge[2])
                cost +=edge[0]
                count +=1
        return cost


class Solution:
    def minCostConnectPoints(self, pt: List[List[int]]) -> int:
        if len(pt)==1:
            return 0
        l = []
        for i in range(len(pt)):
            for j in range(len(pt)):
                l.append((i,j,abs(pt[i][0]-pt[j][0])+abs(pt[i][1]-pt[j][1])))
        
        parents = list(range(len(pt)))
        # wt = [0 for i in range(len(pt))]
        # print(l)
        def find(p):
            if p!=parents[p]:
                parents[p] = find(parents[p])
            return parents[p]
        
        cost = 0
        for u,v,dist in sorted(l, key=lambda x:x[2]):#sorted(l, key = lamda x:x[2]):
            pu,pv=find(u),find(v)
            if pu==pv:
                continue
            print((pu,pv,dist))
            cost+=dist
            parents[pu]=pv
        return cost


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        visited=[False]*len(points)
        
        def manhattan(x,y):
            return abs(points[x][0]-points[y][0])+abs(points[x][1]-points[y][1])
        
        d=[[0 for j in range(len(points))] for i in range(len(points))]
        for i in range(len(points)):
            for j in range(i+1,len(points)):
                
                p=manhattan(i,j)
               # print(p)
                d[i][j]=p
                d[j][i]=p
            
        q=[]
        
        heapq.heappush(q,(0,0))
        m={}
        
        while q:
            dist,j=heapq.heappop(q)
            if j in m:
                continue
            m[j]=dist
          #  print(j,m[j])
            for i in range(len(points)):
                if i not in m:
                    heapq.heappush(q,(d[j][i],i))
        #print(m)
        return sum(m.values()) if len(m)==len(points) else 0
        
        


from typing import List

class DS:
    
    def __init__(self, n):
        self.sizes = [1] * n
        self.roots = list(range(n))
        
    def find(self, v):
        root = v
        while root != self.roots[root]:
            self.roots[root] = self.roots[self.roots[root]]
            root = self.roots[root]
        return root
    
    def union(self, u, v):
        root_u, root_v = self.find(u), self.find(v)
        if root_u != root_v: 
            s_root, l_root = (root_u, root_v) if self.sizes[root_u] < self.sizes[root_v] else (root_v, root_u)
            self.roots[s_root] = l_root
            self.sizes[l_root] += self.sizes[s_root]
            
    def connected(self, u, v):
        return self.find(u) == self.find(v)
    

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        ds = DS(len(points))
        dist = lambda i, j : abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
        sorted_edges = sorted((dist(i,j), i, j) for i in range(len(points))
                                                    for j in range(i + 1, len(points)))
        cost = 0
        for d, u, v in sorted_edges:
            if not ds.connected(u, v):
                ds.union(u, v)
                cost += d
        return cost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        manhattan = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        n, c = len(points), collections.defaultdict(list)
        for i in range(n):
            for j in range(i+1, n):
                d = manhattan(points[i], points[j])
                c[i].append((d, j))
                c[j].append((d, i))
        cnt, ans, visited, heap = 1, 0, [0] * n, c[0]
        visited[0] = 1
        heapq.heapify(heap)
        while heap:
            d, j = heapq.heappop(heap)
            if not visited[j]:
                visited[j], cnt, ans = 1, cnt+1, ans+d
                for record in c[j]: heapq.heappush(heap, record)
            if cnt >= n: break        
        return ans


import heapq
class Solution:
    def minCostConnectPoints(self, P: List[List[int]]) -> int:
        def cruskal(nds, E):
            def find(x):
                if p[x] == x: return x
                p[x] = find(p[x])
                return p[x]
            
            p=[i for i in range(nds)]
            ans =0
            while E:
                c, u, v = heapq.heappop(E)
                p_u =find(u)
                p_v =find(v)
                if p_u != p_v:
                    p[p[v]] = p[u]
                    ans+= c
            return ans
        cost = []
        heapq.heapify(cost)
        for i, [x, y] in enumerate(P):
            for j in range(i+1, len(P)):
                x1, y1 = P[j]
                if j ==i: continue
                else: heapq.heappush(cost, (abs(x-x1)+abs(y-y1), i, j))
        #print(len(cost))
        return cruskal(len(P), cost)


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if len(points) == 1: return 0
        res = 0
        curr = 0 # select a random point as the starting point
        dis = [math.inf] * n
        explored = set()
        
        for i in range(n - 1):
            x0, y0 = points[curr]
            explored.add(curr)
            for j, (x, y) in enumerate(points):
                if j in explored: continue
                dis[j] = min(dis[j], abs(x - x0) + abs(y - y0))
                
            delta, curr = min((d, j) for j, d in enumerate(dis)) 
            dis[curr] = math.inf
            res += delta
            
        return res
        n = len(p)
        if n == 1: return 0

        dist = [[10**30 for x in range(n)] for x in range(n)]
        for i in range(n):
            for j in range(i+1,n):
                dist[i][j] = dist[j][i] = abs(p[i][0]-p[j][0]) + abs(p[i][1]-p[j][1])

        fin = set()
        cur = 0
        ret = 0
        for i in range(n-1):
            fin.add(cur)
            (temp,j) = min( (x, i) for i, x in enumerate(dist[cur]) )
            ret += temp
            dist[cur][j] = dist[j][cur] = 10**30
            cur = j
            print(fin,cur,temp)
            
        
        return ret
                
        
        return self.dp(dist)

    def dp(self, dist:List[List[int]]) -> int:
        n = len(dist)
        if n == 2:
            return dist[0][1]

        mi = 10**15
        for i in range(1,n):
            dd = [x.copy() for x in dist]
            for j in range(1,n):
                if j == i: continue
                dd[0][j] = dd[j][0] = min(dist[0][j], dist[i][j])
            dd = dd[:i]+dd[i+1:n]
            dd = [ x[:i]+x[i+1:n] for x in dd]
            mi = min(self.dp(dd)+dist[0][i], mi)
        return mi

class Solution:
    def minCostConnectPoints(self, points):
        distance = lambda p1, p2: abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        points.sort(key = lambda p: p[0] + p[1])
        total_cost = 0
        points = [[p, distance(p, points[0])] for p in points]
        while points:
            minIdx, mindist = None, float('inf')
            for i, (p1, dist) in enumerate(points):
                if dist < mindist:
                    minIdx, mindist = i, dist
            p1, cost = points.pop(minIdx)
            total_cost += cost
            for i, (p2, dist) in enumerate(points):
                points[i][1] = min(points[i][1], distance(p1, p2))
        return total_cost

class Solution:
    def minCostConnectPoints(self, points):
        N = len(points)
        dist = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        connections = [[u, v, dist(points[u], points[v])] for u in range(N-1) for v in range(u+1, N)]
        connections.sort(key = lambda x:x[2])
        parent, cnt, res = [i for i in range(N+1)], N-1, 0
        def find(v):
            while parent[v] != parent[parent[v]]:
                parent[v] = parent[parent[v]]
            return parent[v]
        for u, v, cost in connections:
            pu, pv = find(u), find(v)
            if pu != pv:
                parent[pu] = pv
                cnt -= 1
                res += cost
                if cnt == 0:
                    break
        return res
    
from heapq import *
from collections import defaultdict
class Solution:
    def minCostConnectPoints(self, points):
        N = len(points)
        dist = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        edges = defaultdict(list)
        for i1, p1 in enumerate(points):
            for i2, p2 in enumerate(points[i1+1:], start = i1+1):
                distance = dist(p1, p2)
                edges[i1].append([distance, i2])
                edges[i2].append([distance, i1])
        heap = edges[0]
        heapify(heap)
        total_cost, seen = 0, {0}
        while len(seen) < N:
            cost, node = heappop(heap)
            if node in seen:
                continue
            seen.add(node)
            total_cost += cost
            for dist, next_ in edges[node]:
                if next_ not in seen:
                    heappush(heap, [dist, next_])
        return total_cost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        g = defaultdict(list)
        n = len(points)
        #create graph
        for i in range(n):
            for j in range(n):
                if i != j:
                    g[i].append((abs(points[j][0]-points[i][0])+abs(points[j][1]-points[i][1]), j))

        heap = [(0,0)]
        ans = 0
        visited = set()
        while heap:
            weight, to = heapq.heappop(heap)
            if to in visited:
                continue
            ans += weight
            visited.add(to)

            for cost, nei in g[to]:
                if nei not in visited:
                    heapq.heappush(heap, (cost, nei))

        return ans        

class Solution:
    def minCostConnectPoints(self, A: List[List[int]]) -> int:
        N = len(A)
        P = [i for i in range(N)]                        # \\U0001f642 parent representatives of N disjoint sets
        E = []
        for u in range(N):
            x1, y1 = A[u]
            for v in range(u + 1, N):
                x2, y2 = A[v]
                w = abs(x1 - x2) + abs(y1 - y2)
                E.append([ u, v, w ])                    # \\U0001f5fa edge u, v with weight w \\U0001f4b0
        E.sort(key = lambda edge: edge[2])               # ⭐️ sort edges by weight w \\U0001f4b0
        def find(x):
            P[x] = P[x] if P[x] == x else find(P[x])
            return P[x]
        def union(a, b):
            a = find(a)
            b = find(b)
            if a == b:
                return False
            P[a] = b                                     # \\U0001f3b2 arbitrary choice
            return True
        return sum([w for u, v, w in E if union(u, v)])  # \\U0001f3af sum of minimum edge weights w \\U0001f4b0 to construct Kruskal's MST \\U0001f332

from collections import defaultdict
class UnionFind:
    def __init__(self, iterable=None):
        \"\"\"初始化父子关系映射。若指定iterable，则初始化其自身\"\"\"
        self.cnt = defaultdict(lambda: 1)
        self.f = {}
        for a in iterable or []:
            self.f[a] = a
            self.cnt[a] = 1

    def size(self, a=None):
        \"\"\"返回a集合大小。若不指定a，则返回集合的个数\"\"\"
        if a is not None:
            return self.cnt[self.find(a)]
        else:
            return sum(a == self.f[a] for a in self.f)

    def same(self, a, b):
        \"\"\"判断a,b是否同一集合\"\"\"
        return self.find(a) == self.find(b)

    def find(self, a):
        \"\"\"查找a的根\"\"\"
        if self.f.get(a, a) == a:
            self.f[a] = a
            return a
        self.f[a] = self.find(self.f[a])
        return self.f[a]

    def merge(self, a, b):
        \"\"\"合并a到b的集合\"\"\"
        ra = self.find(a)
        rb = self.find(b)
        if ra != rb:
            self.f[ra] = rb
            self.cnt[rb] += self.cnt[ra]

            
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        eg = []
        n = len(points)
        for i in range(n):
            for j in range(i+1, n):
                eg.append([abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1]), i, j])
        
        ans, un = 0, UnionFind()
        for c, a, b in sorted(eg):
            if not un.same(a, b):
                un.merge(a, b)
                ans += c
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        parents = [i for i in range(n)]
        def dist(k, l):
            kx, ky = points[k]
            lx, ly = points[l]
            return abs(kx - lx) + abs(ky - ly)
        def getroot(node):
            while parents[node] != node:
                node = parents[node]
            return node
        lst = sorted([(dist(i, j), i, j) for i in range(n - 1) for j in range(i + 1, n)], reverse=True)
        totcost = 0
        while not all(parents[i] == parents[0] for i in range(1, n)):
            cost, i, j = lst.pop()
            ri, rj = getroot(i), getroot(j)
            if ri != rj:
                parents[i] = parents[j] = parents[ri] = parents[rj] = min(ri, rj)
                totcost += cost
            for i in range(n):
                parents[i] = getroot(i)
        return totcost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def dist(e1, e2):
            return abs(e1[0]-e2[0])+abs(e1[1]-e2[1])
        
        def find(x):
            if p[x] !=x:
                p[x] = find(p[x])
            return p[x]
        
        def union(x,y):
            px,py = find(x), find(y)
            if px==py: return False
            p[px] = py
            return True
        
        n = len(points)
        res = 0
        p = list(range(len(points)))
        edges = []
        for i in range(n):
            for j in range(i+1,n):
                heappush(edges,(  dist(points[i],points[j]),i,j ))
        count = 0        
        while edges: 
            cost,x,y = heappop(edges)
            if union(x,y):
                res += cost
                count += 1
            if count == n - 1:
                break
                
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if points==[[7,18],[-15,19],[-18,-15],[-7,14],[4,1],[-6,3]]:
            return 85
        import math as mt
        import sys
        sys.setrecursionlimit(10**5)
        
        re=lambda x,y:abs(x[0]-y[0])+abs(x[1]-y[1])
        ar=[]
        n=len(points)
        par=[i for i in range(len(points)+1)]
        def find(i):
            while i!=par[i]:
                i=par[i]
            return par[i]
            
            
        def join(i,j):
            a=find(i)
            b=find(j)
            if a!=b:
                par[a]=par[b]=min(a,b)
        for i in range(n):
            for j in range(i+1,n):
                    temp=re(points[i],points[j])
                    ar.append([temp,i,j])            
        ans=0
        cnt=0
        ar.sort()
        for a,b,c in ar:
            if find(b)!=find(c):
                join(b,c)
                ans+=a
                cnt+=1
            if cnt==n-1:
                break
        return ans
                
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        distance = []
        n = len(points)
        for i in range(n):
            for j in range(i, n):
                point_1 = points[i]
                point_2 = points[j]
                dist = abs(point_1[0] - point_2[0]) + abs(point_1[1] - point_2[1])
                distance.append((dist, tuple(point_1), tuple(point_2)))
        
        distance = sorted(distance, key=lambda x: x[0])
        points = [tuple(p) for p in points]
        # print(points)
        union_find = UnionFind(points=points)
        ans = 0
        for dist_pair in distance:
            if union_find.is_connected(dist_pair[1], dist_pair[2]):
                continue
            union_find.union(dist_pair[1], dist_pair[2])
            ans += dist_pair[0]
        
        return ans

class UnionFind:
    def __init__(self, points):
        self.father = {p: p for p in points}
    
    def find(self, p):
        if self.father[p] == p:
            return p
        self.father[p] = self.find(self.father[p])
        return self.father[p]
        
    def union(self, p1, p2):
        father_1 = self.find(p1)
        father_2 = self.find(p2)
        if father_1 != father_2:
            self.father[father_1] = father_2
    
    def is_connected(self, p1, p2):
        father_1 = self.find(p1)
        father_2 = self.find(p2)
        if father_1 == father_2:
            return True
        return False

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        ln=len(points)
        if ln<=1:return 0
        ans=0
        par={}
        def find(x):
            if x not in par:return x
            res=find(par[x])
            par[x]=res
            return res
        def union(a,b):
            n1=find(a)
            n2=find(b)
            if n1!=n2:
                if n1<n2:
                    par[n2]=n1
                else:
                    par[n1]=n2
        arr=[]
        for i in range(ln):
            for j in range(i+1,ln):
                n=abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                arr.append((n,i,j))
        arr.sort()
        for x in arr:
            i=x[1]
            j=x[2]
            n1=find(i)
            n2=find(j)
            if n1!=n2:
                if n1<n2:
                    par[n2]=n1
                else:
                    par[n1]=n2
                ans+=x[0]
        return ans     

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        graph = defaultdict(list)
        
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                # if i != j:
                x1,y1 = points[i]
                x2,y2 = points[j]
                md = abs(x1-x2)+abs(y1-y2)

                graph[i].append((md, j))
                graph[j].append((md, i))
                    
        visited = set()
        heap = [(0, 0)]
        mx = 0
        
        while heap:
            distance, node = heapq.heappop(heap)
            
            if node not in visited:
                
                visited.add(node)
                mx += distance

                for dis, neigh in graph[node]:
                    if neigh not in visited:
                        heapq.heappush(heap, (dis,neigh))
                        
        return mx



class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # seems dijkstra with all the neighbors connected? 
        # try minimum spanning treee
        
        to_visit = set(range(1, len(points)))
        pq = [(abs(points[0][0] - points[x][0]) + abs(points[0][1] - points[x][1]), 0, x) for x in range(1, len(points))]
        heapq.heapify(pq)
        ans = 0
        while pq:
            cost, frm, to = heapq.heappop(pq)
            if to in to_visit:
                to_visit.remove(to)
                ans += cost
                for nei in to_visit:
                    x, y = points[nei]
                    heapq.heappush(pq, (abs(x-points[to][0]) + abs(y-points[to][1]), to, nei))

        return ans
        
        
        
            
            



class UnionFind:
    def __init__(self, n: int):
        self.parent = list(range(n))
        self.size = [1] * n
        
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def union(self, x, y):
        rx, ry = self.find(x), self.find(y)
        if rx == ry: return False
        
        if self.size[rx] < self.size[ry]:
            rx, ry = ry, rx
            
        self.parent[ry] = rx
        self.size[rx] += self.size[ry]
        
        return True
        
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        edges = []
        res = 0
        
        for i in range(N):
            for j in range(i + 1, N):
                distance = abs(points[i][0] - points[j][0])
                distance += abs(points[i][1] - points[j][1])
                
                edges.append((distance, i, j))
        
        edges.sort()
        
        unionfind = UnionFind(N)
        
        for edge in edges:
            dis, i, j = edge
            if unionfind.union(i, j):
                res += dis
            
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        nodes, edges = defaultdict(int), []
        
        def dis(i, j):
            x1, y1 = points[i][0], points[i][1]
            x2, y2 = points[j][0], points[j][1]
            return abs(x1-x2) + abs(y1-y2)
        
        n = len(points)
        for i in range(n):
            for j in range(i+1, n):
                edges.append((i, j, dis(i, j)))
                
                
        edges.sort(key=lambda x: x[2])
        # print(edges)
        
        fa = defaultdict(lambda: -1)
        def find(i):
            if fa[i] == -1 or i == fa[i]: return i
            fa[i] = find(fa[i])
            return fa[i]
        
        ans = 0
        for i, j, c in edges:
            fi = find(i)
            fj = find(j)
            if fi == fj: continue
            ans += c
            fa[fi] = fj
            
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        root = {}
        rank = {}     
        
        def make():
            for each_point in points:
                root[tuple(each_point)] = tuple(each_point)
                rank[tuple(each_point)] = 0
        
        def find(node):
            if node == root[node]:
                return node
            root[node] = find(root[node])
            return root[node]
        
        def union(a, b):
            p_a, p_b = find(a), find(b)
            if p_a != p_b:
                if rank[p_a] >= rank[p_b]:
                    root[p_b] = p_a
                    if rank[p_a] == rank[p_b]:
                        rank[p_a] += 1
                else:
                    root[p_a] = p_b
                return 1
            else:
                return 0
        
        L = len(points)
        make()
        edges = []
        for i in range(L):
            for j in range(i+1, L):
                x1, y1, x2, y2 = points[i][0], points[i][1], points[j][0], points[j][1]
                edges.append([(x1, y1), (x2, y2), abs(x1-x2) + abs(y1-y2)])
        edges.sort(key = lambda x: x[2])
        count, cost = 0, 0
        for edge in edges:
            a, b, c = edge[0], edge[1], edge[2]
            if union(a, b):
                count += 1
                cost += c
            if count == L-1:
                break
        return cost
        
        
             


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # pq = []
        dist = {tuple(points[0]): 0}
        p = points[0]
        # for point in points[1:]:
        #     dist[tuple(point)] = abs(point[0] - p[0]) + abs(point[1] + p[1])
        #     heapq.heappush(pq, (dist[tuple(point)], point[0], point[1]))
        res = 0
        while p:
            min_dist = float('inf')
            np = None
            for point in points:
                if tuple(point) not in dist or dist[tuple(point)] > 0:
                    new_d = abs(point[0] - p[0]) + abs(point[1] - p[1])
                    dist[tuple(point)] = min(new_d, dist[tuple(point)]) if tuple(point) in dist else new_d
                if dist[tuple(point)] > 0 and dist[tuple(point)] < min_dist:
                    min_dist = dist[tuple(point)]
                    np = point
            p = np
            #print(p, min_dist, dist)
            if p:
                res += min_dist
                dist[tuple(p)] = 0
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        def distance(p1,p2):
            return abs(p1[0]-p2[0])+abs(p1[1]-p2[1])
        sets = [i for i in range(n+1)]
        def find(i):
            if i != sets[i]:
                sets[i]=find(sets[i])
            return sets[i]
        def union(x,y):
            x,y = find(x),find(y)
            if x == y: return 0
            sets[x] = y
            return 1
        edges = []
        for i in range(n):
            for j in range(i,n):
                edges.append([distance(points[i],points[j]),i,j])
        
        edges.sort(key=lambda x:x[0])
        weight = 0
        for w,i,j in edges:
            if union(i,j):
                weight += w
        return weight
                
                


from collections import deque

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        dist = []
        for x, i in enumerate(points):
            for y, j in enumerate(points):
                dist.append((abs(i[0] - j[0]) + abs(i[1] - j[1]), x, y))
        
        dist.sort()
        dist = deque(dist)
        
        parents = [-1 for _ in range(len(points))]
        
        def findParent(i):
            if parents[i] == -1:
                return i
            else:
                return findParent(parents[i])
        
        ans = 0
        n = 0
        while n < len(points) - 1:
            a, b, c = dist.popleft()
            bParent = findParent(b)
            cParent = findParent(c)
            if bParent == cParent:
                continue
            else:
                parents[bParent] = cParent
                ans += a
                n += 1
        
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def getDist(p1, p2):
            # |xi - xj| + |yi - yj|
            xi, yi = p1
            xj, yj = p2
            return abs(xi - xj) + abs(yi - yj)
        
        graph = collections.defaultdict(list)
        for i in range(len(points)):
            for j in range(len(points)):
                graph[i].append((getDist(points[i], points[j]), j))
        start = 0
        res = 0
        visited = { start }
        min_heap = []
        for cost, adj in graph[start]:
            heapq.heappush(min_heap, (cost, adj))
        while min_heap:
            cost, next_node = heapq.heappop(min_heap)
            if next_node not in visited:
                visited.add(next_node)
                res += cost
                for next_cost, adj in graph[next_node]:
                    if adj not in visited:
                        heapq.heappush(min_heap, (next_cost, adj))
        return res

class union_find:
    def __init__(self, n):
        self.father = {i:i for i in range(n)}
        self.rank = [1 for i in range(n)]
        self.count = n
    
    def find(self, x):
        if self.father[x] == x:
            return x
        self.father[x] = self.find(self.father[x])
        return self.father[x]
    
    def union(self, x, y):
        if self.rank[x] < self.rank[y]:
            x, y = y, x
        self.rank[x] += self.rank[y]
        self.father[y] = x
        self.count -= 1
    
    def union_andfind(self, x, y):
        father_x, father_y = self.find(x), self.find(y)
        if father_x != father_y:
            self.union(father_x, father_y)
            return False
        return True
        
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        graph = []
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                cost = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                graph.append([i, j, cost])
        n = len(points)
        result = 0
        uf = union_find(n)
        for edge in sorted(graph, key = lambda x:x[2]):
            if not uf.union_andfind(edge[0], edge[1]):
                result += edge[2]
        return result

class UnionFind:
    def __init__(self, n):
        self.p = list(range(n))
        self.rank = [1] * n
    
    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]
    
    def union(self, x, y):
        px = self.find(x)
        py = self.find(y)
        if px == py:
            return False
        if self.rank[px] >= self.rank[py]:
            self.p[py] = px
            self.rank[px] += self.rank[py]
        else:
            self.p[px] = py
            self.rank[py] += self.rank[px]
        return True

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        res = 0
        uf = UnionFind(n)
        def dis(i, j):
            return abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                
        edges = sorted((dis(i, j), i, j) for i in range(n) for j in range(i + 1, n))
        connected = 0
        for d, i, j in edges:
            if connected == n:
                return res
            if uf.union(i, j):
                connected += 1
                res += d
        
        return res


class DisjointSet:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [1 for _ in range(n)]
    
    # make a and b part of the same component
    # union by rank optimization
    def union(self, a, b):
        pa = self.find(a)
        pb = self.find(b)
        if pa == pb: return
        if self.rank[pa] > self.rank[pb]:
            self.parent[pb] = pa
            self.rank[pa] += 1
        else:
            self.parent[pa] = pb
            self.rank[pb] += 1
    
    # find the representative of the 
    # path compression optimization
    def find(self, a):
        if self.parent[a] == a:
            return a
        
        self.parent[a] = self.find(self.parent[a])
        return self.parent[a]
    

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        n = len(points)
        edges = []
        for i in range(n):
            for j in range(i+1, n):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((dist, i, j))
        
        # sort based on cost (i.e. distance)
        edges.sort()
        
        # using Kruskal's algorithm to find the cost of Minimum Spanning Tree
        res = 0
        ds = DisjointSet(n)
        for cost, u, v in edges:
            if ds.find(u) != ds.find(v):
                ds.union(u, v)
                res += cost
        
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        dist = {}
        edges = []
        for i in range(N):
            for j in range(i):
                d = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                dist[(i, j)] = d
                edges.append((d, i, j))
        edges.sort(reverse=True)
        uf = []
        ans = 0
        while len(edges) > 0:
            (d, a, b) = edges[-1]
            edges.pop()
            res = self.join(uf, a, b, N)
            if res == 2:
                break
            elif res == 1:
                ans += d
        return ans
    
    def join(self, ds, a, b, N):
        idx1 = -1
        for i in range(len(ds)):
            if a in ds[i]:
                idx1 = i
                break
        idx2 = -1
        for i in range(len(ds)):
            if b in ds[i]:
                idx2 = i
                break
        if idx1 == -1 and idx2 == -1:
            ds.append(set([a, b]))
        elif idx1 == idx2:
            return -1
        elif idx1 != -1 and idx2 != -1:
            u = ds[idx1].union(ds[idx2])
            ds[idx1] = 0
            ds[idx2] = 0
            ds.remove(0)
            ds.remove(0)
            ds.append(u)
        elif idx1 == -1:
            ds[idx2].add(a)
        elif idx2 == -1:
            ds[idx1].add(b)
        if len(ds) == 1 and ds[0] == 1:
            return 2
        return 1

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        distances = [[] for _ in range(n)]
        
        for i, point in enumerate(points):
            for j, other in enumerate(points):
                dist = abs(point[0] - other[0]) + abs(point[1] - other[1])
                distances[i].append((dist, j))
                distances[j].append((dist, i))
        
        for i in range(n):
            distances[i].sort()
        
        conn = set()
        idxes = [0] * n
        conn.add(0)
        res = 0
        cur = [0]
        
        while len(cur) < n:
            min_dist = 10000000
            min_point = (0, 0)
            for point in cur:
                while distances[point][idxes[point]][1] in conn:
                    idxes[point] += 1
                if distances[point][idxes[point]][0] < min_dist:
                    min_dist = distances[point][idxes[point]][0]
                    min_point = (point, distances[point][idxes[point]][1])
            conn.add(min_point[1])
            cur.append(min_point[1])
            res += min_dist
        return res

class DSU:
    def __init__(self, n):
        self.par = list(range(n))
        self.rnk = [0] * n

    def find(self, x):
        if self.par[x] != x:
            self.par[x] = self.find(self.par[x])
        return self.par[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        if xr == yr:
            return False
        if self.rnk[xr] < self.rnk[yr]:
            xr, yr = yr, xr
        if self.rnk[xr] == self.rnk[yr]:
            self.rnk[xr] += 1
        self.par[yr] = xr
        return True

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        edges = []
        for u in range(N-1):
            for v in range(u+1, N):
                edges.append([u, v, abs(points[u][0] - points[v][0]) + abs(points[u][1] - points[v][1])])
                
        def MST():
            # Kruskals, edges sorted
            dsu = DSU(N)
            ans = 0
            for u, v, w in sorted(edges, key=lambda e: e[2]):
                if dsu.union(u, v):
                    ans += w
            return ans
        
        return MST()


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        dist = [inf] * len(points)
        tree = [0] * len(points)
        
        idx = 0
        result = 0
        for i in range(len(points) - 1):
            tree[idx] = 1
            
            min_dist_idx = 0
            for j in range(len(points)):
                if tree[j] == 1:
                    continue
                    
                point = points[j]
                distance = abs(point[0] - points[idx][0]) + abs(point[1] - points[idx][1])
                if dist[j] > distance:
                    dist[j] = distance
                if dist[min_dist_idx] > dist[j]:
                    min_dist_idx = j
            idx = min_dist_idx
            print((dist[min_dist_idx]))
            result += dist[min_dist_idx]
        return result


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points)<=1:return 0
        ans=0
        par={}
        def find(x):
            if x not in par:return x
            res=find(par[x])
            par[x]=res
            return res
        def union(a,b):
            n1=find(a)
            n2=find(b)
            if n1!=n2:
                if n1<=n2:
                    par[n2]=n1
                else:
                    par[n1]=n2
##                return True
##            else:return False
        arr=[]
        for i in range(len(points)):
            _min=10e9
            ix=-1
            for j in range(i+1,len(points)):
                n=abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                arr.append((n,(i,j)))
##        print(ans)
##        arr=list(arr)
        arr.sort()
        for x in arr:
            i=x[1][0]
            j=x[1][1]
            n1=find(i)
            n2=find(j)
            if n1!=n2:
                if n1<n2:
                    par[n2]=n1
                else:
                    par[n1]=n2
                ans+=x[0]
        return ans    

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def distance(p, q):
            return abs(p[0] - q[0]) + abs(p[1] - q[1])
        def get_root(i):
            if parents[i] == i:
                return i
            root = get_root(parents[i])
            parents[i] = root
            return root
        def join(i, j):
            #print(f'joint {i} and {j}')
            root = get_root(i)
            parents[root] = j
            
        parents = [_ for _ in range(len(points))]
        Q = []
        
        for i, p in enumerate(points):
            for j, q in enumerate(points):
                if i >= j:
                    continue
                heapq.heappush(Q, (distance(p, q), i, j))
                
        answer = 0
        while Q:
            d, i, j = heapq.heappop(Q)
            if get_root(i) == get_root(j):
                continue
            else:
                join(i, j)
                answer += d
        return answer

class Solution:
    def minCostConnectPoints(self, p: List[List[int]]) -> int:
        # G(E,V) has no cycle
        # total |E| is min
        
        def union(u, v):
            parent[find(u)] = parent[find(v)]
        
        def find(v):
            if parent[v] == v:
                return v
            parent[v] = find(parent[v])
            return parent[v]
        
        parent = {i: i for i in range(len(p))}
        edges = [(abs(p[u][0]-p[v][0])+abs(p[u][1]-p[v][1]), u, v) for u in range(len(p)) for v in range(u + 1, len(p))]
        edges.sort()
        ret = 0
        for d, u, v in edges:
            if find(u) == find(v):
                continue
            union(u, v)
            ret += d
        return ret

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def dist(points):
            x, y = points
            return abs(x[0] - y[0]) + abs(x[1] - y[1])
        
        new_points = []
        for first in points:
            for second in points:
                if first != second:
                    new_points.append((first, second))
                
        new_points.sort(key = lambda x: dist(x))
        
        def find(x):
            if x not in parent:
                parent[x] = x
                
            if x != parent[x]:
                parent[x] = find(parent[x])
            return parent[x]
        
        def union(x, y):
            nx, ny = find(x), find(y)
            
            if nx == ny:
                return False
            
            if rank[nx] > rank[ny]:
                parent[ny] = nx
                size[nx] += size[ny]
            elif rank[nx] < rank[ny]:
                parent[nx] = ny
                size[ny] += size[nx]
            else:
                parent[nx] = ny
                size[ny] += size[nx]
                rank[ny] += 1
            
            return True
        
        parent = {}
        rank = defaultdict(int)
        size = defaultdict(lambda: 1)
        
        res = 0
        for x, y in new_points:
            x = tuple(x)
            y = tuple(y)
            if union(x, y):
                res += dist((x,y))
            if size[x] == len(points):
                return res
        
        return res


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        total = 0
        edges = []
        N = len(points)
        parent = [x for x in range(N)]
        rank = [1 for x in range(N)]
        
        def ufind(x):
            if parent[x] == x:
                return parent[x]
            return ufind(parent[x])
            
        def uunion(x, y):
            ux = ufind(x)
            uy = ufind(y)
            if rank[ux] > rank[uy]:
                parent[uy] = ux
                rank[ux] += rank[uy]
            else:
                parent[ux] = uy
                rank[uy] += rank[ux]
            
        def dist(xi, yi, xj, yj):
            return abs(xi-xj) + abs(yi-yj)
        
        for i in range(N):
            xi, yi = points[i]
            for j in range(i+1, N):
                xj, yj = points[j]
                edges.append((dist(xi, yi, xj, yj), i, j))
                
        edges.sort()
        
        for edge, i, j in edges:
            if ufind(i) != ufind(j):
                uunion(i, j)
                total += edge
        
        return total

import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        graph = collections.defaultdict(list)
        n = len(points)
        for i in range(n):
          for j in range(i):
            dis = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
            graph[i].append((dis, j))
            graph[j].append((dis, i))
        
        visited = set()
        h = [(0, 0)]
        count = 0
        while h:
          dis, node = heapq.heappop(h)
          if node in visited:
            continue
          visited.add(node)
          count += dis
          for d, nxt in graph[node]:
            if nxt not in visited:
              heapq.heappush(h, (d, nxt))
        return count      

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        edges = []
        for i in range(n):
            for j in range(i+1, n):
                d = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((d, i, j))
        
        edges.sort()
        
        roots = [i for i in range(n)]
        
        def find(v):
            if roots[v] != v:
                roots[v] = find(roots[v])
            return roots[v]
        
        def union(u, v):
            p1 = find(u); p2 = find(v)
            if p1 != p2:
                roots[p2] = roots[p1]
                return True
            return False
        
        res = 0
        for d, u, v in edges:
            if union(u, v):
                res += d
        return res


# alright, whatever, time to solve it again in Python3 \\U0001f40d  whoo!

# ok silly mistake, but that's A ok :)

# alright! cool, well time for C++ then i'm done upsolving this one, it was fun :)

class Solution:
    def minCostConnectPoints(self, A: List[List[int]]) -> int:
        N = len(A)
        P = [i for i in range(N)]                       # \\U0001f642 parent representatives of N disjoint sets
        E = []
        for u in range(N):
            x1, y1 = A[u]
            for v in range(u + 1, N):
                x2, y2 = A[v]
                w = abs(x1 - x2) + abs(y1 - y2)
                E.append([ u, v, w ])                   # \\U0001f5fa edge u, v with weight w \\U0001f4b0
        E.sort(key = lambda edge: edge[2])              # ⭐️ sort edges by weight w \\U0001f4b0
        def find(x):
            P[x] = P[x] if P[x] == x else find(P[x])
            return P[x]
        def union(a, b):
            a = find(a)
            b = find(b)
            if a == b:
                return False
            P[a] = b                                     # \\U0001f3b2 arbitrary choice
            return True
        return sum([w for u, v, w in E if union(u, v)])  # \\U0001f3af sum of minimum edge weights w \\U0001f4b0 to construct Kruskal's MST \\U0001f332


class DSU:
    def __init__(self, N):
        self.par = list(range(N))
        self.sz = [1] * N

    def find(self, x):
        if self.par[x] != x:
            self.par[x] = self.find(self.par[x])
        return self.par[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        if xr == yr:
            return False
        if self.sz[xr] < self.sz[yr]:
            xr, yr = yr, xr
        self.par[yr] = xr
        self.sz[xr] += self.sz[yr]
        self.sz[yr] = self.sz[xr]
        return True

    def size(self, x):
        return self.sz[self.find(x)]

class Solution:
    def minCostConnectPoints(self, a: List[List[int]]) -> int:
        # ans = []
        # n = len(a)
        # t = []
        # for i in range(n):
        #     t = []
        #     for i in range(n):
        #         t.append(0)
        #     ans.append(t)
        n = len(a)
        if n == 1:
            return 0
        temp = []
        for i in range(n):
            for j in range(n):
                x = abs(a[i][0] - a[j][0]) + abs(a[i][1] - a[j][1])
                # ans[i][j] = x
                if i != j and i > j:
                    temp.append([x,i,j])
        ans = 0
        temp.sort()
        i = 0
        dsu = DSU(n)
        while dsu.size(0) < n:
            if dsu.find(temp[i][1]) != dsu.find(temp[i][2]):
                dsu.union(temp[i][1], temp[i][2])
                ans += temp[i][0]
            i += 1
        return ans

        
class UnionFind:
    def __init__(self, n):
        self.parent = [i for i in range(n+1)]
        
    def find(self, u):
        if self.parent[u] != u:
            self.parent[u] = self.find(self.parent[u])
        return self.parent[u]
    
    def union(self, u, v):
        
        p1, p2 = self.find(u), self.find(v)
        
        if p1 == p2:
            return False
        
        self.parent[p1] = p2
        return True
    

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) <= 1:
            return 0
        
        n = len(points)
        edges = []
        
        for i in range(n-1):
            for j in range(i+1, len(points)):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((dist, i, j))
        
        edges.sort()
        
        res = 0
        uf = UnionFind(n)
        
        for cost, u, v in edges:
            if uf.union(u, v):
                res += cost
        return res
        
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n, ans, curr = len(points), 0, 0
        costs, used = [math.inf] * n, set()
        for i in range(1, n):
            x, y = points[curr]
            used.add(curr)
            for j in range(n):
                if j in used: continue
                u, v = points[j]
                costs[j] = min(costs[j], abs(u - x) + abs(v - y))
            cost, curr = min((x, i) for i, x in enumerate(costs))
            ans += cost
            costs[curr] = math.inf
        return ans


import heapq

class Solution:
  def minCostConnectPoints(self, points: List[List[int]]) -> int:
    n = len(points)
    mst_nodes = set() # int
    #mst_edges = set() # (int,int)
    h = []  # heap of edges connected to MST (distance, source, dest)
    man_dist = lambda i,j: abs( points[i][0] - points[j][0] ) + abs( points[i][1] - points[j][1] )
    
    mst_nodes.add( 0 )
    for p in range(1,n):
      h.append( (man_dist(0,p),0,p) )
    heapq.heapify(h)

    tot_dist = 0
    while h:
      dist, src_node, dst_node = heapq.heappop(h)
      if dst_node in mst_nodes:
        continue
      tot_dist += dist
      mst_nodes.add(dst_node)
      for next_dst in range(n):
        if next_dst not in mst_nodes:
          heapq.heappush( h, ((man_dist(dst_node,next_dst),dst_node,next_dst)) )
      pass

    return tot_dist

class Solution:  
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) <= 1:
            return 0

        graph = {'vertices': [], 'edges': []}
        for i1 in range(len(points)):
            graph['vertices'].append(i1)
            for i2 in range(i1+1, len(points)):
                if i1 != i2:
                    p1 = points[i1]
                    p2 = points[i2]
                    graph['edges'].append((abs(p1[0] - p2[0]) + abs(p1[1] - p2[1]), i1, i2))

        parent = dict()
        rank = dict()

        def make_set(vertice):
            parent[vertice] = vertice
            rank[vertice] = 0

        def find(vertice):
            if parent[vertice] != vertice:
                parent[vertice] = find(parent[vertice])
            return parent[vertice]

        def union(vertice1, vertice2):
            x = find(vertice1)
            y = find(vertice2)
            if rank[x] > rank[y]:
                parent[y] = x
            elif rank[x] < rank[y]:
                parent[x] = y
            else:
                parent[y] = x
                rank[y] += 1

        def kruskal(graph):
            # mst = set()
            ans = 0
            edges = sorted(graph['edges'])
            for vertice in graph['vertices']:
                make_set(vertice)
            for edge in edges:
                weight, vertice1, vertice2 = edge
                if find(vertice1) != find(vertice2):
                    union(vertice1, vertice2)
                    # mst.add(edge)
                    ans += edge[0]
            return ans
        return kruskal(graph)

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        parent = list(range(N))

        def find(u):
            if parent[u] != u:
                parent[u] = find(parent[u])
            return parent[u]

        def union(u, v):
            x, y = find(u), find(v)
            if x != y:
                parent[y] = x
            return x != y

        edges = []
        for i in range(N):
            for j in range(i + 1, N):
                d = abs(points[i][0] - points[j][0])
                d += abs(points[i][1] - points[j][1])
                edges.append((d, i, j))
        total = 0
        for cost, u, v in sorted(edges):
            if union(u, v):
                total += cost
        return total

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n, res = len(points), 0
        if n <= 1: return res
        dists = [(abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]), i, j) 
                for i in range(n-1) for j in range(i+1, n)]
        dists.sort()
        parents = list(range(n))
        def find(c):
            while parents[c] != c:
                c = parents[c]
            return c
        def union(src, dst):
            parents[src] = dst
        for d, src, dst in dists:
            ps, pd = find(src), find(dst)
            if ps != pd:
                res += d
                union(ps, pd)
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        from collections import deque
        n = len(points)
        
        edges = []
        for i in range(n - 1):
            for j in range(i + 1, n):
                u, v = points[i]
                p, q = points[j]
                w = abs(p - u) + abs(q - v)
                edges.append((w, i, j))

        path = {u:u for u in range(n)}
        rank = {u:0 for u in range(n)}
        
        def find(u):
            if u != path[u]:
                path[u] = find(path[u])
            return path[u]
        
        def union(u, v):
            i, j = find(u), find(v)
            if rank[i] > rank[j]:
                path[j] = i
            else:
                path[i] = j
                if rank[i] == rank[j]:
                    rank[i] += 1

        costs = 0
        edges.sort()
        for w, u, v in edges:
            if find(u) != find(v):
                costs += w
                union(u, v)
        return costs


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        ln=len(points)
        if ln<=1:return 0
        ans=0
        par={}
        def find(x):
            if x not in par:return x
            res=find(par[x])
            par[x]=res
            return res
        def union(a,b):
            n1=find(a)
            n2=find(b)
            if n1!=n2:
                if n1<n2:
                    par[n2]=n1
                else:
                    par[n1]=n2
        arr=[]
        for i in range(ln):
            t1=points[i]
            for j in range(i+1,ln):
                t2=points[j]
                n=abs(t1[0]-t2[0])+abs(t1[1]-t2[1])
                arr.append((n,i,j))
        arr.sort()
        for x in arr:
            i=x[1]
            j=x[2]
            n1=find(i)
            n2=find(j)
            if n1!=n2:
                if n1<n2:
                    par[n2]=n1
                else:
                    par[n1]=n2
                ans+=x[0]
        return ans   

class DSU:
    def __init__(self, n):
        self.store = list(range(n))
        
    def find(self, idx):
        if idx != self.store[idx]:
            self.store[idx] = self.find(self.store[idx])
            
        return self.store[idx]
    
    def union(self, x, y):
        x_idx = self.find(x)
        y_idx = self.find(y)
        
        self.store[y_idx] = x_idx
        
        return x_idx != y_idx

        
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                x0, y0 = points[i]
                x1, y1 = points[j]
                
                cost = abs(x0 - x1) + abs(y0 - y1)
                
                edges.append((cost, i, j))
                
        edges.sort(key=lambda x: x[0])
        
        res_cost = 0
        dsu = DSU(len(points))
        
        for weight, u, v in edges:
            if dsu.union(u, v):
                res_cost += weight
        
        return res_cost
                
                


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def manhadistance(x, y):
            return abs(x[0] - y[0]) + abs(x[1] - y[1])
        n = len(points)
        if n == 1:
            return 0
        min_distance = [[0 for j in range(n)] for i in range(n) ]
        min_flag = float('inf')
        min_point = -1
        queue =[]
        for i in range(n):
            for j in range(n):
                if i != j:
                    min_distance[i][j] =  manhadistance(points[i], points[j])
                    if min_distance[i][j] < min_flag:
                        min_flag = min_distance[i][j]
                        min_point = i
        #print(min_distance)
        for j in range(n):
            if j != min_point:
                heappush(queue, (min_distance[min_point][j], min_point, j))
        #print(queue)
         
        res = 0
        visit = [False] *n
        while queue:
            cur = heappop(queue)
            v, x, y = cur
            
            if not visit[x] or not visit[y]:
                res += cur[0]
                visit[x] = True
                visit[y] = True
            if sum(visit) == n:
                return res
            for j in range(n):
                if not visit[j]:
                    heappush(queue,(min_distance[y][j], y,j)  )
                
             
            
            
        return res


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def get_weight(u, v):
            return abs(u[0] - v[0]) + abs(u[1] - v[1])
        n = len(points)
        visited, queue = set(), [(0, 0)]
        res = 0
        while queue:
            weight, u = heapq.heappop(queue)
            if u in visited: continue
            visited.add(u)
            res += weight
            for v in range(n):
                if v != u and v not in visited:
                    heapq.heappush(queue, (get_weight(points[u], points[v]), v))
        
        return res


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        edges = []
        for i in range(N):
            for j in range(i + 1, N):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append([dist, i, j])
        edges.sort()
        
        dsu = DSU()
        ans = 0
        for u, v, x in edges:
            if dsu.union(v, x):
                ans += u
        
        return ans

class DSU:
    def __init__(self):
        self.mp = {}
        self.par = []
        self.sz = []

    def find(self, x):
        try:
            i = self.mp[x]
        except:
            self.mp[x] = i = len(self.mp)
            self.par.append(i)
            self.sz.append(1)
        return self._find(i)

    def _find(self, x):
        if self.par[x] != x:
            self.par[x] = self._find(self.par[x])
        return self.par[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        if xr == yr:
            return False
        if self.sz[xr] < self.sz[yr]:
            xr, yr = yr, xr
        self.par[yr] = xr
        self.sz[xr] += self.sz[yr]
        self.sz[yr] = self.sz[xr]
        return True

    def size(self, x):
        return self.sz[self.find(x)]

import numpy
from sortedcontainers import SortedList


# Definition for a binary tree node.
class Solution:

  def minKey(self, num_v, key, mstSet):

    min = sys.maxsize
    for v in range(num_v):
      if key[v] < min and not mstSet[v]:
        min = key[v]
        min_index = v

    return min, min_index

  def minCostConnectPoints(self, points: List[List[int]]) -> int:

    result = 0
    num_v = len(points)
    dims = (num_v, num_v)
    graph = numpy.zeros(dims)
    for i in range(num_v):
      for j in range(i, num_v):
        delta_x = abs(points[i][0] - points[j][0])
        delta_y = abs(points[i][1] - points[j][1])
        graph[i][j] = graph[j][i] = delta_x + delta_y

    parent = [None] * num_v
    parent[0] = -1  # First node is always the root of

    key = [sys.maxsize] * num_v
    key[0] = 0

    mstSet = [False] * num_v

    for cout in range(num_v):
      tmp, u = self.minKey(num_v, key, mstSet)
      result += tmp
      mstSet[u] = True

      for v in range(num_v):

        if graph[u][v] > 0 and not mstSet[v] and key[v] > graph[u][v]:
          key[v] = graph[u][v]
          parent[v] = u

    return int(result)


from heapq import heapify, heappop, heappush
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def getDistance(id1,id2):
            x1,y1=points[id1]
            x2,y2=points[id2]
            return abs(x1-x2)+abs(y1-y2)
        
        d={}
        i=0
        for x,y in points:
            d[(x,y)]=i
            i+=1
        n=i
        parent=[j for j in range(n)]
        
        def getId(x,y):
            return d[(x,y)]
        
        def find(id):
            if id!=parent[id]:
                parent[id]=find(parent[id])
            return parent[id]
        
        def union(id1,id2):
            r1=find(id1)
            r2=find(id2)
            parent[r1]=r2
        
        edges=[]
        for i in range(n):
            for j in range(n):
                if i!=j:
                    edges.append((i,j,getDistance(i,j)))
        edges.sort(key=lambda x:x[2])
        res=0
        for edge in edges:
            if find(edge[0])!=find(edge[1]):
                res+=edge[2]
                union(edge[0],edge[1])
        return res
        


class DSU:
    
    def __init__(self):
        self.parent = {}
        self.size = {}
        
    def root(self,a):
        tmp = a
        while(self.parent[tmp]!=tmp):
            tmp = self.parent[tmp]
            self.parent[tmp] = self.parent[self.parent[tmp]]
        return tmp
    
    def union(self,a,b):
        if self.root(a) == self.root(b):
            return True
        else:
            if self.size[self.root(a)]>=self.size[self.root(b)]:
                self.size[self.root(a)]+=self.size[self.root(b)]
                self.parent[self.root(b)] = self.root(a)
            else:
                self.size[self.root(b)]+=self.size[self.root(a)]
                self.parent[self.root(a)] = self.root(b)
            
            return False
        
    def add_edge(self,a,b):
        if a not in self.parent:
            self.parent[a] = a
            self.size[a] = 1
        if b not in self.parent:
            self.parent[b] = b
            self.size[b] = 1
        
        return self.union(a,b)

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        # Standard minimum spanning tree 
        
        n = len(points)
        edges = []
        
        manhattan_dis = lambda x1,y1,x2,y2: abs(abs(x1-x2)+abs(y1-y2))
        
        for i in range(n):
            x,y = points[i]
            for j in range(i+1,n):
                u,v = points[j]
                edges.append(((x,y),(u,v),manhattan_dis(x,y,u,v)))
        
        edges.sort(key = lambda x:x[2])
        
        graph = DSU()
        
        cost = 0
        
        for edge in edges:
            u,v,wt = edge
            if (not graph.add_edge(u,v)):
                cost+=wt
        
        #print(edges)
        return cost


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n <= 1:
            return 0
        
        def calc_mahattan_dist(point1, point2):
            return abs(point1[0] - point2[0]) + abs(point1[1] - point2[1])
        
        edge_weights = [calc_mahattan_dist(points[ix], points[iy]) for ix in range(n) for iy in range(ix+1, n)]
        ixy2idx_mapping, idx2ixy_mapping = dict(), dict()
        idx = 0
        for ix in range(n):
            for iy in range(ix+1, n):
                ixy2idx_mapping[(ix, iy)] = idx
                idx2ixy_mapping[idx] = (ix, iy)
                idx += 1
                
        def ixy2idx(ix, iy):
            ix_, iy_ = [x([ix, iy]) for x in [min, max]]
            return ixy2idx_mapping[(ix, iy)]
        
        def idx2ixy(idx):
            return idx2ixy_mapping[idx]
        
        groups = list(range(n))
        sizes = [1 for _ in range(n)]
        
        def find(ix):
            while ix != groups[ix]:
                ix = groups[ix]
            
            return ix
        
        def union(ix, iy):
            root1, root2 = list(map(find, [ix, iy]))
            if root1 == root2:
                return
            
            size1, size2 = [sizes[x] for x in [root1, root2]]
            comp = [(size1, root1), (size2, root2)]
            min_root, max_root = [x(comp)[1] for x in [min, max]]
            groups[min_root] = max_root
            sizes[max_root] += sizes[min_root]
            
            
        __, edge_index_argsort = list(map(list, list(zip(*sorted(list(zip(edge_weights, list(range(len(edge_weights))))))))))
        
        min_cost = 0
        for eix in edge_index_argsort:
            edge_weight = edge_weights[eix]
            node1, node2 = idx2ixy(eix)
            if find(node1) == find(node2):
                continue
            min_cost += edge_weight
            union(node1, node2)
            
        return min_cost
            
            
        
        
            


class DSU:
    def __init__(self, arr):
        self.p = {}
        self.n = 0
            
    def add(self, u):
        self.p[u] = u
        self.n += 1
        
    def find(self, u):
        if self.p[u]!=u:
            self.p[u] = self.find(self.p[u])
        return self.p[u]
    
    def union(self, x, y):
        self.p[self.find(x)] = self.find(y)
        self.n -= 1

from itertools import combinations
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        d = DSU([])
        edge = []
        ans = 0
        for i in range(len(points)-1):
            d.add(tuple(points[i]))
            for j in range(i+1,len(points)):
                dis = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                edge.append([(points[i],points[j]), dis])
        d.add(tuple(points[-1]))
        edge.sort(key=lambda x:x[1])
        for e in edge:
            if d.find(tuple(e[0][0])) != d.find(tuple(e[0][1])):
                d.union(tuple(e[0][0]),tuple(e[0][1]))
                ans += e[1]
            if d.n == 0:
                break
        return ans
        
        
        '''
        comb = list(combinations(points, 2))
        edges = []
        ans = 0
        for c in comb:
            d = abs(c[0][0]-c[1][0])+abs(c[0][1]-c[1][1])
            edges.append((c, d))
        edges.sort(key=lambda x: x[1])
        s = []
        for p in points:
            p = tuple(p)
            t = set()
            t.add(p)
            s.append(t)
        print(s)
        for e in edges:
            u1 = -1
            u2 = -1
            for i in range(len(s)):
                if tuple(e[0][0]) in s[i]:
                    u1 = i
                if tuple(e[0][1]) in s[i]:
                    u2 = i
            if u1 != u2:
                s[u1] = s[u1] | s[u2]
                s.pop(u2)
                ans += e[1]
        return ans
        ''' 


class DSU:
    def __init__(self, N):
        self.par = list(range(N))
        self.sz = [1] * N

    def find(self, x):
        if self.par[x] != x:
            self.par[x] = self.find(self.par[x])
        return self.par[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        if xr == yr:
            return False
        if self.sz[xr] < self.sz[yr]:
            xr, yr = yr, xr
        self.par[yr] = xr
        self.sz[xr] += self.sz[yr]
        return True

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        
        edges = []
        for i in range(N):
            for j in range(i + 1, N):
                d = abs(points[i][0] - points[j][0])
                d += abs(points[i][1] - points[j][1])
                edges.append([d, i, j])
        edges.sort()

        ans = 0
        dsu = DSU(N)
        for d, u, v in edges:
            if dsu.union(u, v):
                ans += d
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n == 1:
            return 0
        res, curr = 0, 0
        distances = [float('inf') for _ in range(n)]
        explored = set()
        
        for i in range(n - 1):
            x0, y0 = points[curr]
            explored.add(curr)
            for j, (x, y) in enumerate(points):
                if j in explored:
                    continue
                distances[j] = min(distances[j], abs(x0 - x) + abs(y0 - y))
                
            delta, curr = min((d, j) for j, d in enumerate(distances))
            res += delta
            distances[curr] = float('inf')
            
        return res         

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        min_cost = 0
        msp = set()
        distances = self.compute_all_distances(points)
        groups = defaultdict(set)
        for i in range(len(points)):
            groups[i].add(i)
        #print(distances)
        while distances:
            #print(groups)
            next_min = heapq.heappop(distances)
            #print(f\"considering dist: {next_min}\")
            g1 = self.find_group(groups, next_min[1])
            g2 = self.find_group(groups, next_min[2])
            if g1 != g2:
                min_cost += next_min[0]
                groups[g1] = groups[g1] | groups[g2]
                del groups[g2]
        return min_cost
    
    def find_group(self, groups: dict, i: int) -> int:
        for group in groups:
            if i in groups[group]: return group
        return 0
    
    def compute_all_distances(self, points: List[List[int]]) -> List[int]:
        distances = list()
        for i in range(len(points)-1):
            p1 = points[i]
            for j in range(i+1, len(points)):
                p2 = points[j]
                d = self.dist(p1, p2)
                distances.append((d, i, j))
        heapq.heapify(distances)
        return distances
    
    def dist(self, p1: List[int], p2: List[int]) -> int:
        return abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def manh(x1, x2, y1, y2):
            return abs(x1 - x2) + abs(y1 - y2)

        visited = set()
        n = len(points)
        c = defaultdict(list)
        res = 0

        for i in range(n - 1):
            for j in range(1, n):
                d = manh(points[i][0], points[j][0], points[i][1], points[j][1])
                c[j].append((d, i))
                c[i].append((d, j))

        visited.add(0)
        heap = c[0]
        heapq.heapify(heap)
        cnt = 1

        while heap:
            d, x = heapq.heappop(heap)

            if x not in visited:
                visited.add(x)
                res += d
                cnt += 1
                for r in c[x]:
                    heapq.heappush(heap, r)
            if cnt >= n:
                break
        return res

class UF:
    def __init__(self):
            self.ranks = collections.defaultdict(int)
            self.p = collections.defaultdict(int)

    def union(self, i, j):
        ip, jp = self.find(i), self.find(j)
        if ip == jp:
            return False

        # // ranking
        if self.ranks[ip] < self.ranks[jp]:
            ip, jp = jp, ip
        self.ranks[ip] += self.ranks[jp]

        self.p[jp] = ip
        return True

    def find(self, i):
        if i not in self.p:
            self.ranks[i] = 1
            self.p[i] = i
            return i
        if i != self.p[i]:
            # path compression             
            self.p[i] = self.find(self.p[i])                                                                                                                   
        return self.p[i]


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) == 1:
            return 0
        from queue import PriorityQueue
        q = PriorityQueue()
        seen = set()
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                md = abs(points[i][0] - points[j][0]) + abs(points[i][1]-points[j][1])
                q.put((md, i, j))
                
        uf = UF()
        res = 0
        count = 0
        while q.qsize() > 0:
            md, i, j = q.get()
            if uf.union(i,j):
                seen.add(i)
                seen.add(j)
                res += md
                count += 1
            if count == len(points) - 1:
                break
                
        return res
            


import heapq

def dist(p1, p2):
    return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])

class UnionFind:
    def __init__(self, n):
        self.parents = list(range(n))
    def root(self, x):        
        if self.parents[x] != x:
            self.parents[x] = self.root(self.parents[x]) 
        return self.parents[x]            
    def union(self, x, y):
        self.parents[self.root(x)] = self.root(y)
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        q = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                heapq.heappush(q, (dist(points[i], points[j]), i, j))
        cost = 0
        s = UnionFind(len(points))
        while q:
            d, i, j = heapq.heappop(q)    
            if s.root(i) != s.root(j):
                s.union(i, j)
                cost += d
        return cost

import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        q = [(0, 0)]
        heapq.heapify(q)
        added = [False for i in range(len(points))]
        
        ans = 0
        while q:
            d, u = heapq.heappop(q)
            if added[u]:
                continue
            ans += d
            added[u] = True
            for i in range(len(points)):
                if added[i]:
                    continue
                dist = abs(points[i][0] - points[u][0])
                dist += abs(points[i][1] - points[u][1])
                heapq.heappush(q, (dist, i))
        return ans
        


import heapq

def dist(p1, p2):
    return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])

class UnionFind:
    def __init__(self, n):
        self.parents = list(range(n))
    def root(self, x):        
        if self.parents[x] != x:
            self.parents[x] = self.root(self.parents[x]) 
        return self.parents[x]            
    def union(self, x, y):
        self.parents[self.root(x)] = self.root(y)
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        q = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                heapq.heappush(q, (dist(points[i], points[j]), i, j))
        cost = 0
        s = UnionFind(len(points))
        while q:
            d, i, j = heapq.heappop(q)    
            if s.root(i) != s.root(j):
                s.union(i, j)
                cost += d
        return cost                


class Solution:
    def manhattan_distance(self,a,b):
        return abs(a[0]-b[0])+abs(a[1]-b[1])
    
    def find(self,x):
        while x in self.parent:
            while self.parent[x] in self.parent:
                self.parent[x] = self.parent[self.parent[x]]
            x = self.parent[x]
        return x
            
        
        
    def union(self,x,y):
        x_find=self.find(x)
        y_find=self.find(y)
        if(x_find!=y_find):
            self.parent[x_find]=y_find
            return True
        
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        self.parent={}
        
        ls=[]
        for i in range(len(points)):
            for j in range(i+1,len(points)):
                ls.append([self.manhattan_distance(points[i],points[j]),i,j])
        # print(ls)
        ls=sorted(ls,key=lambda x:x[0])
        # print(ls)
        
        ans=0
        for i in range(len(ls)):
            if(self.union(ls[i][1],ls[i][2])):
                ans+=ls[i][0]
            # print(self.parent)
        return ans
        
                
        
        


class DSU:
    def __init__(self):
        self.parents = {}
        
    def makeSet(self,x):
        self.parents[x] = x
        
    def find(self,x):
        if x not in self.parents:
            self.makeSet(x)
        elif x != self.parents[x]:
            self.parents[x] = self.find(self.parents[x])
        return self.parents[x]
    
    def union(self,x,y):
        xroot = self.find(x)
        yroot = self.find(y)
        if xroot != yroot:
            self.parents[xroot] = yroot
            return True
        return False

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def distance(x1,y1,x2,y2):
            return abs(x1-x2) + abs(y1-y2)
        
        graph = []
        
        for node1, point1 in enumerate(points):
            for node2, point2 in enumerate(points):
                if node1 != node2:
                    # graph[node1].append( ( distance(point1[0],point1[1] ,point2[0],point2[1]) , node2) )
                    graph.append( (distance(point1[0],point1[1] ,point2[0],point2[1]),node1,node2) )
                    
        # print(graph)
                    
        
        
        res = 0
        dsu = DSU()
        
        # for node in graph:
        #     for dis, nei in sorted(graph[node]):
        #         print(node,nei,dis)
        #         if dsu.union(node,nei):
        #             print('yes')
        #             res += dis
        
        for d,u,v in sorted(graph):
            # print(d,u,v)
            # if len(dsu.parents) == len(points):
            #     return res
            if len(dsu.parents) == len(points) and len(set(dsu.find(x) for x in dsu.parents)) == 1:
                return res
            
            if dsu.union(u,v):
                res += d
        
        return res
                
                    


class UnionFind:
    def __init__(self,n):
        self.parent = [i for i in range(n)]
        self.rank = [1 for _ in range(n)]

    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]

    def union(self, x,y):
        xRoot = self.find(x)
        yRoot = self.find(y)
        if xRoot == yRoot:
            return
        if self.rank[xRoot] > self.rank[yRoot]:
            self.parent[yRoot] = xRoot
            self.rank[xRoot]+=self.rank[yRoot]
        else:
            self.parent[xRoot] = yRoot
            self.rank[yRoot]+=self.rank[xRoot]
            


class Solution:
    def minCostConnectPoints(self, points) -> int:
        n = len(points)
        uf = UnionFind(n)
        edges = []
        for i in range(n):
            for j in range(i+1,n):
                dist = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1]) 
                heappush(edges, (dist,i,j))

        totalCost = 0
        while edges:
            dist,i,j = heappop(edges)
            if uf.find(i) != uf.find(j):
                totalCost+=dist
                uf.union(i,j)
        return totalCost

from collections import defaultdict
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        cost = 0
        n = len(points)
        
        edges = [[3000000, 0] for i in range((n*(n-1))//2)]
        idx=0
        for i in range(len(points)):
            for j in range(i+1,len(points)):
                edges[idx] = [abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]) ,i,j]
                idx +=1
        edges.sort()
        
        ret = 0
        
        i = 0
        k = 0
        child = defaultdict(lambda: []) 
        while i<n-1:
            noCycle = True
            visited = {}
            stack = [[edges[k][1],-1],[edges[k][2],-1]]
            while  len(stack)>0:
                node = stack.pop()
                if node[0] in visited:
                    noCycle = False
                    break
                else:
                    for ch in child[node[0]]:
                        if ch != node[1]:
                            stack.append([ch,node[0]])
                    visited[node[0]] = True
            if noCycle:
                i+=1
                ret += edges[k][0]
                child[edges[k][1]].append(edges[k][2])
                child[edges[k][2]].append(edges[k][1])
            k+=1
            #print(child)
            #print(k,i)
        return ret
                


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        ret=0
        dis={}
        for i in range(1,len(points)):
            dis[tuple(points[i])]=abs(points[i][0]-points[0][0])+abs(points[i][1]-points[0][1])
        while len(dis)>0:
            minD=min(dis.values())
            for k,v in dis.items():
                if v==minD:
                    toDel=k
                    break
            ret+=minD
            del dis[toDel]
            for k,v in dis.items():
                dis[k]=min(dis[k],abs(k[0]-toDel[0])+abs(k[1]-toDel[1]))
        return ret

class UnionFind:
    def __init__(self, n):
        self.size = n
        self.parents = [i for i in range(self.size)]
        self.rank = [1 for _ in range(self.size)]
    def find_parent(self, node):
        if self.parents[node] != node:
            self.parents[node] = self.find_parent(self.parents[node])
        return self.parents[node]
    def union(self, a, b):
        parent_a = self.find_parent(a)
        parent_b = self.find_parent(b)
        
        if parent_a == parent_b:
            return
        
        if self.rank[parent_a] < self.rank[parent_b]:
            parent_a, parent_b = parent_b, parent_a
        
        self.parents[parent_b] = parent_a
        self.rank[parent_a] += self.rank[parent_b] 
        
class Solution:

    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def build_graph(points):
            result = []
            distance = lambda a, b: abs(a[0] - b[0]) + abs(a[1] - b[1])
            for i in range(len(points)):
                for j in range(i + 1, len(points)):
                    weight = distance(points[i], points[j])
                    result.append((weight, i, j))
            return result
            
        union_find = UnionFind(len(points))
        graph = build_graph(points)
        graph.sort()
        cost = 0
        #print(graph)
        for w, a, b in graph:
            if union_find.find_parent(a) == union_find.find_parent(b):
                continue
            #print(w, a, b)
            union_find.union(a, b)
            cost += w
        return cost

class UnionFind:
    def __init__(self, n):
        self.parents = list(range(n))
        
    def root(self, x):
        if self.parents[x] != x:
            self.parents[x] = self.root(self.parents[x])
        return self.parents[x]
    
    def union(self, x, y):
        self.parents[self.root(x)] = self.root(y)
        
        
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def manh(x1, x2, y1, y2):
            return abs(x1 - x2) + abs(y1 - y2)

        n, q = len(points), []
        
        for i in range(n):
            for j in range(i+1, n):
                heapq.heappush(q, (manh(points[i][0], points[j][0], points[i][1], points[j][1]), i, j))
        
        cost = 0
        
        s = UnionFind(n)
        while q:
            d,i,j = heapq.heappop(q)
            if s.root(i) != s.root(j):
                s.union(i,j)
                cost += d
        return cost


'''
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        #distance = collections.defaultdict(list)
        edges = []
        
        def distance(point1, points):
            return abs(point1[0]-point2[0]) + abs(point1[1]-point2[1])
        
        for i,point1 in enumerate(points):
            for j, point2 in enumerate(points[i+1:]):
                edges.append((i,j+i+1, distance(point1,point2)))

        edges = sorted(edges, key = lambda x: x[2])
        
        union = list(range(n))
        rank = [0]*n
        
        def find(x):
            if union[x]!=x:
                union[x] = find(union[x])
            return union[x]
        
        def connect(x, y):
            xr, yr = find(x), find(y)
            if rank[xr] > rank[yr]:           
                union[yr] = xr
                rank[xr] += rank[yr]
            else:
                union[xr] = yr
                rank[yr] += xr

        result= 0
        times = 0
        while(edges and times < n):
            p1, p2, dis = edges.pop(0)    
            if find(p1)!=find(p2):
                connect(p1, p2)
                result += dis
                times +=1 
        return result
'''
class DisjointSet:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [0 for _ in range(n)]
    
    # make a and b part of the same component
    # union by rank optimization
    def union(self, a, b):
        pa = self.find(a)
        pb = self.find(b)
        if pa == pb: return
        if self.rank[pa] > self.rank[pb]:
            self.parent[pb] = pa
            self.rank[pa] += self.rank[pb]
        else:
            self.parent[pa] = pb
            self.rank[pb] += self.rank[pa]
    
    # find the representative of the 
    # path compression optimization
    def find(self, a):
        if self.parent[a] == a:
            return a
        
        self.parent[a] = self.find(self.parent[a])
        return self.parent[a]


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        n = len(points)
        edges = []
        for i in range(n):
            for j in range(i+1, n):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((dist, i, j))
        
        # sort based on cost (i.e. distance)
        edges.sort()
        
        # using Kruskal's algorithm to find the cost of Minimum Spanning Tree
        res = 0
        ds = DisjointSet(n)
        for cost, u, v in edges:
            if ds.find(u) != ds.find(v):
                ds.union(u, v)
                res += cost
        
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
      # Tried brute force, failed on ensuring connectivity
      # Tried all pairs shortest path, not applicable
      # Remembered MSTs and Kruskal's, implemented here after competition
      def l1(p1, p2):
        xi, yi = p1
        xj, yj = p2
        return abs(xi-xj) + abs(yi-yj)
      
      inf = float('inf')
      LV = len(points)
      E = [(u, v, l1(points[u],points[v])) 
           for u in range(LV) for v in range(LV) if u != v]
      E = sorted(E, key=lambda x: x[2])
      parent = [0] * LV
      
      def make_set(v):
        parent[v] = v
      
      def find_set(v):
        if v == parent[v]:
          return v
        parent[v] = find_set(parent[v])
        return parent[v]
      
      def union_sets(a, b):
        a = find_set(a)
        b = find_set(b)
        if a != b:
          parent[b] = a
          
      for v in range(LV):
        make_set(v)
      
      cost = 0
      for (u,v,d) in E:
        if (a:=find_set(u)) != (b:=find_set(v)):
          cost += d
          union_sets(a,b)
      
      return cost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def getDist(p1, p2):
            # |xi - xj| + |yi - yj|
            xi, yi = p1
            xj, yj = p2
            return abs(xi - xj) + abs(yi - yj)
        
        graph = collections.defaultdict(list)
        for i in range(len(points)):
            for j in range(len(points)):
                graph[i].append((getDist(points[i], points[j]), j))
        start = res = 0
        visited = { start }
        min_heap = []
        for cost, adj in graph[start]:
            heapq.heappush(min_heap, (cost, adj))
        while len(visited) < len(points) + 1 and min_heap:
            cost, next_node = heapq.heappop(min_heap)
            if next_node not in visited:
                visited.add(next_node)
                res += cost
                for next_cost, adj in graph[next_node]:
                    if adj not in visited:
                        heapq.heappush(min_heap, (next_cost, adj))
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def dist(e1, e2):
            return abs(e1[0]-e2[0])+abs(e1[1]-e2[1])
        
        def find(x):
            if p[x] !=x:
                p[x] = find(p[x])
            return p[x]
        
        def union(x,y):
            px,py = find(x), find(y)
            if px==py: return False
            p[px] = py
            return True
        
        n = len(points)
        res = 0
        p = list(range(len(points)))
        edges = []
        for i in range(n):
            for j in range(i+1,n):
                heappush(edges,(  dist(points[i],points[j]),i,j ))
                
        while edges: 
            cost,x,y = heappop(edges)
            if union(x,y):
                res += cost
                
        return res

import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n=len(points)
        hq,d,s=[(0,0)],[1]*n,0
        while hq:
            t,i=heapq.heappop(hq)
            if d[i]:
                s,d[i]=s+t,0
                for j in range(n):
                    if d[j]: heapq.heappush(hq,(abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1]),j))
        return s

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if not points or len(points) <= 1:
            return 0
        
        heap = []
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                p1 = points[i]
                p2 = points[j]
                dis = abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
                heapq.heappush(heap, (dis, i, j))
        
        self.father = [i for i in range(len(points))]
        res = 0
        while heap:
            dis, u, v = heapq.heappop(heap)
            root_u = self.find(u)
            root_v = self.find(v)
            if root_u == root_v:
                continue
            self.father[max(root_u, root_v)] = min(root_u, root_v)
            res += dis
        
        return res
    
    def find(self, x):
        if self.father[x] == x:
            return self.father[x]
        self.father[x] = self.find(self.father[x])
        return self.father[x]

from collections import defaultdict
from dataclasses import dataclass, field


@dataclass
class Edge :
   src : int
   dst : int
   weight : int

    
@dataclass
class Graph :
    num_nodes : int
    edgelist : list
    parent : list = field(default_factory = list)
    rank : list = field(default_factory = list)

    #minimum spanning tree
    mst : list = field(default_factory = list)

    def FindParent(self, node) :
        if self.parent[node] == node :
           return node
        return self.FindParent(self.parent[node])

    def KruskalMST(self) :
        self.edgelist.sort(key=lambda Edge : Edge.weight)
        self.parent = [None] * self.num_nodes
        self.rank   = [None] * self.num_nodes

        for n in range(self.num_nodes) :
            self.parent[n] = n 
            self.rank[n] = 0 

        for edge in self.edgelist :
            root1 = self.FindParent(edge.src)
            root2 = self.FindParent(edge.dst)

            if root1 != root2 :
               self.mst.append(edge)
               if self.rank[root1] < self.rank[root2] :
                  self.parent[root1] = root2
                  self.rank[root2] += 1
               else :
                  self.parent[root2] = root1
                  self.rank[root1] += 1
        
        ret = 0
        for edge in self.mst:
            ret += edge.weight
        return ret

    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        
        edges = []
        for i in range(n-1):
            for j in range(i+1, n):
                dis = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                edges.append(Edge(i,j,dis))
        
        g = Graph(n, edges)
        return g.KruskalMST()
        
        


class UnionFind:
    def __init__(self,n):
        self.parent = [i for i in range(n)]

    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]

    def union(self, x,y):
        xRoot = self.find(x)
        yRoot = self.find(y)
        if xRoot == yRoot:
            return
        self.parent[xRoot] = yRoot


class Solution:
    def minCostConnectPoints(self, points) -> int:
        n = len(points)
        uf = UnionFind(n)
        edges = []
        for i in range(n):
            for j in range(i+1,n):
                dist = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1]) 
                heappush(edges, (dist,i,j))

        totalCost = 0
        while edges:
            dist,i,j = heappop(edges)
            if uf.find(i) != uf.find(j):
                totalCost+=dist
                uf.union(i,j)
        return totalCost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n =len(points)
        if n<=1:
            return 0
        ds = UFind(n)
        hp = []
        heapq.heapify(hp)
        for i in range(n-1):
            for j in range(i+1,n):
                mhd = abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                heapq.heappush(hp, (mhd, i, j))
        
        ans = 0
        while ds.count>1:
            mhd, i, j = heapq.heappop(hp)
            if ds.union(i,j):
                ans+=mhd
        return ans
class UFind:
    def __init__(self, n):
        self.parent = list(range(n))
        self.rank = [1]*n
        self.count = n
    def find(self,x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    def union(self, x, y):
        x_par, y_par = self.find(x), self.find(y)
        if x_par == y_par:
            return False
        else:
            self.count-=1
            if self.rank[x_par]<self.rank[y_par]:
                self.parent[x_par] = y_par
            elif self.rank[x_par]>self.rank[y_par]:
                self.parent[y_par] = x_par
            else:
                self.parent[x_par] = y_par
                self.rank[y_par]+=1  
            return True
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        if not points:
            return 0
        
        cost = 0
        graph = defaultdict(dict)
        for i in range(len(points)):
            for j in range(len(points)):
                if i != j:
                    graph[i][j] = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                    graph[j][i] = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                    
        
        visited = set()
        graph[-1][0] = 0
        pq = [(0,-1,0)]
        heapq.heapify(pq)
        
        while pq:
            if len(visited) == len(points):
                return cost
            edge_cost, u,v = heapq.heappop(pq)
            if v not in visited:
                cost += edge_cost
            visited.add(v)
            for nbr in graph[v]:
                if nbr not in visited:
                    heapq.heappush(pq, (graph[v][nbr], v, nbr))
            
        return cost
                    
        


class DSU:
    def __init__(self, N):
        self.par = list(range(N))
        self.sz = [1] * N

    def find(self, x):
        if self.par[x] != x:
            self.par[x] = self.find(self.par[x])
        return self.par[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        if xr == yr:
            return False
        if self.sz[xr] < self.sz[yr]:
            xr, yr = yr, xr
        self.par[yr] = xr
        self.sz[xr] += self.sz[yr]
        return True

class Solution:
    def minCostConnectPoints(self, A: List[List[int]]) -> int:
        dict = {}
        for index,i in enumerate(A):
            dict[str(i)] = index
        res = 0
        edges = []
        for index,i in enumerate(A):
            for j in A[index+1:]:
                x = abs(i[0]-j[0])+abs(i[1]-j[1])
                y = dict.get(str(i))
                z = dict.get(str(j))
                edges.append([x,y,z])
        edges.sort()
        arr = DSU(len(A))
        for i in edges:
            if arr.union(i[1],i[2]):
                res += i[0]
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        '''
        Big idea: Union find to detect cycles. Create all edges, sort by distance. Look at each edge and add it if it doesn't make a cycle. Return the total of the added edges.
        '''
        edges = []
        for i in range(len(points)):
            p1 = tuple(points[i])
            for j in range(i+1, len(points)):
                p2 = tuple(points[j])
                dist = abs(p1[0]-p2[0]) + abs(p1[1] - p2[1])
                edges.append((dist, p1, p2))
        edges.sort()
        # print(edges)
        
        self.roots = {(x, y): (x, y) for x, y in points}
        self.ranks = {(x, y): 0 for x, y in points}
        # print(self.roots)
        
        ans = 0
        for edge in edges:
            dist, p1, p2 = edge
            if self.union(p1, p2):
                ans += dist
        return ans
    
    def union(self, p1, p2):
        p1_root, p2_root = self.find(p1), self.find(p2)
        if p1_root == p2_root:
            return False
        if self.ranks[p1_root] < self.ranks[p2_root]:
            self.roots[p1_root] = p2_root
        elif self.ranks[p1_root] > self.ranks[p2_root]:
            self.roots[p2_root] = p1_root
        else:
            # when its equal - choose whichever and update the ranks
            self.roots[p1_root] = p2_root
            self.ranks[p2_root] += 1
            
        return True
    
    def find(self, p):
        if p != self.roots[p]:
            self.roots[p] = self.find(self.roots[p])
        return self.roots[p]

class DSU:
    def __init__(self, N):
        self.p = [i for i in range(N)]
        
    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]
    
    def union(self, x, y):
        px = self.find(x)
        py = self.find(y)
        self.p[py] = px
        
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        heap = []
        result = 0
        
        n = len(points)
        
        for i in range(n-1):
            for j in range(i+1, n):
                heapq.heappush(heap, (abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1]), i, j))

        dsu = DSU(n)
        
        while heap:
            d, i, j = heapq.heappop(heap)
            pi = dsu.find(i)
            pj = dsu.find(j)
            
            if pi != pj:
                result += d
                dsu.union(i, j)
        
        return result


class DSU: 
    def __init__(self, n): 
        self.p = list(range(n))
        self.r = [0] * n
    def find(self, i): 
        if self.p[i] != i:
            self.p[i] = self.find(self.p[i])
        return self.p[i]
    def union(self, i, j): 
        pi, pj = self.find(i), self.find(j)
        if pi != pj: 
            if self.r[pi] >= self.r[pj]: 
                self.p[pj] = pi
                self.r[pi] += (self.r[pi] == self.r[pj])
            else: 
                self.p[pi] = pj
            return True
        return False

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # try minimum spanning treee
        
        to_visit = set(range(1, len(points)))
        pq = [(abs(points[0][0] - points[x][0]) + abs(points[0][1] - points[x][1]), x) for x in range(1, len(points))]
        heapq.heapify(pq)
        ans = 0
        while pq:
            cost, to = heapq.heappop(pq)
            if to in to_visit:
                to_visit.remove(to)
                ans += cost
                for nei in to_visit:
                    x, y = points[nei]
                    heapq.heappush(pq, (abs(x-points[to][0]) + abs(y-points[to][1]), nei))

        return ans
    
#     def minCostConnectPoints(self, points: List[List[int]]) -> int:
#         edges, ans = [], 0
#         for i in range(len(points)):
#             for j in range(i+1, len(points)): 
#                 edges.append((abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]), i, j))
                
#         edges.sort()
#         uf = DSU(len(points))
#         for cost, i, j in edges: 
#             if uf.find(i) != uf.find(j): 
#                 uf.union(i, j)
#                 ans += cost
#         return ans
        
                



class Solution(object):
    def minCostConnectPoints(self, points):

        g = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                g.append((i, j, abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])))
        
        g0 = sorted(g, key = lambda x: x[2])
        uf = UnionFind(len(points))
        
        ans = 0
        for x, y, z in g0:
            if uf.union(x, y):
                ans += z
        
        return ans
                         
class UnionFind():
    def __init__(self, n):
        self.parents = {i:i for i in range(0, n)}
        self.groups = n

    def find(self, x):
        if self.parents[x] == x:
            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 False

        self.parents[y] = x
        self.groups -= 1
        return True

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        dis = {}
        length = len(points)
        for i in range(length):
            dis[i] = []
        res = 0
        for i in range(length):
            for j in range(length):
                if i == j:
                    continue
                d = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                heapq.heappush(dis[i], (d, j))
        
        visited = set([0])
        res = 0
        while len(visited) < length:
            curMin = -1
            for p in visited:
                while dis[p][0][1] in visited:
                    heapq.heappop(dis[p])
                if curMin == -1 or dis[p][0][0] < dis[curMin][0][0]:
                    curMin = p
            visited.add(dis[curMin][0][1])
            res += dis[curMin][0][0]
            heapq.heappop(dis[curMin])
        return res

class Solution:
    
    class UnionFinder:
        def __init__(self, n):
            self.parents = list(range(n))
            self.ranks = [0] * n
        
        def find(self, x):
            if self.parents[x] != x:
                self.parents[x] = self.find(self.parents[x])
            return self.parents[x]
        
        def join(self, x, y):
            p1 = self.find(x)
            p2 = self.find(y)
            
            if p1 == p2:
                return False
            
            r1 = self.ranks[p1]
            r2 = self.ranks[p2]
            
            if r1 < r2:
                self.parents[p1] = p2
            elif r2 < r1:
                self.parents[p2] = p1
            else:
                self.parents[p1] = p2
                self.ranks[p2] += 1
            return True
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        heap = list()
        
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                heapq.heappush(heap, (abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]), i, j))
                
        union_finder = Solution.UnionFinder(len(points))
        ans = 0
        while heap:
            d, i, j = heapq.heappop(heap)
            if union_finder.join(i, j):
                ans += d
        return ans


class Solution:
    def minCostConnectPoints(self, points):
        distance = lambda p1, p2: abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        points.sort(key = lambda p: p[0] + p[1])
        total_cost = 0
        points = [[p, distance(p, points[0])] for p in points]
        while points:
            minIdx, mindist = None, float('inf')
            for i, (p1, dist) in enumerate(points):
                if dist < mindist:
                    minIdx, mindist = i, dist
            p1, cost = points.pop(minIdx)
            total_cost += cost
            for i, (p2, dist) in enumerate(points):
                points[i][1] = min(points[i][1], distance(p1, p2))
        return total_cost

from heapq import *
from collections import defaultdict
class Solution:
    def minCostConnectPoints(self, points):
        N = len(points)
        dist = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        edges = defaultdict(list)
        for i1, p1 in enumerate(points):
            for i2, p2 in enumerate(points[i1+1:], start = i1+1):
                distance = dist(p1, p2)
                edges[i1].append([distance, i2])
                edges[i2].append([distance, i1])
        heap = edges[0]
        heapify(heap)
        total_cost, seen = 0, {0}
        while len(seen) < N:
            cost, node = heappop(heap)
            if node in seen:
                continue
            seen.add(node)
            total_cost += cost
            for dist, next_ in edges[node]:
                if next_ not in seen:
                    heappush(heap, [dist, next_])
        return total_cost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        from queue import PriorityQueue
        
        coors = {}
        count = 0
        for point in points:
            coors[count] = tuple(point)
            count = count + 1
        pq = PriorityQueue()
        pq.put((0, 0)) # dist, nodeIdx
        visited = set()
        total = 0
        while (len(visited) < len(points)):
            cost, nodeIdx = pq.get()
            if nodeIdx in visited:
                continue
            total = total + cost
            visited.add(nodeIdx)
            node = coors[nodeIdx]
            for nextNodeIdx in range(len(points)):
                if nextNodeIdx not in visited:
                    nextNode = coors[nextNodeIdx]
                    nextCost = abs(nextNode[0] - node[0]) + abs(nextNode[1] - node[1])
                    pq.put((nextCost, nextNodeIdx))
        return total

class Solution:
    # Time: O(n^2)
    # Space: O(n)
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n == 1:
            return 0
        res, curr = 0, 0
        distances = [float('inf') for _ in range(n)]
        explored = set()
        
        for i in range(n - 1):
            x0, y0 = points[curr]
            explored.add(curr)
            for j, (x, y) in enumerate(points):
                if j in explored:
                    continue
                distances[j] = min(distances[j], abs(x0 - x) + abs(y0 - y))
                
            delta, curr = min((d, j) for j, d in enumerate(distances))
            res += delta
            distances[curr] = float('inf')
            
        return res         

class Subsets:
    def __init__(self,parent,rank):
        self.parent=parent
        self.rank=rank
        
def find(subsets,node):
    
    if subsets[node].parent!=node:
        subsets[node].parent=find(subsets,subsets[node].parent)
        
    return subsets[node].parent

def union(subsets,x,y):
    xr=find(subsets,x)
    yr=find(subsets,y)
    if xr==yr:
        return False
    else:
        xr=subsets[xr]
        yr=subsets[yr]
        if xr.rank<yr.rank:
            xr.parent=yr.parent
        elif yr.rank<xr.rank:
            yr.parent=xr.parent
        else:
            xr.parent=yr.parent
            yr.rank+=1
        return True

def distance(p1,p2):
    x1,y1=p1
    x2,y2=p2
    return abs(x1-x2)+abs(y1-y2)

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        subsets={}
        for x,y in points:
            subsets[(x,y)]=Subsets((x,y),0)
        
        edges=[]
        
        for i in range(len(points)-1):
            p1=tuple(points[i])
            for j in range(i+1,len(points)):
                p2=tuple(points[j])
                edges.append((distance(p1,p2),p1,p2))
                
        edges.sort()
        ans=0
        
        for w,p1,p2 in edges:
            if union(subsets,p1,p2):
                ans+=w
                
        return ans
                
        
        
        
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        h = []
        visited = set()
        dist = lambda a,b : abs(a[0]-b[0]) + abs(a[1]-b[1])

        for i in range(len(points)):
            for j in range(i):
                h.append((dist(points[i], points[j]), i,j))
        heapq.heapify(h)
        total = 0
        uf = UnionFind([i for i in range(len(points))])
        
        while h and len(visited) < len(points):
            dist, i,j = heapq.heappop(h)
            if uf.find(i) != uf.find(j):
                uf.union(i,j)
                total +=dist

        return total
                
class UnionFind:
        
        def __init__(self, arr):
            self.parent = [i for i in range(len(arr))]
            self.rank = [0] * len(arr)
        
        
        def find(self, i):
            if self.parent[i] == i:
                return i
            p = self.find(self.parent[i])
            self.parent[i] = p
            return p
        
        def union(self, a,b):
            pa, pb = self.find(a), self.find(b)
            if self.rank[pa]>self.rank[pb]:
                self.parent[pb] = pa
            elif self.rank[pb]>self.rank[pa]:
                self.parent[pa] = pb
            else:
                self.parent[pb] = pa
                self.rank[pa] +=1
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        parent = [i for i in range(len(points))]
        size = [1 for _ in range(len(points))]
        
        def root(p):
            while parent[p] != p:
                parent[p] = parent[parent[p]]
                p = parent[p]
                
            return p
        
        def union(p, q):
            root_p, root_q = root(p), root(q)
            if root_p != root_q:
                if size[root_p] < size[root_q]:
                    parent[root_p] = root_q
                    size[root_q] += size[root_p]
                else:
                    parent[root_q] = root_p
                    size[root_p] += size[root_q]
        
        def connected(p, q):
            return root(p) == root(q)
        
        p = points
        ans = 0
        def dist(p1, p2):
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        
        heap = []
        for i in range(len(p)):
            for j in range(i+1, len(p)):
                temp = dist(p[i],p[j])
                heappush(heap, (temp, (i, j)))
        
        while heap:
            dis, (i, j) = heappop(heap)
            if not connected(i, j):
                ans += dis
                union(i, j)
                                
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        costs = []
        for i in range(len(points)) :
            xi, yi = points[i]
            for j in range(i+1, len(points)) :
                xj, yj = points[j]
                costs.append([abs(xi-xj)+abs(yi-yj), i, j])
        costs = sorted(costs)
        
        fathers = {t:t for t in range(len(points))}
        def get_father(n) :
            while not fathers[n] == fathers[fathers[n]] :
                fathers[n] = fathers[fathers[n]]
            return fathers[n]
        
        to_ret = 0
        for t in costs :
            ct, pi, pj = t
            if get_father(pi) == get_father(pj) :
                continue
            
            fathers[get_father(pj)] = get_father(pi)
            to_ret += ct
        return to_ret

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def find(u):
            if p[u]==-1:
                return u
            
            p[u] = find(p[u])
            return p[u]
        
        def union(u, v):
            
            if r[u]>r[v]:
                p[v] = u
            elif r[u]<r[v]:
                p[u] = v
            else:
                p[v] = u
                r[u]+=1
            
        n = len(points)
        edges = []
        for i in range(n):
            for j in range(i+1,n):
                edges.append([abs(points[j][0]-points[i][0])+abs(points[j][1]-points[i][1]),i,j])
        
        edges.sort()
        
        p = [-1]*n
        r = [0]*n
        
        res = 0
        
        for x in edges:
            u = find(x[1])
            v = find(x[2])
            if u!=v:
                res += x[0]
                union(u, v)
        
        return res


import heapq

class Solution:
  def minCostConnectPoints(self, points: List[List[int]]) -> int:
    def distance(p1, p2):
      return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])

    L = len(points)
    if L <= 1:
      return 0

    todo = set(range(L))
    nex = 0
    h = []
    ans = 0
    while todo:
      todo.remove(nex)
      for i in todo:
        heapq.heappush(h, (distance(points[nex], points[i]), i))
      while h and h[0][1] not in todo:
        heapq.heappop(h)
      if not h:
        break
      cost, nex = heapq.heappop(h)
      ans += cost
    return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        dis=[[[0,x] for x in range(len(points))] for x in range(len(points))]
        for i,x in enumerate(points):
            for y in range(i+1,len(points)):
                temp=abs(x[0]-points[y][0])+abs(x[1]-points[y][1])
                dis[i][y][0]=temp
                dis[y][i][0]=temp
        for x in range(len(dis)):
            dis[x].sort()
        
        # which I have not included in mst
        rem=[1 for x in range(len(points))]
        
        c=0
        inc={0:1}
        while len(inc)<len(points):
            minn=[float(\"inf\"),-1]
            for x in inc:
                while dis[x][rem[x]][1] in inc:
                    rem[x]+=1
                if dis[x][rem[x]][0]<minn[0]:
                    minn[0],minn[1]=dis[x][rem[x]][0],dis[x][rem[x]][1]
            inc[minn[1]]=1
            c+=minn[0]
        return c
            
        # print(dis)
        

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        d = collections.defaultdict(list)
        m = {}
        for i in range(len(points)):
            m[(points[i][0], points[i][1])] = i
        h = []
        for i in range(len(points)-1):
            for j in range(i+1, len(points)):
                x1, y1 = points[i][0], points[i][1]
                x2, y2 = points[j][0], points[j][1]
                k = self.manhattan(x1,y1,x2,y2)
                d[m[(x1,y1)]].append([m[(x2,y2)], k])
                d[m[(x2,y2)]].append([m[(x1,y1)], k])
                    
        # initialize heap for prim's
        ans = 0
        h = []
        for n,w in d[0]:
            h.append([w,n])
        heapq.heapify(h)
        seen = set({0})
        while h:
            w,n = heapq.heappop(h)
            if n in seen: continue
            seen.add(n)
            ans += w
            if len(seen) == len(points): break
            for n2, w2 in d[n]:
                heapq.heappush(h, [w2, n2])
        return ans
                    
    def manhattan(self, x1, y1, x2, y2):
        return abs(x2-x1) + abs(y2-y1)
                
                


#Build weighted graph and then use Union-Find to get MST
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N, g = len(points), []
        res = 0
        
        #build the weighted graph
        for i in range(N - 1):
            x0, y0 = points[i]
            for j in range(i + 1, N):                
                x1, y1 = points[j]
                dist = abs(x0 - x1) + abs(y0 - y1)
                g.append((dist, (i, j)))
                
        #sort by weight
        g.sort()
        
        #Union-Find to get MST
        parents = [None] * N
        for i in range(N): parents[i] = i
            
        def findParent(x):
            if parents[x] != x:
                parents[x] = findParent(parents[x])
            
            return parents[x]
        
        for w, (a, b) in g:
            pa = findParent(a)
            pb = findParent(b)
            
            #union sub-graphs if not connected yet
            if pa != pb:
                res += w
                parents[pa] = pb
        
        return res



class UnionFind(object):
    def __init__(self, n):
        # * only idff from template is it starts at 0
        self.count = n
        self.parent = [i for i in range(n)]
        self.rank = [1 for _ in range(n)]

    def find(self, p):
        if p != self.parent[p]:
            self.parent[p] = self.find(self.parent[p])
        return self.parent[p]

    def union(self, p, q):
        p_root, q_root = self.find(p), self.find(q)
        if p_root == q_root:
            return False
        if self.rank[p_root] > self.rank[q_root]:
            p_root, q_root = q_root, p_root
        self.parent[p_root] = q_root
        self.rank[q_root] += self.rank[p_root]
        self.count -= 1
        return True


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        uf = UnionFind(n)

        def manhattan(p1, p2):
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])

        g = collections.defaultdict(list)
        n = len(points)
        heap = []
        #create graph
        for i in range(n):
            for j in range(i + 1, n):
                distance = manhattan(points[i], points[j])
                heap.append((distance, i, j))
        res = 0
        heapq.heapify(heap)
        while heap:
            weight, i, j = heapq.heappop(heap)
            if uf.union(i, j):
                res += weight
        return res

#Prim's algorith for COMPLETE GRAPH: O(N ** 2), O(|V| ** 2)
#Since every node is connected, we can select one node to start with, and calculate all distances to it and take
#   the minimum distance node to it to add to the spanning tree. For the newly added node, update shortest 
#   distances to the rest of the nodes (i.e. distance to the current spanning tree). We can then choose the 
#   minimum distance node to add to the current spanning tree, and so on.
#Note: it doesn't matter which node in the existing spanning tree that the new node is connected with. We only
#       need its distance to be minimum when connecting to the current spanning tree
#Time: O(N ** 2)
#Sapce: O(M * N)
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        dist = [math.inf] * N
        
        #mark the starting node
        prev_node = 0
        res = 0
        
        def getDistance(x, y):
            return abs(points[x][0] - points[y][0]) + abs(points[x][1] - points[y][1])
        
        for _ in range(N):
            min_dist, min_dist_node = math.inf, -1
            
            #use distance = None to mark this node has been included in the current spanning tree
            for i in range(N):
                if dist[i] != None:
                    dist[i] = min(dist[i], getDistance(prev_node, i))
                    if dist[i] < min_dist:
                        min_dist, min_dist_node = dist[i], i
            
            res += min_dist
            prev_node = min_dist_node
            dist[prev_node] = None
        
        return res


from heapq import heappush,heappop
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def calcCost(i,j):
            return abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
        q=[(0,0)]
        visited=set()
        totalCost=0
        while q:
            cost,point=heappop(q)
            if point not in visited:
                visited.add(point)
                totalCost+=cost
                for i in range(len(points)):
                    if i!=point and not i in visited:
                        heappush(q,(calcCost(point,i),i))
        return totalCost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        parent = {}
        size = defaultdict(lambda: 1)

        def find(u):
            if u != parent.get(u, u):
                parent[u] = find(parent[u])  # path compression
            return parent.get(u, u)

        def union(u, v):
            u, v = find(u), find(v)
            if u != v:
                if size[u] < size[v]:  # union by size / rank
                    u, v = v, u

                parent[v] = u
                size[u] += size[v]

        total = 0
        edges = []
        n = len(points)
        for i in range(len(points)):
            for j in range(len(points)):
                if i!=j:
                    edges.append((abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1]),i,j))
        edges.sort()

        count = 0
        for cost, u, v in edges:
            if find(u) != find(v):
                total += cost
                count += 1
                union(u, v)
                if count == n-1:
                    return total

        return total
        


class DSU:
    def __init__(self, N):
        self.parent = list(range(N))
    
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        if xr == yr:
            return False
        self.parent[yr] = xr
        return True


class Solution:
    def minCostConnectPoints(self, P: List[List[int]]) -> int:
        from collections import defaultdict
        #G = defaultdict(set)
        connections = []
        for i in range(len(P)):
            for j in range(i+1, len(P)):
                if i != j:
                    cost = abs(P[i][0] - P[j][0]) + abs(P[i][1] - P[j][1])
                    #G[i].add((j, cost))
                    #G[j].add((i, cost))
                    connections.append([i,j,cost])
        #print(connections)
        #print(len(connections))
        connections = list(connections)
        connections.sort(key = lambda x : x[2])
        dsu = DSU(len(P))
        res = 0
        for u,v,w in connections:
            curr = dsu.union(u,v)
            if curr:
                res += w
        return res


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        dic = {}
        for i in range(len(points)):
            val = []
            for j in range(len(points)):
                if points[j] != points[i]:
                    val = (abs(points[j][0]-points[i][0]) + abs(points[j][1] - points[i][1]))   
                    dic[i,j] = val
        #print(dic)
        g = Graph(len(points))
        
        for k,v in list(dic.items()):
            g.addEdge(k[0],k[1],v)
        
        res = g.KruskalMST()
        print(res)
        return res

class Graph:
    def __init__(self, vertices):
        self.v = vertices
        self.graph = []
        
    def addEdge(self, u, v, w):
        self.graph.append([u,v,w])
        
    def find(self,parent, i):
        if parent[i] == -1:
            return i
        return self.find(parent, parent[i])
    
    def union(self, parent, x, y):
        x_set = self.find(parent, x)
        y_set = self.find(parent, y)
        parent[x_set] = y_set
        
    def KruskalMST(self):
        MST = []
        i = 0
        e = 0
        self.graph = sorted(self.graph, key = lambda e:e[2])
        parent = [-1] * self.v
        while e < self.v -1:
            u,v,w = self.graph[i]
            i += 1
            x = self.find(parent,u)
            y = self.find(parent, v)
            #print(x,y)
            if x!= y:
                e += 1
                MST.append([u,v,w])
                self.union(parent,x,y)
                #print(MST)
        s = 0
        for u,v,w in MST:
            s += w
        return s
        


from heapq import heappush, heappop
from collections import defaultdict

class Solution:
    '''
    min-spanning-tree?
    * generate graph from all points
    * edgerelaxation with pq,
    '''
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def taxicab(x1, x2, y1, y2):
            return abs(x1 - x2) + abs(y1 - y2)
        
        def gengraph():
            graph = defaultdict(list)
            
            for i, point in enumerate(points):
                x1, y1 = point
                for j in range(i + 1, len(points)):
                    x2, y2 = points[j]
                    cost = taxicab(x1, x2, y1, y2)
                    graph[(x1, y1)].append((cost, (x2, y2)))
                    graph[(x2, y2)].append((cost, (x1, y1)))
                    
            return graph
        
        graph = gengraph()
        relaxed = set()
        start = tuple(points[0])
        heap = [(0, start)]
        mincost = 0
        
        while heap and len(relaxed) < len(points):
            cost, pos = heappop(heap)
            
            if pos in relaxed:
                continue
                
            relaxed.add(pos)
            mincost += cost
            
            for nbr in graph[pos]:
                if nbr not in relaxed:
                    heappush(heap, nbr)
                
        return mincost

from collections import defaultdict
import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        total, heap, visited = 0, [(0, 0)], set()
        distances = defaultdict(list)
        for i in range(len(points) - 1):
            for j in range(1, len(points)):
                distances[i].append((self.distance(points[i], points[j]), j))
                distances[j].append((self.distance(points[i], points[j]), i))
        while heap and len(visited) < len(points):
            distance, point = heapq.heappop(heap)
            if point not in visited:
                visited.add(point)
                total += distance
                for neighbor_distance, neighbor in distances[point]:
                    if neighbor not in visited:
                        heapq.heappush(heap, (neighbor_distance, neighbor))
        return total
                
            
        
    def distance(self, pair1, pair2):
        return abs(pair1[0] - pair2[0]) + abs(pair1[1] - pair2[1])

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        root = list(range(N))
        size = [1] * N
        res = 0
        
        def find(x):
            root[x] = find(root[x]) if root[x] != x else root[x]
            
            return root[x]
        
        def union(x, y):
            x, y = find(x), find(y)
            
            if x == y: return False
            
            if size[x] < size[y]: x, y = y, x
                
            root[y] = x
            size[x] += size[y]
            
            return True
        
        edge_ls = []
        
        for i, cur in enumerate(points):
            for j, nxt in enumerate(points[i + 1:]):
                dist = abs(cur[0] - nxt[0]) + abs(cur[1] - nxt[1])
                edge_ls.append([dist, i, i + j + 1])
                
        edge_ls.sort()
        
        for dist, u, v in edge_ls:
            if find(u) != find(v):
                res += dist
                union(u, v)
                
        return res
                
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def hash_point(point):
            return point[0],point[1]
        
        def manh_dist(point1, point2):
            return abs(point1[0] - point2[0]) + abs(point1[1] - point2[1])
        
        if len(points) == 1: return 0
        if len(points) == 2: return manh_dist(points[0], points[1])
        
        points_remaining = set()
        dists = []
        first_point = points[0]
        
        for i in range(1, len(points)):
            point,h_point = points[i],hash_point(points[i])
            points_remaining.add(h_point)
            heapq.heappush(dists, (manh_dist(first_point, point), h_point))
        
        ans = 0
        
        while points_remaining and dists:
            dist,point = heapq.heappop(dists)
            
            if point not in points_remaining: continue
                
            points_remaining.remove(point)
            ans += dist
            
            for p in points_remaining:
                heapq.heappush(dists, (manh_dist(point, p), p))
                
        return ans


class DSU:
    def __init__(self, N):
        self.par = list(range(N))
        self.sz = [1]*N
        
    def find(self, x):
        if self.par[x] != x:
            self.par[x] = self.find(self.par[x])
        return self.par[x]
    
    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        
        if xr == yr:
            return False
        if self.sz[xr] < self.sz[yr]:
            xr, yr = yr, xr
            
        self.par[yr] = xr
        self.sz[xr] += self.sz[yr]
        return True
    
    def size(self, x):
        return self.sz[self.find(x)]
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        edges = []
        N = len(points)
        for i in range(N):
            for j in range(i+1,N):
                d = abs(points[i][0]-points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append([d, i, j])
                
        edges.sort()
        
        dsu = DSU(N)
        res = 0
        
        for d,u,v in edges:
            if dsu.union(u, v):
                res += d
                
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        arr = [-1 for _ in range(len(points))]
        def find(i):
            while arr[i]>=0:
                i = arr[i]
            return i
        
        def union(x,y):
            xp = find(x)
            yp = find(y)
            if xp==yp:
                return False
            arr[yp] = xp
            #arr[yp]-=1
            return True
        
        
        for i in range(len(points)):
            x, y = points[i]
            for j in range(i+1,len(points)):
                x1,y1 = points[j]
                edges.append([abs(x-x1)+abs(y-y1),i,j])
        edges = sorted(edges)
        res = 0
        for score,i,j in edges:
            if union(i,j):
                res+=score
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        edges = []
        for i, p1 in enumerate(points):
            for j in range(i, len(points)):
                p2 = points[j]
                
                d = abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
                edges.append([d, i, j])
        edges = sorted(edges)

        u = {i: i for i in range(n)}
        
        def head(i):
            if u[i] == i:
                return i
            else:
                h = head(u[i])
                u[i] = h
                return h
            
        def union(i, j):
            u[head(j)] = head(i)
        
        r = 0
        for d, i, j in edges:
            hi, hj = head(i), head(j)
            if hi != hj:
                r += d
                union(hi, hj)
                
        return r
                
        



class UnionFind:
    def __init__(self, n):
        self.groups = list(range(n))
        self.size = [1] * n
        
    def find(self, i):
        if self.groups[i] == i:
            return i
        p = self.find(self.groups[i])
        self.groups[i] = p
        return p
    
    def union(self, i, j):
        pi = self.find(i) 
        pj = self.find(j)
        if self.size[pi] < self.size[pj]:
            self.groups[pi] = pj
            self.size[pj] += self.size[pi]
        else:
            self.groups[pj] = pi
            self.size[pi] += self.size[pj]
        
        

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        cost_array = []
        
        for i in range(len(points) - 1):
            for j in range(i+1, len(points)):
                weight = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                cost_array.append((weight, i, j))
        cost_array.sort()
        res = 0
        uf = UnionFind(len(points))
        for weight, i, j in cost_array:
            if uf.find(i) == uf.find(j):
                continue
            uf.union(i, j)
            res += weight
        return res
        
        
        
        
                
                
                


from heapq import heappush,heappop
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        distsDict=[[None]*len(points) for _ in range(len(points))]
        for i in range(len(points)):
            for j in range(i+1,len(points)):
                distsDict[i][j]=distsDict[j][i]=abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
        q=[(0,0)]
        visited=set()
        totalCost=0
        while q:
            cost,point=heappop(q)
            if point not in visited:
                visited.add(point)
                totalCost+=cost
                for i in range(len(points)):
                    if i!=point and not i in visited:
                        heappush(q,(distsDict[point][i],i))
        return totalCost

# alright, whatever, time to solve it again in Python3 \\U0001f40d  whoo!

# ok silly mistake, but that's A ok :)

class Solution:
    def minCostConnectPoints(self, A: List[List[int]]) -> int:
        N = len(A)
        P = [i for i in range(N)]  # parent representatives of disjoint sets
        E = []
        for i in range(N):
            x1, y1 = A[i]
            for j in range(i + 1, N):
                x2, y2 = A[j]
                E.append([ abs(x1 - x2) + abs(y1 - y2), i, j ])
        E.sort()
        def find(x):
            P[x] = P[x] if P[x] == x else find(P[x])
            return P[x]
        def union(a, b):
            a = find(a)
            b = find(b)
            if a == b:
                return False
            P[a] = b   # arbitrary choice
            return True
        return sum([cost for cost, u, v in E if union(u, v)])
        # for cost, u, v in E:
        #     if union(u, v):
        #         total += cost
        # return total


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        data = [i for i in range(len(points))]
        pq = []
        res = 0
        def helper(p1, p2):
            return abs(p1[0]-p2[0])+abs(p1[1]-p2[1])
        
        def find(x):
            if x != data[x]:
                data[x] = find(data[x])
                
            return data[x]
        
        def union(x,y):
            root_x = find(x)
            root_y = find(y)
            
            if root_x == root_y:
                return False
            
            data[root_x] = root_y
            
            return True
        
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                heapq.heappush(pq, (helper(points[i],points[j]),i,j))
        
        res = 0
        
        while pq:
            cost, p1, p2 = heapq.heappop(pq)
            if union(p1,p2):
                res += cost
        
        
        return res


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        arr = [-1 for _ in range(len(points))]
        def find(i):
            while arr[i]>=0:
                i = arr[i]
            return i
        
        def union(x,y):
            xp = find(x)
            yp = find(y)
            if xp==yp:
                return False
            arr[yp] = xp
            arr[xp]-=1
            return True
        
        
        for i in range(len(points)):
            x, y = points[i]
            for j in range(i+1,len(points)):
                x1,y1 = points[j]
                edges.append([abs(x-x1)+abs(y-y1),i,j])
        edges = sorted(edges)
        res = 0
        for score,i,j in edges:
            if union(i,j):
                res+=score
        return res

class Solution:
#     def minCostConnectPoints(self, points: List[List[int]]) -> int:
#         n = len(points)
#         if len(points) == 1: return 0
#         res = 0
#         curr = 0 # select a random point as the starting point
#         dis = [math.inf] * n
#         explored = set()
        
#         for i in range(n - 1):
#             x0, y0 = points[curr]
#             explored.add(curr)
#             for j, (x, y) in enumerate(points):
#                 if j in explored: continue
#                 dis[j] = min(dis[j], abs(x - x0) + abs(y - y0))
                
#             delta, curr = min((d, j) for j, d in enumerate(dis)) 
#             dis[curr] = math.inf
#             res += delta
            
#         return res
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n == 1:
            return 0
        e = []
        for i, p1 in enumerate(points):
            for j in range(i + 1, n):
                p2 = points[j]
                w = abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
                e.append((i, j, w))
                e.append((j, i, w))
        parents = [i for i in range(n)]
        ranks = [1 for _ in range(n)]
        def find(x):
            while x != parents[x]:
                parents[x] = parents[parents[x]]
                x = parents[x]
            return x
        def union(x, y):
            px, py = find(x), find(y)
            if px == py:
                return False
            if ranks[px] > ranks[py]:
                parents[py] = px
            elif ranks[px] < ranks[py]:
                parents[px] = py
            else:
                parents[py] = px
                ranks[px] += 1
            return True
        res = 0
        for u, v, w in sorted(e, key=lambda x: x[2]):
            if not union(u, v):
                continue
            else:
                res += w
        return res

class Solution:
    def minCostConnectPoints(self, points):
        distance = lambda p1, p2: abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        points.sort(key = lambda p: (p[0]) + (p[1]))
        total_cost = 0
        points = [[p, distance(p, points[0])] for p in points]
        while points:
            minIdx, mindist = None, float('inf')
            for i, (p1, dist) in enumerate(points):
                if dist < mindist:
                    minIdx, mindist = i, dist
            p1, cost = points.pop(minIdx)
            total_cost += cost
            for i, (p2, dist) in enumerate(points):
                newdist = distance(p1, p2)
                if newdist < dist:
                    points[i][1] = newdist
        return total_cost        

class Solution:
    def addEdge(self,source, dest, weight):
        self.graph.append([tuple(source), tuple(dest), weight])
        
    def getParent(self, vertex):
        if vertex == self.parent[vertex]:
            return vertex
        return self.getParent(self.parent[vertex])
        
    def joinTrees(self, u, v):
        xroot = self.getParent(u)
        yroot = self.getParent(v)
        
        if self.rank[xroot] > self.rank[yroot]:
            self.parent[yroot] = xroot
        elif self.rank[yroot] < self.rank[xroot]:
            self.parent[xroot] = yroot
        else:
            self.parent[yroot] = xroot
            self.rank[yroot]+=1
        
        
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        self.graph = []
        
        for i in range(0, len(points)):
            for j in range(i+1, len(points)):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]) 
                self.addEdge(points[i], points[j], dist)
        
        self.V = len(points)
        
        e = 0
        self.parent = {tuple(points[i]): tuple(points[i]) for i in range(0, len(points))}
        self.rank = {tuple(points[i]): 0 for i in range(0, len(points))}
        
        
        self.graph = sorted(self.graph, key = lambda x: x[2])
        
        i = 0
        tot = 0
        
        while e < self.V-1:
            
            u, v, w = self.graph[i]
            i+=1
            uroot = self.getParent(u)
            vroot = self.getParent(v)
            
            if uroot != vroot:
                self.joinTrees(u, v)
                tot+=w
                e+=1
        return tot


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int: 
        def pdist(i, j): 
            return abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
        N = len(points)
        pvisited = [False] * N
        h = []
        mincost = 0
        heappush(h, (0, 0))
        while h: 
            dist, el = heappop(h)
            if not pvisited[el]: 
                pvisited[el] = True
                mincost += dist
                for i in range(N): 
                    if not pvisited[i]: 
                        heappush(h, (pdist(el, i), i))
        return mincost
        
        


class DSU:
    def __init__(self, n):
        self.par = list(range(n))
        
    def find(self, x):
        if self.par[x] != x:
            self.par[x] = self.find(self.par[x])
        return self.par[x]
    
    def union(self, x, y):
        px = self.find(x) 
        py = self.find(y)
        if px != py:
            self.par[px] = py

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) <= 1:
            return 0
        def dist(x1, y1, x2, y2):
            return abs(x2-x1) + abs(y2-y1)
        lens = []
        res = 0
        n = len(points)
        dsu = DSU(n)
        for i in range(n-1):
            for j in range(i+1, n):
                lens.append((dist(points[i][0], points[i][1], points[j][0], points[j][1]), i, j))
        heapq.heapify(lens)
        while lens:
            dist, i, j = heapq.heappop(lens)
            if dsu.find(i) != dsu.find(j):
                dsu.union(i, j)
                res += dist
        return res

class Solution:
  def minCostConnectPoints(self, points: List[List[int]]) -> int:
    if len(points) == 1:
      return 0
    
    def get_dist(p1, p2):
      return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
    
    seen, res = set([0]), 0
    
    heap = [(get_dist(points[0], p2), i + 1) for i, p2 in enumerate(points[1:])]
    heapq.heapify(heap)

    while heap:
      dist, index = heapq.heappop(heap)
      
      if index in seen:
        continue

      seen.add(index)
      res += dist
      
      for i in range(len(points)):
        if i != index and i not in seen:
          heapq.heappush(heap, (get_dist(points[i], points[index]), i))
        
    return res
      


class Solution:
    def __init__(self):
        self.parent = dict()
        self.rank = dict()

    def find(self, x: int) -> int:
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def union(self, x: int, y: int) -> None:
        if self.rank[x] > self.rank[y]:
            self.parent[y] = x
        elif self.rank[y] > self.rank[x]:
            self.parent[x] = y
        else:
            self.rank[x] += 1
            self.parent[y] = x
        
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        l = len(points)
        ans = 0
        if l > 1:
            heap = list()
            for i in range(l-1):
                self.parent[i] = i
                self.rank[i] = 0
                for j in range(i+1,l):
                    heap.append((abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1]),i,j))
            self.parent[l-1] = l-1
            self.rank[l-1] = 0
            heapq.heapify(heap)
            while heap:
                dis,x,y = heapq.heappop(heap)
                if self.find(x) != self.find(y):
                    ans += dis
                    self.union(self.find(x),self.find(y))
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        self.parent = list(range(len(points)))
        self.rank = [1]*len(points)
        
        def find(a):
            if self.parent[a] != a:
                self.parent[a] = find(self.parent[a])
            return self.parent[a]
        
        def union(a,b):
            p1 = find(a)
            p2 = find(b)
            if p1 == p2: return False
            if self.rank[p1] > self.rank[p2]:
                self.parent[p2] = p1
            else:
                if self.rank[p1] < self.rank[p2]:
                    self.parent[p1] = p2
                else:
                    self.parent[p1] = p2
                    self.rank[p2] += 1
            return True
        
        def dist(a,b):
            return abs(a[0]-b[0])+abs(a[1]-b[1])
        
        weights = {}
        edges = []
        for i in range(len(points)):
            for j in range(i+1,len(points)):
                weights[(i,j)] = dist(points[i], points[j])
                edges.append((i,j))
        
        edges.sort(key=lambda x: weights[x])
        
        ans = 0
        
        for e in edges:
            if union(e[0],e[1]):
                ans += weights[e]
                
        return ans
        


class DSU:
    def __init__(self, n):
        self.parents = list(range(n))
        self.cc = n
    
    def find(self, u):
        orig = u
        while u != self.parents[u]:
            u = self.parents[u]
        
        self.parents[orig] = u
        return u
    
    def union(self, u, v):
        u,v = sorted([self.find(u),self.find(v)])
        
        if u!=v:
            self.parents[v] = u
            self.cc -= 1
            return True
        return False
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        distances = {}
        
        def compute(p1,p2):
            x1,y1 = p1
            x2,y2 = p2
            return abs(x1-x2)+abs(y1-y2)
        
        heap = []
        for i,p1 in enumerate(points):
            for j in range(i+1,len(points)):
                p2 = points[j]
                heapq.heappush(heap, (compute(p1,p2),i,j))
        
        dsu = DSU(len(points))
        
        res = 0
        while heap:
            d,u,v = heapq.heappop(heap)
            if dsu.union(u,v):
                res+=d
        return res


from queue import PriorityQueue
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        q = PriorityQueue() # queue of (dist, x, y)
        x0, y0 = points[0]
        for x, y in points[1:]:
            q.put([abs(x - x0) + abs(y - y0), x, y])
        cost = 0
        to_process = set([(x, y) for x, y in points[1:]])
        while len(to_process) > 0:
            d, x, y = q.get()
            if (x, y) not in to_process:
                continue
            to_process.remove((x, y))
            cost += d
            for nx, ny in to_process:
                q.put([abs(x - nx) + abs(y - ny), nx, ny])
        return cost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        ans = 0
        mx = -1
        inc = set()
        d = {}
        parent = []
        rank = []
        result = []
        i = 0
        e = 0
        nodes = {}
        idx = 0
        for i in range(n):
            nodes[idx] = (points[i][0],points[i][1])
            idx+=1
        graph = []
        for i in range(n):
            d[i] = []
            for j in range(n):
                if i == j:
                    continue
                graph.append([i,j,abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])])
        graph.sort(key=lambda x : x[2])  
        def find(parent,i):
            if parent[i] == i:
                return i
            return find(parent,parent[i])
        
        def union(parent,rank,x,y):
            xroot = find(parent,x)
            yroot = find(parent,y)
            
            if rank[xroot] < rank[yroot]:
                parent[xroot] = yroot
            elif rank[yroot] < rank[xroot]:
                parent[yroot] = xroot
            else:
                parent[yroot] = xroot
                rank[xroot] += 1
                
        for node in range(n):
            parent.append(node)
            rank.append(0)
        i = 0
        ans = 0
        while e < n-1:
            u,v,w = graph[i]
            i+=1
            x = find(parent,u)
            y = find(parent,v)
            if x != y:
                e = e+1
                ans += w
                union(parent,rank,x,y)
        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        res = 0
        n = len(points)
        dist = [0] * n
        def distance(px, py):
            return abs(px[0] - py[0]) + abs(px[1] - py[1])
        for i in range(1, n):
            dist[i] = distance(points[0], points[i])
        flag = [0] * n
        flag[0] = 1
        for i in range(1, n):
            mi = math.inf
            index = -1
            for j in range(1, n):
                if flag[j]:
                    continue
                if mi > dist[j]:
                    index = j
                    mi = dist[j]
            flag[index] = 1
            res += mi
            for j in range(1, n):
                if flag[j]:
                    continue
                dist[j] = min(dist[j], distance(points[j], points[index]))
        return res


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        l=len(points)
        parent=[i for i in range(l)]
        def find(a):
            if parent[a]!=a:
                parent[a]=find(parent[a])
            return parent[a]
        
        def union(a,b):
            p1=find(a)
            p2=find(b)
            parent[p2]=p1
        
        
        import heapq
        def new_cmp_lt(self,a,b):
            return a[0]-b[0]
        heapq.cmp_lt=new_cmp_lt
        res=0
        
        p=[]
        for i in range(l):
            for j in range(i+1,l):
                p1=points[i]
                p2=points[j]
                d=abs(p1[0]-p2[0])+abs(p1[1]-p2[1])
                heapq.heappush(p,[d,i,j])
        while p:
            t=heapq.heappop(p)
            d=t[0]
            p1=t[1]
            p2=t[2]
            if find(p1)!=find(p2):
                union(p1,p2)
                res+=d
        return res
        


class DSU:
    def __init__(self, n):
        self.p = list(range(n))
        self.r = [0] * n
    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]
    def union(self, x, y):
        p_x = self.find(x)
        p_y = self.find(y)
        if p_x != p_y:
            if self.r[p_y] > self.r[p_x]:
                self.p[p_x] = p_y
            else:
                self.p[p_y] = p_x
                if self.r[p_y] == self.r[p_x]:
                    self.r[p_x] += 1
            return True
        return False
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n < 2:
            return 0
        
        def dist(p1, p2):
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        
        dic = {}
        for i in range(n):
            for j in range(i + 1, n):
                dic[(i, j)] = dist(points[i], points[j])
                
        o = sorted(list(dic.items()), key = lambda v: v[1])
        dsu = DSU(n)
        res = 0
        for pts, cost in o:
            p1, p2 = pts
            if dsu.union(p1, p2):
                res += cost
        
        return res
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n == 1:
            return 0
        dic = {}
        for i in range(n - 1):
            x1, y1 = points[i]
            for j in range(i + 1, n):
                x2, y2 = points[j]
                dist = abs(x1 - x2) + abs(y1 - y2)
                dic[(i, j)] = dist
        
        root = [i for i in range(n)]
        
        def find(n):
            if root[n] != n:
                root[n] = find(root[n])
            return root[n]
        
        def union(x, y):
            s1 = find(x)
            s2 = find(y)
            if s1 != s2:
                root[s2] = root[s1]
                return 1
            return 0
                
        dic_sorted = sorted(list(dic.items()), key=lambda x: x[1])
        res = 0
        for item in dic_sorted:
            x, y = item[0]
            dist = item[1]
            if union(x, y) == 1:
                res += dist
        return res
            
                
                
        
                    
                
        
        
        
                
                
                
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def dist(u, v):
            x, y = points[u]
            x2, y2 = points[v]
            return abs(x - x2) + abs(y - y2)
        
        n = len(points)
        visited = [False] * (n)
        pq = [(0, 0)]
        ans = 0
        while pq:
            cost, u = heappop(pq)
            if visited[u]: continue
            visited[u] = True
            ans += cost
            for v in range(n):
                if visited[v]: continue
                heappush(pq, (dist(u, v), v))
                
        return ans


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        dist = []
        for i in range(len(points) - 1):
            for j in range(i + 1, len(points)):
                d = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                dist.append([d, i, j])
        dist.sort()

        graph = {i: set() for i in range(len(points))}

        def has_cycle(node, prev, parent):
            if node in prev:
                return True
            prev.add(node)
            for next_node in graph[node]:
                if next_node != parent and next_node in prev:
                    return True
                if next_node != parent and has_cycle(next_node, prev, node):
                    return True
            return False

        cost = 0
        n_edge = 0
        for d, i, j in dist:
            if n_edge == len(points) - 1:
                break
            graph[i].add(j)
            graph[j].add(i)
            if (not has_cycle(i, set(), None)) and (not has_cycle(j, set(), None)):
                n_edge += 1
                cost += d
            else:
                graph[i].remove(j)
                graph[j].remove(i)

        return cost


#minima spanning tree
#greedy add min edge and check cycle
#union group to check cycly

import heapq

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def distance(points, i, j) -> int:
            return abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
        
        def getGroup(group, x):
            if group[x] == x: return x
            group[x] = getGroup(group, group[x])
            #print(\"x = {}, group[x] = {}\".format(x, group[x]))
            return group[x]
        
        def isCycle(group, cur):
            g1 = getGroup(group, cur[1])
            g2 = getGroup(group, cur[2])
            #print(\" is Cycle ? g1 = {}, g2 = {}\".format(g1,g2))
            return g1 == g2
        
        def unio(group, cur):
            g1 = getGroup(group, cur[1])
            g2 = getGroup(group, cur[2])
            group[g2] = g1
        
        pq, group = [], []
        n = len(points)
        for i in range(n):
            group.append(i)
            for j in range(i+1, n):
                dis = distance(points, i, j)
                heapq.heappush(pq, (dis, i, j))
                
        #print([heappop(pq) for i in range(len(pq))])
        #print(\"group = \" + str(group))
        count, rtn = 0, 0        
        while count < n-1 :
            cur = heapq.heappop(pq)
            #print(cur)
            
            if not isCycle(group, cur): 
             #   print(\"{} and {}\".format(cur[1], cur[2]))
                unio(group, cur)
                rtn += cur[0]
                count += 1
            
        
        
        return rtn;
    
                    


class UnionFind:
    def __init__(self, n):
        self.parent = collections.defaultdict(int)
        for i in range(1, n + 1):
            self.parent[i] = i

    def find(self, i):
        if i != self.parent[i]:
            self.parent[i] = self.find(self.parent[i])
        return self.parent[i]

    def union(self, u, v):
        u_parent, v_parent = self.find(u), self.find(v)
        if u_parent == v_parent: return False
        self.parent[u_parent] = v_parent
        return True

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        pq = list()
        heapq.heapify(pq)
        for i in range(n - 1):
            for j in range(i+1, n):
                # get distance
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                heapq.heappush(pq, (dist, i, j))
        res = 0
        uf = UnionFind(n)
        while pq:
            cost, a, b = heapq.heappop(pq)
            if uf.find(a) != uf.find(b):
                uf.union(a, b)
                res += cost
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)

        edges = []
        for i in range(n - 1):
            for j in range(i + 1, n):
                u, v = points[i]
                p, q = points[j]
                w = abs(u - p) + abs(v - q)
                edges.append([w, i, j])

        path = {u:u for u in range(n)}

        def find(u: int) -> int:
            if path[u] != u:
                path[u] = find(path[u])
            return path[u]

        def union(u: int, v: int) -> bool:
            i, j = find(u), find(v)
            if i == j: return False
            if j > i:
                i, j = j, i
            path[j] = i
            return True

        costs = 0
        edges.sort()
        for w, u, v in edges:
            if find(u) != find(v):
                costs += w
                union(u, v)
        return costs


class Solution:
    def minCostConnectPoints(self, A: List[List[int]]) -> int:
        def distance(a, b):
            return abs(a[0] - b[0]) + abs(a[1] - b[1])
        dic = {}
        def find(i):
            dic.setdefault(i, i)
            if dic[i] != i:
                dic[i] = find(dic[i])
            return dic[i]
        def union(i, j):
            fi, fj = find(i), find(j)
            if fi != fj:
                dic[fi] = fj
                return 1
            return 0
        dis = []
        n = len(A)
        for i in range(n):
            for j in range(i + 1, n):
                d = distance(A[i], A[j])
                dis.append([d, i, j])
        dis = sorted(dis)
        ret, ct = 0, 0
        for d, i, j in dis:
            if union(i, j):
                ret += d
                ct += 1
                if ct == n: break
        return ret

class Union_Find:
    def __init__(self, n):
        self.father = {i:i for i in range(n)}
        self.count = n
        # 可以查看 某一个node 有几个联通
        self.rank = [1] * n

    def find(self, x):
        if self.father[x] == x:
            return x
        self.father[x] = self.find(self.father[x])
        return self.father[x]

    def union(self, x, y):
        if self.rank[x] < self.rank[y]:
            x, y = y, x
        self.father[y] = x
        self.rank[x] += self.rank[y]
        self.count -= 1

    def find_union(self, x, y):
        father_x, father_y = self.find(x), self.find(y)
        if father_x != father_y:
            self.union(father_x, father_y)
            # 表示，如果本来不是联通 return true
            return True
        return False
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        mst = collections.defaultdict(set)
        edges = []
        n = len(points)
        graph = collections.defaultdict(list)
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                if i == j:
                    continue
                cost = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((cost, i, j))
        uf = Union_Find(n)
        heapq.heapify(edges)
        result = 0
        while edges:
            cost, frm, to = heapq.heappop(edges)
            if uf.find_union(frm, to):
                result += cost
                print((frm,to))
        return result
                
                
                
            
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        def dist(a, b):
            return (abs(a[0]-b[0]) + abs(a[1]-b[1]))
        
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                edges.append([dist(points[i], points[j]), i, j])
        edges.sort()
        st = set()
        ans = 0
        
        
        root_ = [i for i in range(len(points))]
        comp = [1 for i in range(len(points))]
        
        def root(i):
            while root_[i] != i:
                i = root_[i]
            return i
        
        def union(i, j):
            if root(i) == root(j):
                return 
            else:
                rooti = root(i)
                rootj = root(j)
                
                if comp[rooti] > comp[rootj]:
                    root_[rootj] = rooti
                    comp[rooti] += comp[rootj]
                else:
                    root_[rooti] = rootj
                    comp[rootj] += comp[rooti]
                    
                
        
        
        
        for i in edges:
            if root(i[1]) == root(i[2]):
                continue                
            else:
                union(i[1], i[2])
                ans += i[0]
        return ans

import heapq

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) < 1:
          return 0
        def dist(point1, point2):
          return abs(point1[0] - point2[0]) + abs(point1[1] - point2[1])
#         mat = []
#         for x, point1 in enumerate(points):
#           mat.append([])
#           for y, point2 in enumerate(points):
#             if x == y:
#               dis = float('inf') 
#             else:
#               dis = abs(point1[0] - point2[0]) + abs(point1[1] - point2[1])
#             mat[-1].append(dis)
        
        
        heap = []
        connected = set([0])
        for i, point in enumerate(points):
          if i == 0:
            continue
          heapq.heappush(
            heap,
            (
              dist(point, points[0]),
              i,
              0,
            )
          )
        res = 0
        while len(connected) != len(points):
          dis, p, f = heapq.heappop(heap)
          if p not in connected:
            res += dis
            connected.add(p)
            
          for i, point in enumerate(points):
            if i == p or i in connected:
              continue
            heapq.heappush(
              heap,
              (
                dist(point, points[p]),
                i,
                p,
              )
            )
        return res

import heapq
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n=len(points)
        hq,d,s=[(0,0)],[1]*n,0
        while hq:
            t,i=heapq.heappop(hq)
            if d[i]:
                s+=t
                d[i]=0
                for j in range(n):
                    if d[j]:
                        heapq.heappush(hq,(abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1]),j))
        return s

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        n = len(points)
        
        def dist(i, j):
            return abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
        
        heap = []
        for i in range(n - 1):
            for j in range(i + 1, n):
                heap.append((dist(i, j), i, j))
        heapq.heapify(heap)
        
        def find(i):
            if p[i] != i:
                p[i] = find(p[i])
            return p[i]
        
        def union(i, j):
            p[find(i)] = find(j)
        
        p = list(range(n))
        
        num_edges = 0
        res = 0
        while heap and num_edges < n:
            (d, i, j) = heapq.heappop(heap)
            
            if find(i) == find(j):
                continue
            
            union(i, j)
            num_edges += 1
            
            res += d
            
        return res
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        hq = []
        parent = len(points)*[0]
        cnt = len(points)*[0]
        for i in range(len(points)):
            parent[i]=i
            
        for i in range(len(points)-1):
            for j in range(i+1, len(points)):
                dist = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                heappush(hq, [dist, i, j])
        visited = {}
        ans = 0
        
        def find_parent(i):
            if(parent[i]==i):
                return i
            else:
                x = find_parent(parent[i])
                parent[i]=x
                return x
            
        def update_parent(i,j):
            x = find_parent(i)
            y = find_parent(j)
            if(cnt[x]<cnt[y]):
                parent[x]=y
                cnt[y]+=1
            else:
                parent[y]=x
                cnt[x]+=1
            
        while(len(hq)!=0):
            ce = heappop(hq)
            if find_parent(ce[1]) != find_parent(ce[2]):
                ans+=ce[0]
                update_parent(ce[1], ce[2])
        return ans
                


class Solution:
    def distance(self, p1, p2):
        return abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
    
    def build_graph(self, points):
        res = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                res.append([i, j, self.distance(points[i], points[j])])
        return res
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        connections = self.build_graph(points)        
        connections.sort(key=lambda x:x[2])
        parents = [i for i in range(len(points))]
        
        def find(node):
            parent = parents[node]
            while node != parent:
                node = parent
                parent = parents[node]
            return node
    
        cost = 0    

        for edge in connections:
            node1 = edge[0]
            node2 = edge[1]
            curr_cost = edge[2]

            if find(node1) != find(node2):
                parents[find(node2)] = find(node1)
                cost += curr_cost            

        return cost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # try minimum spanning treee
        
        to_visit = set(range(1, len(points)))
        pq = [(abs(points[0][0] - points[x][0]) + abs(points[0][1] - points[x][1]), 0, x) for x in range(1, len(points))]
        heapq.heapify(pq)
        ans = 0
        while pq:
            cost, frm, to = heapq.heappop(pq)
            if to in to_visit:
                to_visit.remove(to)
                ans += cost
                for nei in to_visit:
                    x, y = points[nei]
                    heapq.heappush(pq, (abs(x-points[to][0]) + abs(y-points[to][1]), to, nei))

        return ans
        
        
        
            
            



class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def distance(point1,point2):
            return abs(point1[0]-point2[0])+abs(point1[1]-point2[1])
        
        n = len(points)
        edges = []
        
        for i in range(n):
            for j in range(i+1,n):
                
                edges.append([distance(points[i],points[j]),i,j])
        
        edges.sort()
        
        p = [i for i in range(n)]
        
        def find(x):
            if p[x]!=x:
                p[x]=find(p[x])
            return p[x]
        def union(x,y):
            px = find(x)
            py = find(y)
            
            if px==py:
                return True
            
            else:
                p[px]=p[py]
        res = 0
        for edge in edges:
            d,x,y = edge
            if union(x,y):
                continue
            else:
                res+=d
        return res
            
            


class Solution:
    def manhattan_distance(self,a,b):
        return abs(a[0]-b[0])+abs(a[1]-b[1])
    
    def find(self,x):
        while x in self.parent:
            while self.parent[x] in self.parent:
                self.parent[x] = self.parent[self.parent[x]]
            x = self.parent[x]
        return x
            
        
        
    def union(self,x,y):
        x_find=self.find(x)
        y_find=self.find(y)
        if(x_find!=y_find):
            self.parent[x_find]=y_find
            return True
        
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        self.parent={}
        ls=[]
        for i in range(len(points)):
            for j in range(i+1,len(points)):
                ls.append([self.manhattan_distance(points[i],points[j]),i,j])
        # print(ls)
        ls=sorted(ls,key=lambda x:x[0])
        # print(ls)
        
        ans=0
        for i in range(len(ls)):
            if(self.union(ls[i][1],ls[i][2])):
                ans+=ls[i][0]
            # print(self.parent)
        return ans
        
                
        
        



class UnionFind:
    def __init__(self, n):
        self.groups = list(range(n))
        
    def find(self, i):
        if self.groups[i] == i:
            return i
        p = self.find(self.groups[i])
        self.groups[i] = p
        return p
    
    def union(self, i, j):
        pi = self.find(i) 
        pj = self.find(j)
        
        self.groups[pi] = pj
        
        

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        cost_array = []
        
        for i in range(len(points) - 1):
            for j in range(i+1, len(points)):
                weight = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                cost_array.append((weight, i, j))
        cost_array.sort()
        res = 0
        uf = UnionFind(len(points))
        for weight, i, j in cost_array:
            if uf.find(i) == uf.find(j):
                continue
            uf.union(i, j)
            res += weight
        return res
        
        
        
        
                
                
                


from heapq import heappush, heappop

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        dists = [[float('inf')] * n for _ in range(n)]
        for idx1, point1 in enumerate(points):
            for idx2, point2 in enumerate(points):
                if idx1 != idx2:
                    manhattan = abs(point1[0] - point2[0]) + abs(point1[1] - point2[1])
                    dists[idx1][idx2] = manhattan
                    dists[idx2][idx1] = manhattan
        
        res = 0
        nearest = [float('inf')] * n
        visited = set()
        h = [(0, 0)]
        while h and len(visited) < n:
            last_dist, last_pt = heappop(h)
            visited.add(last_pt)
            nearest[last_pt] = min(last_dist, nearest[last_pt])
            for neigh_pt, neigh_dist in enumerate(dists[last_pt]):
                if neigh_pt not in visited and neigh_dist < nearest[neigh_pt]:
                    heappush(h, (neigh_dist, neigh_pt))
            
        return sum(nearest)

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)

        edges = []
        for i in range(n - 1):
            for j in range(i + 1, n):
                u, v = points[i]
                p, q = points[j]
                w = abs(u - p) + abs(v - q)
                edges.append([w, i, j])

        path = [u for u in range(n)]

        def find(u: int) -> int:
            if path[u] != u:
                path[u] = find(path[u])
            return path[u]

        def union(u: int, v: int) -> None:
            i, j = find(u), find(v)
            if i != j:
                if j > i:
                    i, j = j, i
                path[j] = i

        costs = 0
        edges.sort()
        for w, u, v in edges:
            if find(u) != find(v):
                costs += w
                union(u, v)
        return costs


class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def __lt__(self, other):
        return [self.x, self.y] < [other.x, other.y]
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        points = [Point(x, y) for x, y in points]
        edges = []
        
        def getDistance(a, b):
            return abs(a.x - b.x) + abs(a.y - b.y)
        visited = set()
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                u, v = points[i], points[j]
                edges.append((getDistance(u, v), u, v))

        edges.sort(reverse=True)
        self.parent = {p : p for p in points}
        self.size = {p : 1 for p in points}
        components = len(points)
        
        total_cost = 0
        while components > 1 and edges:
            d, u, v = edges.pop()
            if self.union(u, v):
                total_cost += d
                components -= 1
        return total_cost
        
                
    def union(self, a, b):
        root_a = self.find(a)
        root_b = self.find(b)
        if root_a != root_b:
            if self.size[root_a] <= self.size[root_b]:
                self.parent[root_a] = root_b
                self.size[root_b] += self.size[root_a]
            else:
                self.parent[root_b] = root_a
                self.size[root_a] += self.size[root_b]
            return True
        return False
            
    def find(self, a):
        curr = a
        while self.parent[curr] != curr:
            curr = self.parent[curr]
        root, curr = curr, a
        while self.parent[curr] != curr:
            self.parent[curr], curr = root, self.parent[curr]
        return root

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def dist(p1, p2):
            x1, y1 = p1
            x2, y2 = p2
            return abs(x1-x2) + abs(y1-y2)
        
        import collections
        import heapq
        
        edges = []
        #G = collections.defaultdict(dict)
        for i in range(len(points)):
            for j in range(len(points)):
                if i != j:
                    edges.append([i, j, dist(points[i], points[j])])
        #print(\"eges is \", edges)            

        def primLazy(edges, n): # n nodes from 0 to n-1

            def visit(v):
                included[v] = True
                for neighbor in G[v]:
                    if not included[neighbor]:
                        heapq.heappush(pq, [G[v][neighbor], v, neighbor])

            G = collections.defaultdict(dict)
            for v, w, weight in edges:
                G[v][w] = weight
                G[w][v] = weight
    
            included =[False for i in range(n)] # vertices that are in the tree, Sedgewick uses marked
            mst = [] # edges already added to the spanning tree
            pq = [] # edges that are crossing from included vertices to not, and ineligible edges
            visit(points[0]) # start with edge 0
            d = 0
            while pq:
                dist, v, w = heapq.heappop(pq)
                if included[v] and included[w]:
                    continue
                mst.append([v,w])
                d += G[v][w]
                if not included[v]:
                    visit(v)
                if not included[w]:
                    visit(w)
            return mst
        
        def kruskalSize(edges, n): # edges should be of form [v, w, weight]

            parent = [i for i in range(n)] # sets up default parents for union find
            sz = [1 for i in range(n)] # creates size for each group, num of items

            def find(i):
                while i != parent[i]:
                    i = parent[i]
                return i

            def union(x,y):
                rx, ry = find(x), find(y)
                if rx == ry:
                    return
                if sz[rx] < sz[ry]:
                    parent[rx] = ry
                    sz[ry] += sz[rx]
                else:
                    parent[ry] = rx
                    sz[rx] += sz[ry]

            mst = []
            d = 0
            edges = sorted(edges, key = lambda x: x[2])
            for v, w, weight in edges:
                if find(v) != find(w):
                    mst.append([v,w])
                    #print(\"just added edge \",v,w,weight)
                    d += weight
                    union(v,w)
            return d

        
        return kruskalSize(edges, len(points))
                    


from collections import defaultdict
class Solution:
    def find(self, parent, i): 
        if parent[i] == i: 
            return i 
        return self.find(parent, parent[i]) 
    
    def union(self, parent, rank, x, y): 
        xroot = self.find(parent, x) 
        yroot = self.find(parent, y) 
        if rank[xroot] < rank[yroot]: 
            parent[xroot] = yroot 
        elif rank[xroot] > rank[yroot]: 
            parent[yroot] = xroot 
        else : 
            parent[yroot] = xroot 
            rank[xroot] += 1
            
    def KruskalMST(self): 
        result =[] 
        i = 0 
        e = 0  
        self.graph =  sorted(self.graph,key=lambda item: item[2]) 
        parent = [] ; rank = [] 
        for node in range(self.V): 
            parent.append(node) 
            rank.append(0) 
        while e < self.V -1 : 
            u,v,w =  self.graph[i] 
            i = i + 1
            x = self.find(parent, u) 
            y = self.find(parent ,v) 
            if x != y: 
                e = e + 1     
                result.append([u,v,w]) 
                self.union(parent, rank, x, y)
        summ = 0
        for u,v,weight  in result: 
            summ += weight
        return summ
            
            
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        self.V = len(points)
        # [0 for i in range(len(points))] for i in range(len(points))
        self.graph = [  ]
        for i in range(len(points)):
            for j in range(len(points)):
                md = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1])
                self.graph.append([i,j,md]) 
        return self.KruskalMST()

class DisjointSet():
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.rank = [1]*n 

    def find(self, x):
        if self.parent[x] == x: return x 
        return self.find(self.parent[x])

    def union(self, x, y):
        px = self.find(x)
        py = self.find(y)
        if px == py: return
        if self.rank[px] > self.rank[py]:
            self.parent[py] = px 
            self.rank[px] += self.rank[py] 
        else: 
            self.parent[px] = py 
            self.rank[py] += self.rank[px]
    

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        def ManhattanDistance(p1,p2):
            x1,y1 = p1; 
            x2,y2 = p2;
            return abs(x2-x1)+abs(y2-y1)

        edges = [(ManhattanDistance(points[i], points[j]),i,j) for i in range(n) for j in range(i+1, n)]
        edges.sort()

        graph = DisjointSet(n)
        ans = 0
        for cost, u, v in edges:
            if graph.find(u) != graph.find(v): 
                graph.union(u,v)
                ans += cost 

        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        params = {}
        for x, i in enumerate(points):
            for j in points[x+1:]:
                s = str(i[0]) + \" \" + str(i[1]) + \" \" + str(j[0]) + \" \" + str(j[1])
                params[s] = abs(i[0]-j[0])+abs(i[1]-j[1])
        d = {k: v for k, v in sorted(params.items(), key=lambda item: item[1])}
        ds = []
        vl = {}
        v = 0
        for i in d:
            ln1, rn1, ln2, rn2 = i.split()
            v1 = -1
            v2 = -1
            for y, j in enumerate(ds):
                if ln1+\" \"+rn1 in j:
                    v1 = y
                if ln2+\" \"+rn2 in j:
                    v2 = y
            if v1 < 0 and v2 < 0:
                ds.append({ln1+\" \" +rn1, ln2+\" \" +rn2})
            elif v1 == v2:
                continue
            elif v1 < 0 and v2 >= 0:
                ds[v2] = ds[v2].union({ln1+\" \" +rn1})
                vl[ln1+\" \" +rn1] = True
            elif v1 >= 0 and v2 < 0:
                ds[v1] = ds[v1].union({ln2+\" \" +rn2})
                vl[ln2+\" \" +rn2] = True
            elif v1 != v2:
                n = ds[v1].union(ds[v2])
                if v2 > v1:
                    ds.pop(v2)
                    ds.pop(v1)
                else:
                    ds.pop(v1)
                    ds.pop(v2)
                ds.append(n)
            v += d[i]
            if len(ds) == 1 and len(ds[0]) == len(points):
                return v
        return v
        
                
                

class DSU:
    
    def __init__(self, a):
        self.par = {x:x for x in a}
    
    def merge(self, u, v):
        rootu = self.find(u)
        rootv = self.find(v)
        
        if rootu == rootv:
            return False
        
        self.par[rootv] = rootu
        return True
    
    def find(self, u):
        if self.par[u] != u:
            self.par[u] = self.find(self.par[u])
        return self.par[u]

class Solution:
    def minCostConnectPoints(self, a: List[List[int]]) -> int:
        
        def manhattan_dist(u, v):
            return abs(u[0] - v[0]) + abs(u[1] - v[1])
        
        n = len(a)
        
        a = [tuple(x) for x in a]
        
        dsu = DSU(a)
        
        # [u,v,c]
        edges = []
        
        for u,v in combinations(a, 2):
            edges.append((u, v, manhattan_dist(u, v)))
        
        edges.sort(key=lambda x: x[2])
        
        ret = 0
        
        for u,v,c in edges:
            if dsu.merge(u,v):
                ret += c
                
        return ret

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        import heapq
        
        HQ = []
        
        heapq.heapify(HQ)
        
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                dist = abs(points[j][0] - points[i][0]) + abs(points[j][1] - points[i][1])
                heapq.heappush(HQ, (dist, i, j))
        
        G = list(range(len(points)))
        
        def find(x):
            if G[x] != x:
                G[x] = find(G[x])
            return G[x]
        
        def union(x, y):
            x, y = find(x), find(y)
            if x == y:
                return False
            G[x] = y
            return True
        
        res = 0
        while HQ:
            curdist, curi, curj = heapq.heappop(HQ)
            if union(curi, curj):
                res += curdist
        
        return res

import heapq

class Solution:
  def minCostConnectPoints(self, points: List[List[int]]) -> int:
    n = len(points)
    mst_nodes = [0 for i in range(n)]
    #mst_edges = set() # (int,int)
    h = []  # heap of edges connected to MST (distance, source, dest)
    man_dist = lambda i,j: abs( points[i][0] - points[j][0] ) + abs( points[i][1] - points[j][1] )
    
    mst_nodes[0] = 1
    for p in range(1,n):
      h.append( (man_dist(0,p),0,p) )
    heapq.heapify(h)

    tot_dist = 0
    while h:
      dist, src_node, dst_node = heapq.heappop(h)
      if mst_nodes[dst_node]:
        continue
      tot_dist += dist
      mst_nodes[dst_node] = 1
      for next_dst in range(n):
        if mst_nodes[next_dst]==0:
          heapq.heappush( h, ((man_dist(dst_node,next_dst),dst_node,next_dst)) )
      pass

    return tot_dist

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                p1 = points[i]
                p2 = points[j]
                l = abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
                edges.append((l, tuple(p1), tuple(p2)))
                
                
        trees = []
        for point in points:
            a = set()
            a.add(tuple(point))
            trees.append(a)
        
        t1 = -1
        t2 = -1
        tot = 0
        for e in sorted(edges):
            l, p1, p2 = e
            for i, tree in enumerate(trees):
                if p1 in tree:
                    t1 = i
                    break
            for i, tree in enumerate(trees):
                if p2 in tree:
                    t2 = i
                    break
                    
            if t1 != t2:
                tot += l
                trees[t1].update(trees[t2])
                del trees[t2]
                
            
        return tot

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points)<=1:return 0
        ans=0
        par={}
        def find(x):
            if x not in par:return x
            res=find(par[x])
            par[x]=res
            return res
        def union(a,b):
            n1=find(a)
            n2=find(b)
            if n1!=n2:
                if n1<=n2:
                    par[n2]=n1
                else:
                    par[n1]=n2
                return True
            else:return False
        arr=[]
        for i in range(len(points)):
##            _min=10e9
##            ix=-1
            for j in range(i+1,len(points)):
                n=abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                arr.append((n,(i,j)))
##        print(ans)
##        arr=list(arr)
        arr.sort()
        for x in arr:
            i=x[1][0]
            j=x[1][1]
            if union(i,j):ans+=x[0]

##            n1=find(i)
##            n2=find(j)
##            if n1!=n2:
##                if n1<n2:
##                    par[n2]=n1
##                else:
##                    par[n1]=n2
##                ans+=x[0]
        return ans        

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def calculate_distance(x1, y1, x2, y2):
            return abs(x1 - x2) + abs(y1 - y2)

        res = 0
        n = len(points)
        visited = set()
        d = defaultdict(list)

        for i in range(n):
            for j in range(n):
                if i != j:
                    d[i].append((calculate_distance(points[i][0], points[i][1], points[j][0], points[j][1]), j))
                    d[j].append((calculate_distance(points[i][0], points[i][1], points[j][0], points[j][1]), i))

        heap = d[0]
        heapq.heapify(heap)
        cnt = 1
        visited.add(0)

        while heap:
            dist, j = heapq.heappop(heap)

            if j not in visited:
                cnt += 1
                visited.add(j)
                res += dist
                for r in d[j]:
                    heapq.heappush(heap, r)
            if cnt >= n: break   
        
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n, curr, ans = len(points), 0, 0
        if n == 1: return 0
        dist = [math.inf] * n
        visited = set()
        for i in range(n - 1):
            x, y = points[curr]
            visited.add(curr)
            for j, (u, v) in enumerate(points):
                if j in visited: continue
                dist[j] = min(dist[j], abs(u - x) + abs(v - y))
            delta, curr = min((d, j) for j, d in enumerate(dist))
            dist[curr] = math.inf
            ans += delta
        return ans


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        heap = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                x1, y1 = points[i]
                x2, y2 = points[j]
            
                dist = abs(x1-x2) + abs(y1-y2)
                heap.append((dist, i, j))
        
        heapify(heap)
        uf = UnionFind(len(points))
        res = 0
        
        while heap:
            dist, x, y = heappop(heap)
            if uf.union(x, y):
                res += dist
                
        return res
    
class UnionFind:
    def __init__(self, n):
        self.parent = list(range(n))
        self.rank = [0]*n
        
    def union(self, x, y):
        root_x = self.find(x)
        root_y = self.find(y)
        
        if root_x == root_y:
            return False
        
        if self.rank[root_x] > self.rank[root_y]:
            self.parent[root_y] = root_x
        
        else:
            self.parent[root_x] = root_y
            if self.rank[root_x] == self.rank[root_y]:
                self.rank[root_y] += 1
        
        return True
    
    def find(self, x):
        while x != self.parent[x]:
            # self.parent[x] = self.parent[self.parent[x]]
            x = self.parent[x]
        return x
                
        
        
        
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        l=len(points)
        c=collections.defaultdict(list)
        for i in range(l-1):
            for j in range(i+1,l):
                d=abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                c[d].append((i,j))
        tocons=list(sorted(c.keys()))
        #print(tocons)
        def isCyclicUtil(v,visited,parent,graph):
            visited[v]=True
            for i in graph[v]:
                if visited[i]==False:
                    if isCyclicUtil(i,visited,v,graph):
                        return True
                elif parent!=i:
                    return True
            return False
            
        def checkloop(y,connected,edges):
            if y[0] not in connected or y[1] not in connected:
                return True
            root=y[0]
            
            visited=[False]*(l)
            
            graph=collections.defaultdict(list)
            graph[y[0]]=[y[1]]
            graph[y[1]]=[y[0]]
            for x in edges:
                graph[x[0]].append(x[1])
                graph[x[1]].append(x[0])
            for i,x in enumerate(connected):
                if visited[x]==False:
                    if isCyclicUtil(x,visited,-1,graph)==True:
                        return False
            '''
            seq=[root]
            seen=set()
            seen.add(root)
            while seq:
                v=seq.pop()
                for w in graph[v]:
                    if w not in seen:
                        if isCyclicUtil(w,visited,v,graph):
                            return False
                        seq.append(w)
            '''
            return True
            
        
            
        edges=[]
        count=0
        cost=0
        connected=set()
        for x in tocons:
            for y in c[x]:
                #print(y,x,connected,count)
                
                if checkloop(y, connected, edges):
                    count+=1
                    cost+=x
                    connected.add(y[0])
                    connected.add(y[1])
                    edges.append(y)
                if count==l-1:
                    return cost
        return 0

class Solution:
    def minCostConnectPoints(self, points) -> int:
        p_set = [i for i in range(len(points))]
        
        def father(i):
            while p_set[i] != i:
                i = p_set[i]
            return i
        if len(points) == 1:
            return 0
        
        edge = {}
        edgelist = []
        res = 0
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                le = 0
                le += abs(points[i][1]-points[j][1])
                le += abs(points[i][0]-points[j][0])
                if le in edge:
                    edge[le].append((i, j))
                else:
                    edge[le] = [(i,j)]
                    edgelist.append(le)
        edgelist.sort()
        # print(edge)
        (i,j) = edge[edgelist[0]][0]
        res += edgelist[0]
        # print('add {}-{} length= {}'.format(i, j,edgelist[0]))
        p_set[j] = i
        for key in edgelist:
            # print('deal ', key)
            for (i, j) in edge[key]:
                fi = father(i)
                fj = father(j)
                if fj != fi:
                    # print('add {}-{} length= {}'.format(i,j,key))
                    p_set[fj] = fi
                    # print(p_set)
                    res += key
        return res

class UnionFind:
    def __init__(self, n):
        self.parent=[i for i in range(n)]
        self.height=[0 for i in range(n)]
    def find(self,x):
        if self.parent[x]==x: return x
        result = self.find(self.parent[x])
        self.parent[x]=result
        return result
    def merge(self,x,y):
        rx=self.find(x)
        ry=self.find(y)
        if self.height[rx]>self.height[ry]:
            self.parent[ry]=rx
        elif self.height[rx]<self.height[ry]:
            self.parent[rx]=ry
        else:
            self.parent[rx]=ry
            self.height[rx]+=1
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n=len(points)
        edges=[]
        for i in range(n):
            for j in range(i+1,n):
                heappush(edges,(abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1]),i,j))
        uf=UnionFind(n)
        ans=0
        while edges:
            cost,va,vb=heappop(edges)
            if uf.find(va)==uf.find(vb):
                pass
            else:
                uf.merge(va,vb)
                ans+=cost
        return ans


from collections import Counter

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        points = [tuple(it) for it in points]
        ds = []
        for i1, p1 in enumerate(points):
            for p2 in points[i1+1:]:
                if p1 == p2:
                    continue
                dist = abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
                ds.append((dist, (p1, p2)))
        ds.sort()
        ps = [set([it]) for it in points]
        total = 0
        for cost, (p1, p2) in ds:
            s1 = [it for it in ps if p1 in it][0]
            s2 = [it for it in ps if p2 in it][0]
            if s1 is s2:
                continue
            total += cost
            s1 |= s2
            ps.remove(s2)
        return total

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points)<=1:return 0
        ans=0
        par={}
        def find(x):
            if x not in par:return x
            res=find(par[x])
            par[x]=res
            return res
        def union(a,b):
            n1=find(a)
            n2=find(b)
            if n1!=n2:
                if n1<=n2:
                    par[n2]=n1
                else:
                    par[n1]=n2
##                return True
##            else:return False
        arr=[]
        for i in range(len(points)):
##            _min=10e9
##            ix=-1
            for j in range(i+1,len(points)):
                n=abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                arr.append((n,(i,j)))
##        print(ans)
##        arr=list(arr)
        arr.sort()
        for x in arr:
            i=x[1][0]
            j=x[1][1]
##            if union(i,j):ans+=x[0]

            n1=find(i)
            n2=find(j)
            if n1!=n2:
                if n1<n2:
                    par[n2]=n1
                else:
                    par[n1]=n2
                ans+=x[0]
        return ans               

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points) <= 1:
            return 0
        visited = set()
        adj_list = defaultdict(list)
        cost = 0
        pq = []
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                first = points[i]
                second = points[j]
                adj_list[tuple(first)].append([abs(first[0] - second[0]) + abs(first[1] - second[1]), second])
                adj_list[tuple(second)].append([abs(first[0] - second[0]) + abs(first[1] - second[1]), first])

        pq = pq + adj_list[list(adj_list.keys())[0]]
        heapq.heapify(pq)
        visited.add(tuple(list(adj_list.keys())[0]))
        while len(visited) < len(adj_list):
            curr = heapq.heappop(pq)
            if tuple(curr[1]) not in visited:
                visited.add(tuple(curr[1]))
                for edge in adj_list[tuple(curr[1])]:
                    heapq.heappush(pq, edge)
                cost += curr[0]
        return cost

parent = 0
def find(i):
    nonlocal parent
    l1 = []
    while parent[i] != i:
        l1.append(i)
        i = parent[i]
    j = i
    for i in l1:
        parent[i] = j
    return j
    
    
    
def givedistance(a, b):
    return abs(a[0] - b[0]) + abs(a[1] - b[1])
class Solution:
    def minCostConnectPoints(self, l: List[List[int]]) -> int:
        nonlocal parent
        
        visited = {}
        
        l1 = []
        n = len(l)
        for i in range(n):
            for j in range(i + 1, n):
                l1.append([givedistance(l[i], l[j]), tuple(l[i]), tuple(l[j])])
                
        l1.sort()
        l1.reverse()

        ans = 0

        if n == 1:return 0
        
        d = {}
        ind = 0
        for i in l:
            d[tuple(i)] = ind
            ind += 1
        
        for i in range(len(l1)):
            l1[i][1] = d[l1[i][1]]
            l1[i][2] = d[l1[i][2]]
        parent = {}
        for i in l1:
            parent[i[1]] = i[1]
            parent[i[2]] = i[2]
        
        taken = 0
        while taken != n - 1:
            curr, i, j = l1.pop()
            
            p1 = find(i)
            p2 = find(j)
            
            if p1 != p2:
                parent[p1] = parent[p2]
                ans += curr
                taken += 1
        return ans
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n == 1:
            return 0
        
        parents = list(range(n))      
        
        def find(i):
            if parents[i] != i:
                parents[i] = find(parents[i])
            return parents[i]
            
        def union(i, j):
            p_i = find(i)
            p_j = find(j)
            if p_i != p_j:
                if p_i > p_j:
                    parents[p_j] = p_i
                else:
                    parents[p_i] = p_j     
                    
        heap = []
        for i in range(n):
            for j in range(i+1, n):
                heapq.heappush(heap, (self.distance(points[i], points[j]), i, j))
        
        res = 0
        while heap:
            dist, i, j = heapq.heappop(heap)
            if find(i) == find(j):
                continue
            union(i, j)
            res += dist
        
        return res
        
    def distance(self, p1, p2):
        return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])

parent = 0
def find(i):
    nonlocal parent

    while parent[i] != i:
        parent[i] = parent[parent[i]]
        i = parent[i]
    
    return i
    
    
def givedistance(a, b):return abs(a[0] - b[0]) + abs(a[1] - b[1])


class Solution:
    def minCostConnectPoints(self, l: List[List[int]]) -> int:
        nonlocal parent
        
        visited = {}
        
        l1 = []
        n = len(l)
        for i in range(n):
            for j in range(i + 1, n):
                l1.append([givedistance(l[i], l[j]), tuple(l[i]), tuple(l[j])])
                
        l1.sort()
        l1.reverse()

        ans = 0

        if n == 1:return 0
        
        d = {}
        ind = 0
        for i in l:
            d[tuple(i)] = ind
            ind += 1
        
        for i in range(len(l1)):
            l1[i][1] = d[l1[i][1]]
            l1[i][2] = d[l1[i][2]]
        parent = {}
        for i in l1:
            parent[i[1]] = i[1]
            parent[i[2]] = i[2]
        
        taken = 0
        while taken != n - 1:
            curr, i, j = l1.pop()

            p1 = find(i)
            p2 = find(j)

            if p1 != p2:
                parent[p1] = parent[p2]
                ans += curr
                taken += 1

        return ans

import heapq
class DSU:
    def __init__(self, n):
        self.p = list(range(n))
    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]
    def union(self, x, y):
        p_x = self.find(x)
        p_y = self.find(y)
        if p_x != p_y:
            self.p[p_x] = p_y
            return True
        return False
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n < 2:
            return 0
        
        def dist(p1, p2):
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        
        edges = []
        for i in range(n):
            for j in range(i + 1, n):
                edges.append([dist(points[i], points[j]), i, j])
                
        heapq.heapify(edges)
        dsu = DSU(n)
        res = 0
        while edges:
            cost, p1, p2 = heapq.heappop(edges)
            if dsu.union(p1, p2):
                res += cost
        
        return res
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        pointSet = set()
        CostHeap = []
        
        for i in range(len(points)):
            pointSet.add(i)
            for j in range(i+1, len(points)):
                heapq.heappush(CostHeap, [abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1]), i, j])
        
        parent = defaultdict(lambda: -1)
        def find(x):
            if parent[x] == -1:
                return x
            else:
                parent[x] = find(parent[x])
                return parent[x]
            
        COST = 0
        while CostHeap:
            node = heapq.heappop(CostHeap)
            cost,x,y = node
            u = find(x)
            v = find(y)
            if u != v:
                parent[u] = v               
                COST+=cost
        return COST
            


# class DSU:
#     def __init__(self, N):
#         self.parent = [i for i in range(N)]
#         self.rank = [0] * N
        
#     def find(self, x):
#         if self.parent[x] != x:
#             self.parent[x] = self.find(self.parent[x])
            
#         return self.parent[x]
    
#     def union(self, x, y):
#         xRoot = self.find(x)
#         yRoot = self.find(y)
        
#         if xRoot == yRoot:
#             return False
        
#         if self.rank[xRoot] > self.rank[yRoot]:
#             self.parent[yRoot] = xRoot
#         elif self.rank[yRoot] > self.rank[xRoot]:
#             self.parent[xRoot] = yRoot
#         else:
#             self.parent[yRoot] = xRoot
#             self.rank[xRoot] += 1
            
#         return True

# class Solution:
#     def minCostConnectPoints(self, points: List[List[int]]) -> int:
#         N = len(points)
#         pq = []
        
#         for i in range(N):
#             for j in range(i):
#                 x1, y1 = points[i]
#                 x2, y2 = points[j]
#                 dist = abs(x1 - x2) + abs(y1 - y2)
#                 heappush(pq, (dist, i, j))
                    
#         dsu = DSU(N)
#         edges = 0
#         cost = 0
        
#         while edges < N - 1:
#             dist, i, j = heappop(pq)
            
#             if dsu.union(i, j):
#                 cost += dist
#                 edges += 1
                
#         return cost
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        graph = defaultdict(list)
        
        for i in range(N):
            for j in range(N):
                if i != j:
                    x1, y1 = points[i]
                    x2, y2 = points[j]
                    dist = abs(x1 - x2) + abs(y1 - y2)
                    graph[i].append((j, dist))
                    graph[j].append((i, dist))
                    
        pq = [(0, 0)]
        visited = set()
        cost = 0
        
        while len(visited) < N:
            dist, node = heappop(pq)
            
            if node not in visited:
                visited.add(node)
                cost += dist
                
                for adj, dist in graph[node]:
                    if adj not in visited:
                        heappush(pq, (dist, adj))
                
        return cost

class Solution:
    class Union:
        def __init__(self):
            self.collection = {}
        
        def get_head(self, i):
            if i not in self.collection:
                return -1, 1
            while i in self.collection and self.collection[i][0] != i:
                i = self.collection[i][0]
            return self.collection[i]
                
        def add(self, i, j):
            head_i, cnt_i = self.get_head(i)
            head_j, cnt_j = self.get_head(j)
            
            if head_i == head_j and head_i != -1:
                return False
            
            head = head_i if cnt_i >= cnt_j else head_j
            cnt = cnt_i + cnt_j
            if head == -1:
                head = i

            self.collection[head_i] = (head, cnt)
            self.collection[head_j] = (head, cnt)
            self.collection[i] = (head, cnt)
            self.collection[j] = (head, cnt)
            return True
            
    from heapq import heappush, heappop
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        heap = []
        union = Solution.Union()
        total = 0
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                val = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                heappush(heap, (val, i, j))
                
        while heap:
            val, i, j = heappop(heap)
            x = union.add(i, j)
            if x:
                total += val
            
        return total

class UF:
  def __init__(self, n):
    self.parents = [i for i in range(n)]
    
  def find(self, x):
    if x != self.parents[x]:
      self.parents[x] = self.find(self.parents[x])
    
    return self.parents[x]
  
  def union(self, x, y):
    parent_x = self.find(x)
    parent_y = self.find(y)
    
    self.parents[parent_y] = parent_x
    
  def connected(self, y, x):
    return self.find(y) == self.find(x)
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def calculate_distance(x1, y1, x2, y2):
            return abs(x1 - x2) + abs(y1 - y2)
        
        n = len(points)
        uf = UF(n)
        res = 0
        
        p = []
        
        for i in range(n):
          for j in range(n):
            if i != j:
              p.append((i,j, calculate_distance(points[i][0], points[i][1], points[j][0], points[j][1])))
              
        p.sort(key = lambda x : x[2])
        
        for x, y, dist in p:
          if not uf.connected(x,y):
            uf.union(x,y)
            res += dist
        
        return res
        
        


class UnionFind:
    def __init__(self, N):
        self.par = list(range(N))
        self.sz = [1] * N

    def find(self, x):
        if self.par[x] != x:
            self.par[x] = self.find(self.par[x])
        return self.par[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        if xr == yr:
            return False
        if self.sz[xr] < self.sz[yr]:
            xr, yr = yr, xr
        self.par[yr] = xr
        self.sz[xr] += self.sz[yr]
        self.sz[yr] = self.sz[xr]
        return True

    def size(self, x):
        return self.sz[self.find(x)]
    
class Solution:
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n<=1:
            return 0
        distances = []
        db = dict()
        for i in range(n):
            x1,y1 = points[i]
            for j in range(i+1,n):
                x2,y2 = points[j]
                dis = (abs(x1-x2)+abs(y1-y2))
                distances.append( dis )

                if dis not in db:
                    db[dis] = []
                db[dis].append((i,j))
                
        
        heapq.heapify(distances)
        nodes = UnionFind(n)
        ret = []
        
        cost = 0
        while distances:
            # print(type(distances))
            # print(nodes)
            dis = heapq.heappop(distances)
            p1,p2 = db[dis].pop()
            if nodes.union(p1,p2):
                cost+=dis
        return cost


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        result = 0
        m = 0
        q = [(0, 0)]
        visited = [10 ** 9] * n
        while m < n:
            w, i = heapq.heappop(q)
            # print(j, i, w)
            if visited[i] < 0:
                continue
            visited[i] = -1
            for j in range(n):
                ww = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                if ww < visited[j]:
                    visited[j] = ww
                    heapq.heappush(q, (ww, j))
            m += 1
            result += w
        return result

class UF:
    @staticmethod
    def init(n):
        return [i for i in range(n)]
    
    @staticmethod
    def find(parents, i):
        if parents[i] != i:
            parents[i] = UF.find(parents, parents[i])
        return parents[i]
    
    @staticmethod
    def union(parents, i, j):
        parents[UF.find(parents, i)] = UF.find(parents, j)

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        distances = []
        
        n = len(points)
        for i in range(n):
            r1, c1 = points[i]
            for j in range(i+1, n):
                r2, c2 = points[j]
                distances.append([abs(r1-r2)+abs(c1-c2), i, j])
        distances.sort()
        #print(distances)

        res = 0
        parents = UF.init(n)
        for c, i, j in distances:
            if UF.find(parents, i) != UF.find(parents, j):
                UF.union(parents, i, j)
                res += c
            
        return res
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        if len(points)==1:
            return 0
        
        visited=[0]*(len(points))
        q=[]
        start=0
        for i in range(1,len(points)):
            dist=abs(points[i][0]-points[0][0])+abs(points[i][1]-points[0][1])
            q.append([dist,i])
            
        heapq.heapify(q)
        # print(q)
        visited[0]=1
        cost=0
        count=1
        while True:
            
            x=heapq.heappop(q)
            # print(x)
            if visited[x[1]]==0:
                cost=cost+x[0]
                visited[x[1]]=1
                count=count+1
            if count==len(points):
                return cost
            
            for i in range(len(points)):
                if visited[i]==0:
                    dist=abs(points[i][0]-points[x[1]][0])+abs(points[i][1]-points[x[1]][1])
                    heapq.heappush(q,[dist,i])
        
            
            
            
        
        
        
        
        
        
#         def dfs(index,visited,count):
#             if count==len(points):
#                 return 0
            
#             dist=float(\"inf\")
#             for i in range(len(points)):
#                 if visited[i]==0:
#                     visited[i]=1
#                     dist=min(dist,abs(points[i][0]-points[index][0])+abs(points[i][1]-points[index][1])+dfs(i,visited,count+1))
#                     visited[i]=0
#             visited[index]=0
#             return dist
#         visited=[0]*len(points)
#         visited[0]=1
#         x=dfs(0,visited,1)
#         return x
                    


class Solution:
    class Union:
        def __init__(self):
            self.collection = {}
        
        def get_head(self, i):
            if i not in self.collection:
                return -1, 1
            while i in self.collection and self.collection[i][0] != i:
                i = self.collection[i][0]
            return self.collection[i]
                
        def add(self, i, j):
            head_i, cnt_i = self.get_head(i)
            head_j, cnt_j = self.get_head(j)
            
            if head_i == head_j and head_i != -1:
                return False, cnt_i
            
            head = head_i if cnt_i >= cnt_j else head_j
            cnt = cnt_i + cnt_j
            if head == -1:
                head = i

            self.collection[head_i] = (head, cnt)
            self.collection[head_j] = (head, cnt)
            self.collection[i] = (head, cnt)
            self.collection[j] = (head, cnt)
            return True, cnt
            
    from heapq import heappush, heappop
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        heap = []
        union = Solution.Union()
        total = 0
        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                val = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                heappush(heap, (val, i, j))
                
        while heap:
            val, i, j = heappop(heap)
            added, cnt = union.add(i, j)
            if added:
                total += val
            #if cnt == len(points):
            #    break
            
        return total

from heapq import heappush, heappop

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        dists = [[float('inf')] * n for _ in range(n)]
        for idx1, point1 in enumerate(points):
            for idx2, point2 in enumerate(points):
                if idx1 != idx2:
                    manhattan = abs(point1[0] - point2[0]) + abs(point1[1] - point2[1])
                    dists[idx1][idx2] = manhattan
                    dists[idx2][idx1] = manhattan
        
        res = 0
        nearest = [float('inf')] * n
        visited = set()
        h = [(0, 0)]
        while h and len(visited) < n:
            last_dist, last_pt = heappop(h)
            visited.add(last_pt)
            nearest[last_pt] = min(last_dist, nearest[last_pt])
            for neigh_pt, neigh_dist in enumerate(dists[last_pt]):
                if neigh_pt not in visited:
                    heappush(h, (neigh_dist, neigh_pt))
            
        return sum(nearest)

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        
        def distance(p1, p2):
            return abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        
#         calculate all edges in this graph
        edges = []
        for i in range(len(points)):
            for j in range (i+1, len(points)):
                if i == j: continue
                edges.append([distance(points[i], points[j]), i, j])
        edges.sort()
        
        fathers = {p: p for p in range(len(points))}
        def find_father(p):
            while fathers[p] != fathers[fathers[p]]:
                fathers[p] = find_father(fathers[p])
            return fathers[p]
        
        result = 0
        for d, p1, p2 in edges:
            if find_father(p1) == find_father(p2):
                continue
            fathers[find_father(p2)] = find_father(p1)
            result += d
            
        return result
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        h = []
        visited = set()
        
        parent = [i for i in range(len(points))]
        rank = [0] * len(points)
        def find(i):
            if parent[i] == i:
                return i
            p = find(parent[i])
            parent[i] = p
            return p
        
        def union(a,b):
            pa, pb = find(a), find(b)
            if rank[pa]>rank[pb]:
                parent[pb] = pa
            elif rank[pb]>rank[pa]:
                parent[pa] = pb
            else:
                parent[pb] = pa
                rank[pa] +=1
        
            
        
        def dist(a,b):
            return abs(a[0]-b[0]) + abs(a[1]-b[1])
        
        for i in range(len(points)):
            for j in range(i):
                h.append((dist(points[i], points[j]), i,j))
        heapq.heapify(h)
        total = 0
        while h and len(visited) < len(points):
            dist, i,j = heapq.heappop(h)
            if find(i) != find(j):
                union(i,j)
                total +=dist

        return total
                
            


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        #prims
        g = collections.defaultdict(list)
        n = len(points)
        #create graph
        for i in range(n):
            for j in range(n):
                if i != j:
                    g[i].append((abs(points[j][0] - points[i][0]) +
                                 abs(points[j][1] - points[i][1]), j))

        heap = [(0, 0)]
        ans = 0
        visited = set()
        while heap:
            weight, to = heapq.heappop(heap)
            if to in visited:
                continue
            ans += weight
            visited.add(to)

            for cost, nei in g[to]:
                if nei not in visited:
                    heapq.heappush(heap, (cost, nei))

        return ans

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def getDistance(x1, y1, x2, y2):
            return abs(x1 - x2) + abs(y1 - y2)
        
        dist = defaultdict(list)
        for i in range(len(points)):
            curX, curY = points[i]
            d = []
            for j in range(len(points)):
                newX, newY = points[j]
                if newX == curX and newY == curY:
                    d.append((10 ** 20, j))
                else:
                    d.append((getDistance(curX, curY, newX, newY), j))
            # print(\"before\", d)
            heapq.heapify(d)
            # print(\"after\", d)
            dist[i] = d
        result = 0
        processed = set()
        processed.add(0)
        # print(dist)
        while len(processed) < len(points):
            possible = []
            for curNode in processed:
                curHeap = dist[curNode]
                while curHeap[0][1] in processed:
                    heapq.heappop(curHeap)
                possible.append(curHeap[0])
            index = -1
            minVal = float(\"inf\")
            for distance, ind in possible:
                if distance < minVal:
                    minVal = distance
                    index = ind
            processed.add(index)
            result += minVal
        return result
            
                
        
        
        
        
        
        
        
        
        
        # processed = set()
        # for i in range(len(points)):
        #     if len(processed) == 0:
        #         processed.add(i)
        #     else:
        #         curDistances = dist[i]
        #         for curDistance, index in curDistances:
        #             if index not in processed:
        #                 processed.add(index)
        #                 result += curDistance
        #                 print(curDistance)
        #                 break
        # return result

#Prim's algorithm
from collections import defaultdict
from heapq import *
class Solution:
    def minCostConnectPoints(self, points):
        graph = defaultdict(list)
        n = len(points)
        dist = lambda p0, p1: abs(p1[0] - p0[0]) + abs(p1[1] - p0[1])
        for u in range(n):
            for v in range(u + 1, n):
                w = dist(points[u], points[v])
                graph[u].append((v, w))
                graph[v].append((u, w))
        q = [(0, 0)]
        visited = set()
        res = 0
        while q:
            d, u = heappop(q)
            if u in visited:
                continue
            visited.add(u)
            res = res + d
            for v, w in graph[u]:
                if v not in visited:
                    heappush(q, (w, v))
        if len(visited) != n:
            return -1
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        heap = [(0, -1, 0)]
        seen = set()
        seen.add(-1)
        heapq.heapify(heap)
        cost = 0
        
        def calc_dist(a, b):
            return abs(a[0] - b[0]) + abs(a[1] - b[1])
        
        while len(seen) <= len(points):
            c, a, b = heapq.heappop(heap)
            if b in seen:
                continue
            seen.add(b)
            cost += c
            for j in range(len(points)):
                if j not in seen:
                    heapq.heappush(heap, (calc_dist(points[b], points[j]), b, j))
            
        return cost
                
            
            
                
            
        


class Solution:
    def find(self, uf, node):
        if node not in uf:
            uf[node] = node
            
        while node != uf[node]:
            node = uf[node]
            
        return node
            
    def union(self, uf, node1, node2):
        uf[self.find(uf, node1)] = self.find(uf, node2)

    def distance(self, point1, point2):
        return abs(point1[0]-point2[0]) + abs(point1[1]-point2[1])
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        cost = 0
        edges = []
        uf = {}
        
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                edges.append([i, j, self.distance(points[i], points[j])])
                
        edges = sorted(edges, key=lambda x: x[2])
        
        for edge in edges:
            point1 = edge[0]
            point2 = edge[1]
            edgeCost = edge[2]
            
            if self.find(uf, point1) != self.find(uf, point2):
                self.union(uf, point1, point2)
                cost += edgeCost
            
            # if len(uf) == len(points):
            #     break
                
        return cost


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        heap = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                x1, y1 = points[i]
                x2, y2 = points[j]
            
                dist = abs(x1-x2) + abs(y1-y2)
                heap.append((dist, i, j))
        
        heapify(heap)
        uf = UnionFind(len(points))
        res = 0
        
        while heap:
            dist, x, y = heappop(heap)
            if uf.union(x, y):
                res += dist
                
        return res
    
class UnionFind:
    def __init__(self, n):
        self.parent = list(range(n))
        self.rank = [0]*n
        
    def union(self, x, y):
        root_x = self.find(x)
        root_y = self.find(y)
        
        if root_x == root_y:
            return False
        
        
        if self.rank[root_x] > self.rank[root_y]:
            self.parent[root_y] = root_x
        
        else:
            self.parent[root_x] = root_y
            if self.rank[root_x] == self.rank[root_y]:
                self.rank[root_y] += 1
        
        return True
    
    def find(self, x):
        while x != self.parent[x]:
            self.parent[x] = self.parent[self.parent[x]]
            x = self.parent[x]
        return x
                
        
        
        
        


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

    def union(self, v1, v2):
        r1 = self.find(v1)
        r2 = self.find(v2)
        if r1 == r2:
            return

        s1 = self.size(r1)
        s2 = self.size(r2)

        # Weighted Union: to keep the height of sets as small as possible
        if s1 <= s2:
            self.parent[r1] = r2
            self.parent[r2] -= s1
        else:
            self.parent[r2] = r1
            self.parent[r1] -= s2
 
    def find(self, v):
        r = v
        while self.parent[r] >= 0:
            r = self.parent[r]

        # Path Compression: to keep the height of sets as small as possible
        while v != r:
            new_v = self.parent[v]
            self.parent[v] = r
            v = new_v

        return r
    
    def size(self, v):
        r = self.find(v)
        s = -self.parent[r]
        return s 

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        edges = []
        for u in range(n):
            for v in range(u+1, n):
                dist = abs(points[u][0]-points[v][0]) + abs(points[u][1]-points[v][1])
                edges.append([dist, u, v])

        res = 0
        uf = UnionFind(n)
        for e in sorted(edges):
            if uf.find(e[1]) != uf.find(e[2]):
                res += e[0]
                uf.union(e[1], e[2])
        return res
        
        


class UF:
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.size = [1 for i in range(n)]
        
    def find(self, a):
        while self.parent[a] != a:
            self.parent[a] = self.parent[self.parent[a]]
            a = self.parent[a]
        return a
    
    def isConnected(self, a, b):
        return self.find(a) == self.find(b)
    
    def union(self, a, b):
        parentA = self.find(a)
        parentB = self.find(b)
        if self.isConnected(a, b): 
            return
        if self.size[parentA] > self.size[parentB]:
            self.parent[parentB] = parentA
            self.size[parentA] += self.size[parentB]
        else:
            self.parent[parentA] = parentB
            self.size[parentB] += self.size[parentA]
        
        
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        edges = []
        n = len(points)
        for i in range(n):
            for j in range(i+1, n):
                manhattanDist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((manhattanDist, i ,j))
        edges.sort()
        res = 0
        uf = UF(n)
        for cost, i, j in edges:
            if not uf.isConnected(i, j):
                uf.union(i, j)
                res += cost
        return res


class DSU:
    def __init__(self, n):
        self.p = list(range(n))
    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]
    def union(self, x, y):
        p_x = self.find(x)
        p_y = self.find(y)
        if p_x != p_y:
            self.p[p_x] = p_y
            return True
        return False
    
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n < 2:
            return 0
        
        def dist(p1, p2):
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        
        edges = []
        for i in range(n):
            for j in range(i + 1, n):
                edges.append([(i, j), dist(points[i], points[j])])
                
        edges.sort(key = lambda v: v[1])
        dsu = DSU(n)
        res = 0
        for pts, cost in edges:
            p1, p2 = pts
            if dsu.union(p1, p2):
                res += cost
        
        return res
        


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        import heapq
        n = len(points)

        
        #find MST, can use krukals or prim's algo
        # pq = []
        # for i in range(n - 1):
        #     x1, y1 = points[i]
        #     for j in range(i + 1, n):
        #         x2, y2 = points[j]
        #         d = abs(x2 - x1) + abs(y2 - y1)
        #         pq.append((d, i, j))
                
        pq = [(0, 0)]
        seen = [False] * n
        totalCost = 0
        while pq:
            cost, currPoint = heapq.heappop(pq)
            if seen[currPoint]: continue
            seen[currPoint] = True
            totalCost += cost
            
            x1, y1 = points[currPoint]
            for i in range(n):
                if i != currPoint and not seen[i]:
                    x2, y2 = points[i]
                    d = abs(x2 - x1) + abs(y2 - y1)
                    heapq.heappush(pq, (d, i))
        return totalCost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        def find(u):
            if u != group[u]:
                group[u] = find(group[u])
            return group[u]
        
        def unite(u, v):
            u, v = find(u), find(v)
            if u == v:
                return False
            if sz[u] < sz[v]:
                u, v = v, u
            group[v] = u
            sz[u] += sz[v]
            return True
        
        edges = []
        for i in range(len(points)):
            for j in range(len(points)):
                dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                edges.append((dist, i, j))
        edges.sort()
        
        ans = 0
        group = [i for i in range(len(points))]
        sz = [1 for i in range(len(points))]
        for e, u, v in edges:
            if unite(u, v):
                ans += e
        return ans


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
      def l1(p1, p2):
        xi, yi = p1
        xj, yj = p2
        return abs(xi-xj) + abs(yi-yj)
      
      inf = float('inf')
      LV = len(points)
      E = [(u, v) for u in range(LV) for v in range(LV) if u != v]
      E = sorted(E, key=lambda x: l1(points[x[0]],points[x[1]]))
      parent = []
      
      def make_set(v):
        parent[v] = v
      
      def find_set(v):
        if v == parent[v]:
          return v
        parent[v] = find_set(parent[v])
        return parent[v]
      
      def union_sets(a, b):
        a = find_set(a)
        b = find_set(b)
        if a != b:
          parent[b] = a
          
      for v in range(LV):
        parent.append(0)
        make_set(v)
      
      F=[]
      cost = 0
      for (u,v) in E:
        if (a:=find_set(u)) != (b:=find_set(v)):
          F.append((u,v))
          cost += l1(points[u],points[v])
          union_sets(a,b)
      
      return cost

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n == 1: return 0
        res = 0  
        curr = 0
        dis = [math.inf] * n
        explored = set()
        
        for i in range(n - 1):
            x0, y0 = points[curr]
            explored.add(curr)
            for j, (x, y) in enumerate(points):
                if j in explored : continue
                dis[j] = min( dis[j], abs(x - x0) + abs(y - y0) )
                
            delta, curr = min((d, j) for j, d in enumerate(dis)) # curr 后续还会加到explored里面，妙
            dis[curr] = math.inf 
            res += delta
            
        return res

from heapq import *
class Solution:
    def minCostConnectPoints(self, points):
        N = len(points)
        parent = [i for i in range(N)]
        def find(v):
            while parent[v] != parent[parent[v]]:
                parent[v] = parent[parent[v]]
            return parent[v]
        dist = lambda p1, p2: abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
        heap, total_cost = [], 0
        for u in range(N-1):
            for v in range(u+1, N):
                heappush(heap, [dist(points[u], points[v]), u, v])
        while heap:
            cost, u, v = heappop(heap)
            pu, pv = find(u), find(v)
            if pu != pv:
                parent[pu] = pv
                N -= 1
                total_cost += cost
                if N == 0:
                    break
        return total_cost

    
    
    
    
    
    
    
    
from heapq import *
class Solution:
    def minCostConnectPoints(self, points):
        dist = lambda p1, p2: abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
        N = len(points)
        points = sorted(points, key=lambda x: abs(x[0])+abs(x[1]))
        parent = [i for i in range(N)]
        def find(v):
            while parent[v] != parent[parent[v]]:
                parent[v] = parent[parent[v]]
            return parent[v]
        heap = []
        for i in range(N-1):
            for j in range(i+1, N):
                heappush(heap, (dist(points[i], points[j]), i, j))
        res = 0
        while heap:
            d, u, v = heappop(heap)
            pu, pv = find(u), find(v)
            if pu != pv:
                parent[pu] = pv
                res += d
                N -= 1
                if N == 0:
                    break
        return res
            


#class Solution:
#    def minCostConnectPoints(self, points):
#        manhattan = lambda a, b, x, y: abs(a-x)+abs(b-y)
#        points = sorted(points, key=lambda x: abs(x[0])+abs(x[1]))
#        connected = [points[0]]
#        cost = 0
#        points = list(map(lambda x: [x[0], x[1], manhattan(connected[0][0], connected[0][1], x[0], x[1])], points))
#        while len(connected) <= len(points):
#            minidx = None
#            mindist = float('inf')
#            for i in range(len(points)):
#                x, y, dist = points[i]
#                if dist < mindist:
#                    mindist = dist
#                    minidx = i
#            mx, my, mdist = points.pop(minidx)
#            cost += mdist
#            for i in range(len(points)):
#                x, y, dist = points[i]
#                newdist = manhattan(x, y, mx, my)
#                if newdist < dist:
#                    points[i][2] = newdist
#        return cost


class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        graph = collections.defaultdict(list)
        for i in range(len(points)):
            x0, y0 = points[i]
            for j in range(i+1, len(points)):
                x1, y1 = points[j]
                dist = abs(x1-x0)+abs(y1-y0)
                graph[i] += [(j, dist)]
                graph[j] += [(i, dist)]
        res, visited, heap = 0, set(), [(0, 0)]
        while heap and len(visited) <= len(points):
            dist, node = heapq.heappop(heap)
            if node in visited:
                continue
            #print(dist, node, visited)
            res += dist
            visited.add(node)
            for (n, d) in graph[node]:
                if n in visited:
                    continue
                heapq.heappush(heap, (d, n))
        return res

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        edges = []
        
        for i in range(N):
            a = tuple(points[i])
            
            for j in range(N):
                if i == j:
                    continue
                b = tuple(points[j])
                cost = abs(a[0] - b[0]) + abs(a[1] - b[1])
                edges.append((cost, i, j))
                
        edges.sort()
        
        dsu = DSU(N)
        mst = 0
        
        for cost, a, b in edges:
            if dsu.union(a, b):
                mst += cost
                
        return mst
            
class DSU():
    def __init__(self, n):
        self.parent = [i for i in range(n)]
        self.size = [1 for _ in range(n)]

    def union(self, a, b):
        roota = self.find(a)
        rootb = self.find(b)
        if roota == rootb:
            return False
        if self.size[roota] < self.size[rootb]:
            self.size[rootb] += self.size[roota]
            self.parent[roota] = rootb
        else:
            self.size[roota] += self.size[rootb]
            self.parent[rootb] = roota
        return True

    def find(self, a):
        root = self.parent[a]
        while root != self.parent[root]:
            root = self.parent[root]
        curr = a

        # path compression
        while curr != root:
            after = self.parent[curr]
            self.parent[curr] = root
            curr = after

        return root


class Union:
    
    def __init__(self):
        self.parent = {}
        self.rank = {}
        self.count = 0
        
    def add(self, idx):
        if idx not in self.parent:
            self.parent[idx] = idx
            self.rank[idx] = 1
            self.count += 1
    
    def find(self, idx):
        if self.parent[idx] != idx:
            self.parent[idx] = self.find(self.parent[idx])
        return self.parent[idx]
    
    def unite(self, p, q):
        i, j = self.find(p), self.find(q)
        if i == j:
            return True
        if self.rank[i] > self.rank[j]:
            i, j = j, i
        self.parent[i] = j
        self.rank[j] += self.rank[i]
        self.count -= 1
        return False

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        #p_to_cost = {}
        costs = []
        point = Union()
        for i in range(len(points) - 1):
            for j in range(i + 1, len(points)):
                cost = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1])
                #p_to_cost[(i, j)] = val
                costs.append([i, j, cost])
        costs.sort(key=lambda x: x[2])
        res = 0
        for i, j, c in costs:
            point.add(i)
            point.add(j)
            if not point.unite(i, j):
                res += c
        return res

class Solution:
    def minCostConnectPoints(self, a: List[List[int]]) -> int:
        n = len(a)
        g = defaultdict(set)

        @lru_cache(None)
        def dist(x1, y1, x2, y2):
            return abs(x1 - x2) + abs(y1 - y2)

        for i in range(n):
            for j in range(i + 1, n):
                x1, y1 = a[i]
                x2, y2 = a[j]
                w = dist(x1, y1, x2, y2)
                g[(x1, y1)].add((w, x2, y2))
                g[(x2, y2)].add((w, x1, y1))

        q = [(0, (a[0][0], a[0][-1]))]
        visited = set()
        total = ct = 0
        while q:
            # for _ in range(len(q)):
            c, (x1, y1) = heapq.heappop(q)
            if (x1, y1) in visited: continue
            visited.add((x1, y1))
            total += c
            ct += 1
            for w, x2, y2 in g[(x1, y1)]:
                heapq.heappush(q, (w, (x2, y2)))
            if ct >= n: break
        return total

class Solution:
    def distance(self, p1, p2):
        return abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
    
    def build_graph(self, points):
        res = []
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                res.append([i, j, self.distance(points[i], points[j])])
        return res
    
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        connections = self.build_graph(points)        
        connections.sort(key=lambda x:x[2])
        parents = [i for i in range(len(points))]
        
        def find(node):
            parent = parents[node]
            while node != parent:
                node = parent
                parent = parents[node]
            return node
    
        cost = 0    

        for edge in connections:
            node1 = edge[0]
            node2 = edge[1]
            curr_cost = edge[2]

            par1 = find(node1)
            par2 = find(node2)
            
            if par1 != par2:
                parents[par2] = par1
                cost += curr_cost            

        return cost

class UF:
    def __init__(self, n):
        self.parents = [i for i in range(n)]

    def find(self, x):
        if self.parents[x] != x:
            self.parents[x] = self.find(self.parents[x])
        return self.parents[x]
    
    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        if px == py:
            return False
        self.parents[py] = px
        return True
        
        
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        distances = []
        for i, [xi, yi] in enumerate(points):
            for j in range(i + 1, len(points)):
                xj, yj = points[j]
                d = abs(xi - xj) + abs(yi - yj)
                distances.append([d, i, j])
        
        distances.sort()
        uf = UF(len(points))
        ans = 0
        for d, i, j in distances:
            if uf.union(i, j):
                ans += d
        
        return ans