#include <bits/stdc++.h>
#define rep(i,n) for(int i=0;i<n;i++)
using namespace std;
typedef pair<int,int>Pii;
typedef pair<long long,Pii>P2;

#define F first
#define S second

// for debug
unsigned long long xor128() {
    static unsigned long long rx = 123456789, ry = 362436069, rz = 521288629, rw = 88675123;
    unsigned long long rt = (rx ^ (rx << 11));
    rx = ry;
    ry = rz;
    rz = rw;
    return (rw = (rw ^ (rw >> 19)) ^ (rt ^ (rt >> 8)));
}


struct UnionFind{
  int n;
  vector<int> ran,p,cnt;
  UnionFind(){}
  UnionFind(int sz):n(sz),ran(sz,1),p(sz,0){iota(p.begin(),p.end(),0);}
  int find(int x){
    return (x==p[x]?x:p[x]=find(p[x]));
  }
  bool same(int x,int y){
    return find(x)==find(y);
  }
  void unite(int x,int y){
    x=find(x);y=find(y);
    if(x==y) return;
    if(ran[x]<ran[y]) swap(x,y);
    ran[x]+=ran[y];
    p[y]=x;
  }
  int sum(int x){
    return ran[find(x)];
  }
};



const int MAKE = 50000;   // この周期でkd木を再構築。（気休めに）


long long ans;
int n,root,x[100009],y[100009];
map<Pii,int>M;

class Node{
public:
  int location;
  int p,l,r;
  Node(){}
};

class Point{
public:
  int id,x,y;
  Point(){}
  Point(int id,int x,int y): id(id),x(x),y(y){}
  bool operator < (const Point &p){return id<p.id;}
};

static const int MAX =1000000;
static const int NIL = -1;

Point P[MAX];
Node T[MAX];
int np;

bool lessX(Point &p1,Point &p2){return p1.x<p2.x;}
bool lessY(Point &p1,Point &p2){return p1.y<p2.y;}

int makeKDTree(int l,int r, int d){
  if(!(l<r))return NIL;
  int mid=(l+r)>>1;
  int t=np++;
  nth_element(P+l,P+mid,P+r,(d&1 ? lessY : lessX));
  T[t].location=mid;
  T[t].l=makeKDTree(l,mid,d+1);
  T[t].r=makeKDTree(mid+1,r,d+1);
  return t;
}




int find(int v,int sx,int tx,int sy,int ty,int d,int left){
  int x=P[T[v].location].x;
  int y=P[T[v].location].y;
  if(sx<=x&&x<=tx&&sy<=y&&y<=ty)return T[v].location;
  int res = -1;
  if(d%2==0){
    if(T[v].l!=NIL&&sx<=x){
      res = find(T[v].l,sx,tx,sy,ty,d+1,left);
      if(res!=-1)return res;
    }
    if(T[v].r!=NIL&&x<=tx){
      res = find(T[v].r,sx,tx,sy,ty,d+1,left);
      if(res!=-1)return res;
    }
  }
  else{
    if(T[v].l!=NIL&&sy<=y){
      res = find(T[v].l,sx,tx,sy,ty,d+1,left);
      if(res!=-1)return res;
    }
    if(T[v].r!=NIL&&y<=ty){
      res = find(T[v].r,sx,tx,sy,ty,d+1,left);
      if(res!=-1)return res;
    }
  }
  return -1;
}



bool exist(int v,int sx,int tx,int sy,int ty,int d,int left){
  int x=P[T[v].location].x;
  int y=P[T[v].location].y;
  if(sx<=x&&x<=tx&&sy<=y&&y<=ty)return 1;
  if(d%2==0){
    if(T[v].l!=NIL&&sx<=x && exist(T[v].l,sx,tx,sy,ty,d+1,left))return 1;
    if(T[v].r!=NIL&&x<=tx && exist(T[v].r,sx,tx,sy,ty,d+1,left))return 1;
  }
  else{
    if(T[v].l!=NIL&&sy<=y && exist(T[v].l,sx,tx,sy,ty,d+1,left))return 1;
    if(T[v].r!=NIL&&y<=ty && exist(T[v].r,sx,tx,sy,ty,d+1,left))return 1;
  }
  return 0;
}

vector<Pii>v;

P2 get_point(int idx,int Y,int X,int left){
  int l=0,r =1e9,ANS;
  if(left)X--,Y++;
  else X++,Y++;
  if(!left){
      if(!exist( root,X,X+r,Y,Y+r,0,0 )) return P2(0,Pii(0,0));
  }
  else{
      if(!exist( root,X-r,X,Y,Y+r,0,1 )) return P2(0,Pii(0,0));
  }
  while(r-l>1){
    int mid=(r+l)/2;
    if(!left){
      if(exist( root,X,X+mid,Y,Y+mid,0,0 )) r=mid;
      else l=mid;
    }
    else{
      if(exist( root,X-mid,X,Y,Y+mid,0,1 )) r=mid;
      else l=mid;
    }
  }

  if(!left){
    if(exist( root,X,X+l,Y,Y+l,0,0 )) r--;
  }
  else{
    if(exist( root,X-l,X,Y,Y+l,0,1 )) r--;
  }

  if(!left)ANS=find(root,X,X+r,Y,Y+r,0,0);
  else ANS=find( root,X-r,X,Y,Y+r,0,1 );

  if(ANS==-1)return P2(0,Pii(0,0));
  return P2(r+1,Pii( M[Pii( P[ANS].x , P[ANS].y )] , M[Pii( v[idx].S , v[idx].F )] ));
}


vector<Pii>v2;

signed main(){

  priority_queue<P2,vector<P2>,greater<P2> >q;

  //n=xor128()%100000;
  cin>>n;

  rep(i,n){
    //x[i]=xor128()%10000000;
    //y[i]=xor128()%10000000;
    cin>>x[i]>>y[i];
    M[Pii(x[i],y[i])]=i;
    v.push_back(Pii(y[i],x[i]));
    v2.push_back(Pii(x[i],y[i]));
  }

  sort(v.begin(),v.end());
  sort(v2.begin(),v2.end());

  rep(i,n-1){
    if(v[i].F!=v[i+1].F)continue;
    int ax = M[Pii( v[i].S , v[i].F )];
    int bx = M[Pii( v[i+1].S , v[i+1].F )];
    int cost = max( abs(v[i].S-v[i+1].S) , abs(v[i].F-v[i+1].F) );
    q.push( P2( cost , Pii( ax , bx )) );
  }

  rep(i,n-1){
    if(v2[i].F!=v2[i+1].F)continue;
    int ax = M[Pii( v2[i].F , v2[i].S )];
    int bx = M[Pii( v2[i+1].F , v2[i+1].S )];
    int cost = max( abs(v2[i].S-v2[i+1].S) , abs(v2[i].F-v2[i+1].F) );
    q.push( P2( cost , Pii( ax , bx )) );
  }

  rep(i,n){
    if(i%MAKE==0){ np=0;
      for(int j=0;j<n-i;j++){
        T[j].l=T[j].r=T[j].p=NIL;
        P[j]=Point(i+j,v[i+j].S,v[i+j].F);
      }
      root = makeKDTree(0,n-i,0);
    }
    q.push( get_point(i,v[i].F,v[i].S,1) );
    q.push( get_point(i,v[i].F,v[i].S,0) );
  }

  UnionFind U(n+10);

  while(!q.empty()){
    int cost=q.top().F;
    int a=q.top().S.F;
    int b=q.top().S.S;  q.pop();
    if(U.same(a,b))continue;
    ans+=cost;
    U.unite(a,b);
  }

  cout<< ans <<endl;
}


Measured memory_bytes: 22572