Problem:
Road Construction
The Zuia Kingdom has finally emerged through annexation of $N$ cities, which are identified by index from $1$ to $N$. You are appointed the Minister of Transport of the newly born kingdom to construct the inter-city road network.
To simplify the conceptual design planning, you opted to consider each city as a point on the map, so that the $i$-th city can be represented by an coordinate ($x_i, y_i$).
The cost of road construction connecting $u$-th and $v$-th cities is equal to the distance $|x_u - x_v|$ or $|y_u - y_v|$, whichever the larger. The notation $|A|$ represents the absolute value of $A$. The object here is to explore the minimum cost required to construct the road network in such a way that people can move between different cities along one or more roads.
Make a program to calculate the minimum of total road construction cost from the number of cities and their coordinates.
Input
The input is given in the following format.
$N$
$x_1$ $y_1$
$x_2$ $y_2$
...
$x_N$ $y_N$
The first line provides the number of cities $N$ ($2 \leq N \leq 10^5$). Each of the subsequent $N$ lines provides the coordinate of the $i$-th city $x_i, y_i$ ($0 \leq x_i, y_i \leq 10^9$) as integers. Note that none of these coordinates coincides if: $i \ne j$, then $x_i \ne x_j$ or $y_i \ne y_j$.
Output
Output the minimum road construction cost.
Sample Input 1
3
1 2
3 4
10 1
Sample Output 1
9
The road connecting city 1 and 2 can be constructed at the cost of 2, and that connecting city 2 and 3 at the cost of 7. Therefore, the total cost becomes 9, which is the minimum.
Sample Input 2
3
1 2
3 4
3 2
Sample Output 2
4
Sample Input 3
5
7 41
10 0
99 27
71 87
14 25
Sample Output 3
163

Submitted solutions:

code_snippet: // AOJ #0403 Road Construction
// 2025.4.30

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

#define gc() getchar_unlocked()

int Cin() {
	int n = 0; int c = gc();
	do n = 10*n + (c & 0xf), c = gc(); while (c >= '0');
	return n;
}

vector<int> p, rk;
int findf(int x){ return p[x]==x ? x : p[x]=findf(p[x]); }
bool unite(int a, int b){
    a = findf(a); b = findf(b);
    if(a==b) return false;
    if(rk[a]<rk[b]) swap(a,b);
    p[b] = a;
    if(rk[a]==rk[b]) rk[a]++;
    return true;
}

struct P { ll x, y; };

int main(){
    int N = Cin();
    vector<P> ps(N);
    for(int i = 0; i < N; i++){
        ll x = Cin(), y = Cin();
        ps[i] = { x+y, x-y };
    }

    vector<int> id(N);
    iota(id.begin(), id.end(), 0);
    vector<tuple<ll,int,int>> es;
    es.reserve(4LL * N);

    for(int rot = 0; rot < 4; rot++){
        sort(id.begin(), id.end(), [&](int i, int j){
            return ps[i].x + ps[i].y < ps[j].x + ps[j].y;
        });
        map<ll,int, greater<ll>> active;
        for(int i : id){
            ll xi = ps[i].x, yi = ps[i].y;
            for(auto it = active.lower_bound(xi); it != active.end(); ){
                int j = it->second;
                ll xj = ps[j].x, yj = ps[j].y;
                if(xi - yi > xj - yj) break;
                es.emplace_back((xi - xj) + (yi - yj), i, j);
                it = active.erase(it);
            }
            active[xi] = i;
        }
        for(auto &pp : ps){
            if (rot & 1) pp.x = -pp.x;
            else swap(pp.x, pp.y);
        }
    }

    p.resize(N); rk.assign(N,0);
    iota(p.begin(), p.end(), 0);
    sort(es.begin(), es.end(), [](auto &a, auto &b){
        return get<0>(a) < get<0>(b);
    });
    ll ans = 0;
    for(auto &e : es){
        ll w; int u, v;
        tie(w, u, v) = e;
        if(unite(u, v)) ans += w;
    }
    cout << (ans / 2) << endl;
    return 0;
}
accuracy: 1
time_ms: 100
memory_kb: 15996
final_rank: 1

code_snippet: #include <bits/stdc++.h>
using namespace std;

using ll = long long;

struct UnionFind {
	vector<int> par;
	UnionFind(const int n) : par(n, -1) {}
	int find(const int u) {
		return par[u] < 0 ? u : par[u] = find(par[u]);
	}
	bool merge(int x, int y) {
		x = find(x);
		y = find(y);
		if (x == y) return false;
		if (par[x] > par[y]) swap(x, y);
		par[x] += par[y];
		par[y] = x;
		return true;
	}
};

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	
	int N;
	cin >> N;
	vector<int> X(N), Y(N);
	for (int i = 0; i < N; ++i) {
		cin >> X[i] >> Y[i];
	}

	vector<tuple<int, int, int>> edges;
	const auto process = [&] {
		vector<int> ord(N);
		iota(begin(ord), end(ord), 0);
		sort(begin(ord), end(ord), [&](const int i, const int j) {
			return X[i] < X[j];
		});

		std::map<int, int> map;
		for (const int i : ord) {
			auto itr = map.upper_bound(Y[i]);
			while (itr != begin(map)) {
				--itr;
				const int j = itr->second;
				if (Y[j] - X[j] > Y[i] - X[i]) {
					itr = map.erase(itr);
					continue;
				}
				edges.emplace_back(Y[i] - Y[j], i, j);
				break;
			}
			map[Y[i]] = i;
		}
	};

	for (int a = 0; a < 2; ++a) {
		for (int b = 0; b < 2; ++b) {
			for (int c = 0; c < 2; ++c) {
				process();
				swap(X, Y);
			}
			for (int i = 0; i < N; ++i) X[i] = 1000000000 -X[i];
		}
		for (int i = 0; i < N; ++i) Y[i] = 1000000000 -Y[i];
	}

	sort(begin(edges), end(edges));
	UnionFind uf(N);
	ll ans = 0;
	for (const auto& [c, i, j] : edges) {
		if (uf.merge(i, j)) {
			ans += c;
		}
	}
	cout << ans << '\n';

	return 0;
}
accuracy: 1
time_ms: 240
memory_kb: 17816
final_rank: 5

code_snippet: #include <bits/stdc++.h>
#pragma GCC optimize("O2")
using namespace std;

typedef pair<int, int> pii;
typedef long long ll;
typedef pair<ll, ll> pll;
#define X first
#define Y second
#define io ios_base::sync_with_stdio(0); cin.tie(0);
#define setpr setprecision
#define eb emplace_back
#define lowb lower_bound
#define uppb upper_bound
#define lowbit(x) ((x) & -(x))
#define mk make_pair
const ll M = 1e9 + 7;
const ll INF = 1e14;

pll pt[100005];
vector <int> v[100005];
ll cost[1200005];
pll edge[1200005];
int add[100005];

ll dis(pll a, pll b){
	return max(abs(a.X - b.X), abs(a.Y - b.Y));
}

bool cmp(pll a, pll b){
	return a.Y == b.Y ? a.X < b.X : a.Y < b.Y;
}

ll solve(int n){
	int ct = 0; ll ans = 0;
	priority_queue <pll, vector<pll>, greater<pll> > pq;
	while(pq.size()) pq.pop();
	pq.emplace(0, 1);

	while(pq.size()){
		pll p = pq.top(); pq.pop();
		if(add[p.Y]) continue;
		ct++; add[p.Y] = 1; ans += p.X;
		if(ct == n) break;

		for(auto i : v[p.Y]){
			int ver = edge[i].X + edge[i].Y - p.Y;
			if(add[ver]) continue;
			pq.emplace(cost[i], ver);
		}
	}
	return ans;
}

int main(){
	io
	int n; cin >> n;
	for(int i = 0; i < n; i++)
		cin >> pt[i].X >> pt[i].Y;
	sort(pt, pt + n);
	ll maxdis = -1, ct = 0;
	for(int i = 1; i < n; i++)
		maxdis = max(maxdis, dis(pt[i - 1], pt[i]));
	for(int i = 0; i < n; i++){
		for(int j = i + 1; j < n; j++){
			if(pt[j].X - pt[i].X > maxdis) break;
			ll tmp = dis(pt[j], pt[i]);
			if(tmp <= maxdis){
				v[i + 1].eb(ct); v[j + 1].eb(ct);
				edge[ct] = mk(i + 1, j + 1); cost[ct++] = tmp;
			}
		}
	}
	ll ans = solve(n);
	cout << ans << "\n";
	return 0;
}
accuracy: 0.140625
time_ms: 80
memory_kb: 49176
final_rank: 19

code_snippet: #include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <numeric>
#include <bitset>
#include <cmath>

static const int MOD = 1000000007;
using ll = long long;
using u32 = unsigned;
using u64 = unsigned long long;
using namespace std;

template<class T> constexpr T INF = ::numeric_limits<T>::max()/32*15+208;

template<typename T>
vector<pair<int, int>> manhattanMST(vector<T> xs, vector<T> ys) {
    using P = pair<int, int>;
    vector<P> es;
    vector<int> ord(xs.size());
    for (int s = 0; s < 4; s++) {
        iota(ord.begin(), ord.end(), 0);
        auto cmp = [&](int i, int j) -> bool {
            if (xs[i]+ys[i] != xs[j]+ys[j]) return xs[i]+ys[i] < xs[j]+ys[j];
            return (s>>1) ^ (i > j);
        };
        sort(ord.begin(), ord.end(), cmp);
        map<pair<T, int>, int> idx;
        for (auto &&i : ord) {
            pair<T, int> p = {-ys[i], (s == 3)?i:-i};
            for (auto it = idx.lower_bound(p); it != idx.end(); it = idx.erase(it)) {
                if (xs[i] - xs[it->second] < ys[i] - ys[it->second]) break;
                es.emplace_back(i, it->second);
            }
            idx[p] = i;
        }
        swap(xs, ys);
        if(s&1) for(auto &&i : xs) i = -i;
    }
    return es;
}

class UnionFind {
    int n;
    vector<int> uni;
    int forest_size;
public:
    explicit UnionFind(int n) : n(n), uni(static_cast<u32>(n), -1), forest_size(n) {};

    int root(int a){
        if (uni[a] < 0) return a;
        else return (uni[a] = root(uni[a]));
    }

    bool unite(int a, int b) {
        a = root(a);
        b = root(b);
        if(a == b) return false;
        if(uni[a] > uni[b]) swap(a, b);
        uni[a] += uni[b];
        uni[b] = a;
        forest_size--;
        return true;
    }
    int size(){ return forest_size; }
    int size(int i){ return -uni[root(i)]; }
    bool same(int a, int b) { return root(a) == root(b); }
};

int main() {
    int n;
    cin >> n;
    vector<int> xs(n), ys(n);
    for (int i = 0; i < n; ++i) {
        int x, y;
        cin >> x >> y;
        xs[i] = x+y, ys[i] = x-y;
    }
    auto res = manhattanMST(xs, ys);
    vector<pair<int, pair<int, int>>> r(res.size());
    for (int i = 0; i < res.size(); ++i) {
        auto &&x = res[i];
        r[i] = {abs(xs[x.first]-xs[x.second])+abs(ys[x.first]-ys[x.second]), {x.first, x.second}};
    }
    sort(r.begin(),r.end());
    UnionFind uf(n);
    ll ans = 0;
    for (auto &&i : r) {
        pair<int, int> p; tie(ignore, p) = i;
        if(uf.unite(p.first, p.second)) ans += i.first;
    }
    cout << ans/2 << "\n";
    return 0;
}
accuracy: 1
time_ms: 160
memory_kb: 12780
final_rank: 3

code_snippet: #include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
using i32 = int32_t;
using u32 = uint32_t;
using i64 = int64_t;
using u64 = uint64_t;
#define rep(i,n) for(int i=0; i<(n); i++)



#include <vector>
#include <algorithm>
#include <map>


pair<i64, vector<pair<int, int>>> manhattan_mst(const vector<pair<i64, i64>>& pos) {
    auto dist = [&pos](int a, int b)->i64 {
        //return abs(pos[a].first - pos[b].first) + abs(pos[a].second - pos[b].second);
        return max(abs(pos[a].first - pos[b].first), abs(pos[a].second - pos[b].second));
    };
    int n = pos.size();
    using POS2 = pair<i64, i64>;
    vector<POS2> P(n);
    rep(i, n) P[i] = make_pair(pos[i].first, pos[i].second);
    vector<int> I(n);
    rep(i, n) I[i] = i;
    vector<pair<i64, pair<int, int>>> res;
    rep(s, 2) {
        rep(t, 2) {
            sort(I.begin(), I.end(), [&P](int l, int r) { return P[l].first < P[r].first; });
            map<i64, int> G;
            for (auto i : I) {
                for (auto ig = G.lower_bound(-P[i].first - P[i].second);
                    ig != G.end();  ig = G.erase(ig))
                {
                    int j = ig->second;
                    if (P[i].second > P[j].second) break;
                    res.emplace_back(dist(i, j), make_pair(i, j));
                }
                G[-P[i].first - P[i].second] = i;
            }
            rep(i, n) swap(P[i].first, P[i].second);
        }
        rep(i, n) P[i].first = -P[i].first;
    }
    struct DSU {
        vector<int> A;
        DSU(int n) { A.assign(n, -1); }
        int leader(int a) {
            if (A[a] < 0) return a;
            return A[a] = leader(A[a]);
        }
        void merge(int a, int b) {
            a = leader(a);
            b = leader(b);
            if (a == b) return;
            A[a] = b;
        }
    } dsu(n);
    sort(res.begin(), res.end());
    i64 ans_val = 0;
    vector<pair<int, int>> ans;
    for (auto e : res) {
        if (dsu.leader(e.second.first) == dsu.leader(e.second.second)) continue;
        ans_val += e.first;
        ans.push_back(e.second);
        dsu.merge(e.second.first, e.second.second);
    }
    return make_pair(ans_val, move(ans));
}


int main(){
  int N; cin >> N;
  vector<pair<i64,i64>> P(N);
  for(auto& a : P) cin >> a.first >> a.second;
  cout << manhattan_mst(P).first << endl;
  return 0;
}




struct ios_do_not_sync {
    ios_do_not_sync() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
    }
} ios_do_not_sync_instance;
accuracy: 1
time_ms: 130
memory_kb: 19156
final_rank: 4

code_snippet: #include <bits/stdc++.h>
using namespace std;

struct Edge
{
  int w = INT_MAX, to = -1;
  bool operator<(Edge const &other) const
  {
    return make_pair(w, to) < make_pair(other.w, other.to);
  }
};

int n, coords[100000][2];
vector<vector<Edge>> adj;

bool sortX(int a, int b) { return coords[a][0] < coords[b][0]; }
bool sortY(int a, int b) { return coords[a][1] < coords[b][1]; }

void prim()
{
  long total_weight = 0;
  vector<Edge> min_e(n);
  min_e[0].w = 0;
  set<Edge> q;
  q.insert({0, 0});
  vector<bool> selected(n, false);
  for (int i = 0; i < n; ++i)
  {
    if (q.empty())
    {
      cout << "No MST!" << endl;
      exit(0);
    }

    int v = q.begin()->to;
    selected[v] = true;
    total_weight += q.begin()->w;
    q.erase(q.begin());

    // if (min_e[v].to != -1)
    //   cout << v << " " << min_e[v].to << endl;

    for (Edge e : adj[v])
    {
      if (!selected[e.to] && e.w < min_e[e.to].w)
      {
        q.erase({min_e[e.to].w, e.to});
        min_e[e.to] = {e.w, v};
        q.insert({e.w, e.to});
      }
    }
  }

  cout << total_weight << endl;
}

int main()
{
  ios::sync_with_stdio(false);
  cin.tie(0);

  cin >> n;
  vector<int> x(n), y(n);
  adj.resize(n);
  for (int i = 0; i < n; i++)
  {
    cin >> coords[i][0] >> coords[i][1];
    x[i] = i;
    y[i] = i;
  }

  sort(x.begin(), x.end(), sortX);
  for (int i = 0; i < n; i++)
  {
    if (i == 0)
    {
      for (int j = 1; j < 1000 && i + j < n; j++)
        adj[x[i]].push_back({max(abs(coords[x[i]][0] - coords[x[i + j]][0]), abs(coords[x[i]][1] - coords[x[i + j]][1])), x[i + j]});
    }
    else if (i == n - 1)
    {
      for (int j = 1; j < 1000 && i - j >= 0; j++)
        adj[x[i]].push_back({max(abs(coords[x[i]][0] - coords[x[i - j]][0]), abs(coords[x[i]][1] - coords[x[i - j]][1])), x[i - j]});
    }
    else
    {
      for (int j = 1; j < 500 && i + j < n; j++)
        adj[x[i]].push_back({max(abs(coords[x[i]][0] - coords[x[i + j]][0]), abs(coords[x[i]][1] - coords[x[i + j]][1])), x[i + j]});
      for (int j = 1; j < 500 && i - j >= 0; j++)
        adj[x[i]].push_back({max(abs(coords[x[i]][0] - coords[x[i - j]][0]), abs(coords[x[i]][1] - coords[x[i - j]][1])), x[i - j]});
    }
  }
  // for (int i = 0; i < n; i++)
  // {
  //   cout << i << ": ";
  //   for (Edge x : adj[i])
  //   {
  //     cout << x.to << " ";
  //   }
  //   cout << endl;
  // }

  sort(y.begin(), y.end(), sortY);
  for (int i = 0; i < n; i++)
  {
    if (i == 0)
    {
      for (int j = 1; j < 1000 && i + j < n; j++)
        adj[y[i]].push_back({max(abs(coords[y[i]][0] - coords[y[i + j]][0]), abs(coords[y[i]][1] - coords[y[i + j]][1])), y[i + j]});
    }
    else if (i == n - 1)
    {
      for (int j = 1; j < 1000 && i - j >= 0; j++)
        adj[y[i]].push_back({max(abs(coords[y[i]][0] - coords[y[i - j]][0]), abs(coords[y[i]][1] - coords[y[i - j]][1])), y[i - j]});
    }
    else
    {
      for (int j = 1; j < 500 && i + j < n; j++)
        adj[y[i]].push_back({max(abs(coords[y[i]][0] - coords[y[i + j]][0]), abs(coords[y[i]][1] - coords[y[i + j]][1])), y[i + j]});
      for (int j = 1; j < 500 && i - j >= 0; j++)
        adj[y[i]].push_back({max(abs(coords[y[i]][0] - coords[y[i - j]][0]), abs(coords[y[i]][1] - coords[y[i - j]][1])), y[i - j]});
    }
  }

  prim();

  return 0;
}
accuracy: 0.140625
time_ms: 480
memory_kb: 134112
final_rank: 20

code_snippet: #include <bits/stdc++.h>
using namespace std;

struct Edge
{
  int w = INT_MAX, to = -1;
  bool operator<(Edge const &other) const
  {
    return make_pair(w, to) < make_pair(other.w, other.to);
  }
};

int n, coords[100000][2];
vector<vector<Edge>> adj;

bool sortX(int a, int b) { return coords[a][0] < coords[b][0]; }
bool sortY(int a, int b) { return coords[a][1] < coords[b][1]; }

void prim()
{
  long total_weight = 0;
  vector<Edge> min_e(n);
  min_e[0].w = 0;
  set<Edge> q;
  q.insert({0, 0});
  vector<bool> selected(n, false);
  for (int i = 0; i < n; ++i)
  {
    if (q.empty())
    {
      cout << "No MST!" << endl;
      exit(0);
    }

    int v = q.begin()->to;
    selected[v] = true;
    total_weight += q.begin()->w;
    q.erase(q.begin());

    // if (min_e[v].to != -1)
    //   cout << v << " " << min_e[v].to << endl;

    for (Edge e : adj[v])
    {
      if (!selected[e.to] && e.w < min_e[e.to].w)
      {
        q.erase({min_e[e.to].w, e.to});
        min_e[e.to] = {e.w, v};
        q.insert({e.w, e.to});
      }
    }
  }

  cout << total_weight << endl;
}

int main()
{
  ios::sync_with_stdio(false);
  cin.tie(0);

  cin >> n;
  vector<int> x(n), y(n);
  adj.resize(n);
  for (int i = 0; i < n; i++)
  {
    cin >> coords[i][0] >> coords[i][1];
    x[i] = i;
    y[i] = i;
  }

  sort(x.begin(), x.end(), sortX);
  for (int i = 0; i < n; i++)
  {
    if (i == 0)
    {
      for (int j = 1; j < 100 && i + j < n; j++)
        adj[x[i]].push_back({max(abs(coords[x[i]][0] - coords[x[i + j]][0]), abs(coords[x[i]][1] - coords[x[i + j]][1])), x[i + j]});
    }
    else if (i == n - 1)
    {
      for (int j = 1; j < 100 && i - j >= 0; j++)
        adj[x[i]].push_back({max(abs(coords[x[i]][0] - coords[x[i - j]][0]), abs(coords[x[i]][1] - coords[x[i - j]][1])), x[i - j]});
    }
    else
    {
      for (int j = 1; j < 50 && i + j < n; j++)
        adj[x[i]].push_back({max(abs(coords[x[i]][0] - coords[x[i + j]][0]), abs(coords[x[i]][1] - coords[x[i + j]][1])), x[i + j]});
      for (int j = 1; j < 50 && i - j >= 0; j++)
        adj[x[i]].push_back({max(abs(coords[x[i]][0] - coords[x[i - j]][0]), abs(coords[x[i]][1] - coords[x[i - j]][1])), x[i - j]});
    }
  }
  // for (int i = 0; i < n; i++)
  // {
  //   cout << i << ": ";
  //   for (Edge x : adj[i])
  //   {
  //     cout << x.to << " ";
  //   }
  //   cout << endl;
  // }

  sort(y.begin(), y.end(), sortY);
  for (int i = 0; i < n; i++)
  {
    if (i == 0)
    {
      for (int j = 1; j < 100 && i + j < n; j++)
        adj[y[i]].push_back({max(abs(coords[y[i]][0] - coords[y[i + j]][0]), abs(coords[y[i]][1] - coords[y[i + j]][1])), y[i + j]});
    }
    else if (i == n - 1)
    {
      for (int j = 1; j < 100 && i - j >= 0; j++)
        adj[y[i]].push_back({max(abs(coords[y[i]][0] - coords[y[i - j]][0]), abs(coords[y[i]][1] - coords[y[i - j]][1])), y[i - j]});
    }
    else
    {
      for (int j = 1; j < 50 && i + j < n; j++)
        adj[y[i]].push_back({max(abs(coords[y[i]][0] - coords[y[i + j]][0]), abs(coords[y[i]][1] - coords[y[i + j]][1])), y[i + j]});
      for (int j = 1; j < 50 && i - j >= 0; j++)
        adj[y[i]].push_back({max(abs(coords[y[i]][0] - coords[y[i - j]][0]), abs(coords[y[i]][1] - coords[y[i - j]][1])), y[i - j]});
    }
  }

  prim();

  return 0;
}
accuracy: 0.140625
time_ms: 40
memory_kb: 19924
final_rank: 18

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 100005

struct Info{
	bool operator<(const struct Info& arg) const{

		return value < arg.value;
	}
	void set(ll arg_value,ll arg_index){
		value = arg_value;
		index = arg_index;
	}
	ll value,index;
};


struct Point{

	ll x,y,input_index;
};

struct Edge{
	Edge(int arg_a,int arg_b,ll arg_cost){
		a = arg_a;
		b = arg_b;
		cost = arg_cost;
	}
	bool operator<(const struct Edge& arg) const{

		return cost < arg.cost;
	}
	int a,b;
	ll cost;
};

int N;
int boss[SIZE],height[SIZE],num_member[SIZE];
int INDEX[SIZE];
Info table[6*SIZE];
Point point[SIZE];
vector<Edge> edge;


void init(int first_N){
	N = 1;
	while(N < first_N)N *= 2;
}

void update(int loc,ll value,ll index){
	loc += N-1;

	if(table[loc].value <= value){

		return;
	}
	table[loc].set(value,index);

	if(N == 1)return;

	int parent = (loc-1)/2;

	while(true){

		int L = 2*parent+1,R = 2*parent+2;
		table[parent] = min(table[L],table[R]);

		if(parent == 0)break;
		else{
			parent = (parent-1)/2;
		}
	}
}


Info query(int search_left,int search_right,int node_id,int node_left,int node_right){

	Info ret;

	if(search_right < node_left || search_left > node_right){

		ret.set(HUGE_NUM,-1);
		return ret;
	}

	if(search_left <= node_left && search_right >= node_right){
		return table[node_id];
	}

	Info left_min = query(search_left,search_right,2*node_id+1,node_left,(node_left+node_right)/2);
	Info right_min = query(search_left,search_right,2*node_id+2,(node_left+node_right)/2+1,node_right);

	return min(left_min,right_min);
}

int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

int isSame(int x,int y){
	return get_boss(x) == get_boss(y);
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[boss_x] > height[boss_y]){

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;

	}else if(height[boss_x] < height[boss_y]){

		num_member[boss_y] += num_member[boss_x];
		boss[boss_x] = boss_y;

	}else{ //height[boss_x] == height[boss_y]

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;
		height[x]++;
	}
}


int main(){

	int first_N;

	scanf("%d",&first_N);

	init(first_N);

	for(int i = 0; i < first_N; i++){

		scanf("%lld %lld",&point[i].x,&point[i].y);
		point[i].input_index = i;
	}

	for(int a = 0; a <= 1; a++){
		for(int b = 0; b <= 1; b++){
			for(int c = 0; c <= 1; c++){
				for(int i = 0; i <= 2*N-2; i++){

					table[i].value = HUGE_NUM;
				}

				vector<int> IND(first_N);
				iota(IND.begin(), IND.end(), 0);

				sort(IND.begin(), IND.end(), [&](int i, int j) {
					if(point[i].y-point[i].x != point[j].y-point[j].x){

						return point[i].y-point[i].x < point[j].y-point[j].x;
					}else if(point[i].y != point[j].y){

						return point[i].y > point[j].y;
					}else{

						return i > j;
					}
				});

				vector<ll> vec_Y;
				for(int i = 0; i < first_N; i++){

					vec_Y.push_back(point[i].y);
				}
				sort(vec_Y.begin(),vec_Y.end());
				vec_Y.erase(unique(vec_Y.begin(),vec_Y.end()),vec_Y.end());

				map<ll,ll> MAP;
				for(int i = 0; i < vec_Y.size(); i++){

					MAP[vec_Y[i]] = i;
				}

				for(int i = 0; i < first_N; i++){

					Info ret = query(MAP[point[IND[i]].y],first_N,0,0,N-1); //y座標が自分以上のデータの、max(x,y)の最小値を取得
					if(ret.value != HUGE_NUM){

						edge.push_back(Edge(IND[i],ret.index,max(abs(point[IND[i]].x-point[ret.index].x),abs(point[IND[i]].y-point[ret.index].y))));
					}
					update(MAP[point[IND[i]].y],max(point[IND[i]].x,point[IND[i]].y),IND[i]); //★★★xとyの大きい方の値を登録★★★
				}

				for(int i = 0; i < first_N; i++){
					swap(point[i].x,point[i].y);
				}
			}
			for(int i = 0; i < first_N; i++){

				point[i].x *= -1;
			}
		}
		for(int i = 0; i < first_N; i++){

			point[i].y *= -1;
		}
	}
	for(int i = 0; i < first_N; i++){

		boss[i] = i;
		height[i] = 0;
		num_member[i] = 1;
	}

	sort(edge.begin(),edge.end());

	ll ans = 0;

	vector<Edge> ANS;

	for(int i = 0; i < edge.size(); i++){
		if(isSame(edge[i].a,edge[i].b))continue;

		unite(edge[i].a,edge[i].b);
		ANS.push_back(edge[i]);
		ans += edge[i].cost;
	}

	printf("%lld\n",ans);

	return 0;
}
accuracy: 1
time_ms: 900
memory_kb: 33000
final_rank: 6

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 100005

struct Info{
	bool operator<(const struct Info& arg) const{

		return value < arg.value;
	}
	void set(ll arg_value,ll arg_index){
		value = arg_value;
		index = arg_index;
	}
	ll value,index;
};


struct Point{

	ll x,y,input_index;
};

struct Edge{
	Edge(int arg_a,int arg_b,ll arg_cost){
		a = arg_a;
		b = arg_b;
		cost = arg_cost;
	}
	bool operator<(const struct Edge& arg) const{

		return cost < arg.cost;
	}
	int a,b;
	ll cost;
};

int N;
int boss[SIZE],height[SIZE],num_member[SIZE];
int INDEX[SIZE];
Info table[6*SIZE];
Point point[SIZE];
vector<Edge> edge;


void init(int first_N){
	N = 1;
	while(N < first_N)N *= 2;
}

void update(int loc,ll value,ll index){
	loc += N-1;

	if(table[loc].value <= value){

		return;
	}
	table[loc].set(value,index);

	if(N == 1)return;

	int parent = (loc-1)/2;

	while(true){

		int L = 2*parent+1,R = 2*parent+2;
		table[parent] = min(table[L],table[R]);

		if(parent == 0)break;
		else{
			parent = (parent-1)/2;
		}
	}
}


Info query(int search_left,int search_right,int node_id,int node_left,int node_right){

	Info ret;

	//今回のノードが検索区間をカバーしていなければ、結果に関係ない値を返す
	if(search_right < node_left || search_left > node_right){

		ret.set(HUGE_NUM,-1);
		return ret;
	}

	//今回のノードの区間が、検索区間の部分区間である場合、今回のノードの値を返す
	if(search_left <= node_left && search_right >= node_right){
		return table[node_id];
	}

	//今回のノードの区間に、一部検索区間と重なっている区間がある場合→再帰的に子どもに尋ねる
	Info left_min = query(search_left,search_right,2*node_id+1,node_left,(node_left+node_right)/2);
	Info right_min = query(search_left,search_right,2*node_id+2,(node_left+node_right)/2+1,node_right);

	return min(left_min,right_min);
}

int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

int isSame(int x,int y){
	return get_boss(x) == get_boss(y);
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[boss_x] > height[boss_y]){

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;

	}else if(height[boss_x] < height[boss_y]){

		num_member[boss_y] += num_member[boss_x];
		boss[boss_x] = boss_y;

	}else{ //height[boss_x] == height[boss_y]

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;
		height[x]++;
	}
}


int main(){

	int first_N;

	scanf("%d",&first_N);

	init(first_N);

	for(int i = 0; i < first_N; i++){

		scanf("%lld %lld",&point[i].x,&point[i].y);
		point[i].input_index = i;
	}

	for(int a = 0; a <= 1; a++){
		for(int b = 0; b <= 1; b++){
			for(int c = 0; c <= 1; c++){
				for(int i = 0; i <= 2*N-2; i++){

					table[i].value = HUGE_NUM;
				}

				std::vector<int> IND(first_N);
				std::iota(IND.begin(), IND.end(), 0);

				std::sort(IND.begin(), IND.end(), [&](int i, int j) {
					if(point[i].y-point[i].x != point[j].y-point[j].x){

						return point[i].y-point[i].x < point[j].y-point[j].x;
					}else if(point[i].y != point[j].y){

						return point[i].y > point[j].y;
					}else{

						return i > j;
					}
				});

				vector<ll> vec_Y;
				for(int i = 0; i < first_N; i++){

					vec_Y.push_back(point[i].y);
				}
				sort(vec_Y.begin(),vec_Y.end());
				vec_Y.erase(unique(vec_Y.begin(),vec_Y.end()),vec_Y.end());

				map<ll,ll> MAP;
				for(int i = 0; i < vec_Y.size(); i++){

					MAP[vec_Y[i]] = i;
				}

				for(int i = 0; i < first_N; i++){

					Info ret = query(MAP[point[IND[i]].y],first_N,0,0,N-1); //y座標が自分以上のデータの、max(x,y)の最小値を取得
					if(ret.value != HUGE_NUM){

						edge.push_back(Edge(IND[i],ret.index,max(abs(point[IND[i]].x-point[ret.index].x),abs(point[IND[i]].y-point[ret.index].y))));
					}
					update(MAP[point[IND[i]].y],max(point[IND[i]].x,point[IND[i]].y),IND[i]);
				}

				for(int i = 0; i < first_N; i++){
					swap(point[i].x,point[i].y);
				}
			}
			for(int i = 0; i < first_N; i++){

				point[i].x *= -1;
			}
		}
		for(int i = 0; i < first_N; i++){

			point[i].y *= -1;
		}
	}
	for(int i = 0; i < first_N; i++){

		boss[i] = i;
		height[i] = 0;
		num_member[i] = 1;
	}

	sort(edge.begin(),edge.end());

	ll ans = 0;

	vector<Edge> ANS;

	for(int i = 0; i < edge.size(); i++){
		if(isSame(edge[i].a,edge[i].b))continue;

		unite(edge[i].a,edge[i].b);
		ANS.push_back(edge[i]);
		ans += edge[i].cost;
	}

	printf("%lld\n",ans);

	return 0;
}
accuracy: 1
time_ms: 920
memory_kb: 33088
final_rank: 7

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 100005

struct Info{
	bool operator<(const struct Info& arg) const{

		return value < arg.value;
	}
	void set(ll arg_value,ll arg_index){
		value = arg_value;
		index = arg_index;
	}
	ll value,index;
};


struct Point{

	ll x,y,input_index;
};

struct Edge{
	Edge(int arg_a,int arg_b,ll arg_cost){
		a = arg_a;
		b = arg_b;
		cost = arg_cost;
	}
	bool operator<(const struct Edge& arg) const{

		return cost < arg.cost;
	}
	int a,b;
	ll cost;
};

int N;
int boss[SIZE],height[SIZE],num_member[SIZE];
int INDEX[SIZE];
Info table[6*SIZE];
Point point[SIZE];
vector<Edge> edge;


void init(int first_N){
	N = 1;
	while(N < first_N)N *= 2;
}

void update(int loc,ll value,ll index){
	loc += N-1;

	if(table[loc].value <= value){

		return;
	}
	table[loc].set(value,index);

	if(N == 1)return;

	int parent = (loc-1)/2;

	while(true){

		int L = 2*parent+1,R = 2*parent+2;
		table[parent] = min(table[L],table[R]);

		if(parent == 0)break;
		else{
			parent = (parent-1)/2;
		}
	}
}


Info query(int search_left,int search_right,int node_id,int node_left,int node_right){

	Info ret;

	//今回のノードが検索区間をカバーしていなければ、結果に関係ない値を返す
	if(search_right < node_left || search_left > node_right){

		ret.set(HUGE_NUM,-1);
		return ret;
	}

	//今回のノードの区間が、検索区間の部分区間である場合、今回のノードの値を返す
	if(search_left <= node_left && search_right >= node_right){
		return table[node_id];
	}

	//今回のノードの区間に、一部検索区間と重なっている区間がある場合→再帰的に子どもに尋ねる
	Info left_min = query(search_left,search_right,2*node_id+1,node_left,(node_left+node_right)/2);
	Info right_min = query(search_left,search_right,2*node_id+2,(node_left+node_right)/2+1,node_right);

	return min(left_min,right_min);
}

int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

int isSame(int x,int y){
	return get_boss(x) == get_boss(y);
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[boss_x] > height[boss_y]){

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;

	}else if(height[boss_x] < height[boss_y]){

		num_member[boss_y] += num_member[boss_x];
		boss[boss_x] = boss_y;

	}else{ //height[boss_x] == height[boss_y]

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;
		height[x]++;
	}
}


int main(){

	int first_N;

	scanf("%d",&first_N);

	init(first_N);

	for(int i = 0; i < first_N; i++){

		scanf("%lld %lld",&point[i].x,&point[i].y);
		point[i].input_index = i;
	}

	for(int d = 0; d < 2; d++){
	for(int a = 0; a <= 1; a++){
		for(int b = 0; b <= 1; b++){
			for(int c = 0; c <= 1; c++){
				for(int i = 0; i <= 2*N-2; i++){

					table[i].value = HUGE_NUM;
				}

				std::vector<int> IND(first_N);
				std::iota(IND.begin(), IND.end(), 0);

				std::sort(IND.begin(), IND.end(), [&](int i, int j) {
					if(point[i].y-point[i].x != point[j].y-point[j].x){

						return point[i].y-point[i].x < point[j].y-point[j].x;
					}else if(point[i].y != point[j].y){

						return point[i].y > point[j].y;
					}else{

						if(d == 0){
						return i > j;
						}else{
							return i < j;
						}
					}
				});

				vector<ll> vec_Y;
				for(int i = 0; i < first_N; i++){

					vec_Y.push_back(point[i].y);
				}
				sort(vec_Y.begin(),vec_Y.end());
				vec_Y.erase(unique(vec_Y.begin(),vec_Y.end()),vec_Y.end());

				map<ll,ll> MAP;
				for(int i = 0; i < vec_Y.size(); i++){

					MAP[vec_Y[i]] = i;
				}

				for(int i = 0; i < first_N; i++){

					Info ret = query(MAP[point[IND[i]].y],first_N,0,0,N-1); //y座標が自分以上のデータの、x+yの最小値を取得
					if(ret.value != HUGE_NUM){

						edge.push_back(Edge(IND[i],ret.index,max(abs(point[IND[i]].x-point[ret.index].x),abs(point[IND[i]].y-point[ret.index].y))));
					}
					update(MAP[point[IND[i]].y],point[IND[i]].x+point[IND[i]].y,IND[i]);
				}

				for(int i = 0; i < first_N; i++){
					swap(point[i].x,point[i].y);
				}
			}
			for(int i = 0; i < first_N; i++){

				point[i].x *= -1;
			}
		}
		for(int i = 0; i < first_N; i++){

			point[i].y *= -1;
		}
	}
	}
	for(int i = 0; i < first_N; i++){

		boss[i] = i;
		height[i] = 0;
		num_member[i] = 1;
	}

	sort(edge.begin(),edge.end());

	ll ans = 0;

	vector<Edge> ANS;

	for(int i = 0; i < edge.size(); i++){
		if(isSame(edge[i].a,edge[i].b))continue;

		unite(edge[i].a,edge[i].b);
		ANS.push_back(edge[i]);
		ans += edge[i].cost;
	}

	printf("%lld\n",ans);

	return 0;
}
accuracy: 0.359375
time_ms: 40
memory_kb: 5416
final_rank: 17

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 100005

struct Info{
	bool operator<(const struct Info& arg) const{

		return value < arg.value;
	}
	void set(ll arg_value,ll arg_index){
		value = arg_value;
		index = arg_index;
	}
	ll value,index;
};

struct DATA{
	bool operator<(const struct DATA &arg) const{

		return y < arg.y;
	}
	void set(ll arg_x,ll arg_y,ll arg_input_index){
		x = arg_x;
		y = arg_y;
		input_index = arg_input_index;
	}
	ll x,y,input_index;
};

struct Point{

	ll x,y,input_index;
};

struct Edge{
	Edge(int arg_a,int arg_b,ll arg_cost){
		a = arg_a;
		b = arg_b;
		cost = arg_cost;
	}
	bool operator<(const struct Edge& arg) const{

		return cost < arg.cost;
	}
	int a,b;
	ll cost;
};

int N;
int boss[SIZE],height[SIZE],num_member[SIZE];
int INDEX[SIZE];
DATA D[SIZE];
Info table[6*SIZE];
Point point[SIZE];
vector<Edge> edge;


void init(int first_N){
	N = 1;
	while(N < first_N)N *= 2;
}

void update(int loc,ll value,ll index){
	loc += N-1;

	if(table[loc].value <= value){

		return;
	}
	table[loc].set(value,index);

	if(N == 1)return;

	int parent = (loc-1)/2;

	while(true){

		int L = 2*parent+1,R = 2*parent+2;
		table[parent] = min(table[L],table[R]);

		if(parent == 0)break;
		else{
			parent = (parent-1)/2;
		}
	}
}


Info query(int search_left,int search_right,int node_id,int node_left,int node_right){

	Info ret;

	//今回のノードが検索区間をカバーしていなければ、結果に関係ない値を返す
	if(search_right < node_left || search_left > node_right){

		ret.set(HUGE_NUM,-1);
		return ret;
	}

	//今回のノードの区間が、検索区間の部分区間である場合、今回のノードの値を返す
	if(search_left <= node_left && search_right >= node_right){
		return table[node_id];
	}

	//今回のノードの区間に、一部検索区間と重なっている区間がある場合→再帰的に子どもに尋ねる
	Info left_min = query(search_left,search_right,2*node_id+1,node_left,(node_left+node_right)/2);
	Info right_min = query(search_left,search_right,2*node_id+2,(node_left+node_right)/2+1,node_right);

	return min(left_min,right_min);
}

int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

int isSame(int x,int y){
	return get_boss(x) == get_boss(y);
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[boss_x] > height[boss_y]){

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;

	}else if(height[boss_x] < height[boss_y]){

		num_member[boss_y] += num_member[boss_x];
		boss[boss_x] = boss_y;

	}else{ //height[boss_x] == height[boss_y]

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;
		height[x]++;
	}
}


int main(){

	int first_N;

	scanf("%d",&first_N);

	init(first_N);

	for(int i = 0; i < first_N; i++){

		scanf("%lld %lld",&point[i].x,&point[i].y);
		point[i].input_index = i;
	}

	for(int a = 0; a <= 1; a++){
		for(int b = 0; b <= 1; b++){
			for(int c = 0; c <= 1; c++){
				for(int i = 0; i <= 2*N-2; i++){

					table[i].value = HUGE_NUM;
				}

				std::vector<int> IND(first_N);
				std::iota(IND.begin(), IND.end(), 0);

				std::sort(IND.begin(), IND.end(), [&](int i, int j) {
					if(point[i].y-point[i].x != point[j].y-point[j].x){

						return point[i].y-point[i].x < point[j].y-point[j].x;
					}else if(point[i].y != point[j].y){

						return point[i].y > point[j].y;
					}else{

						//if(a == 0){
							return i > j;
						/*}else{

							return i < j;
						}*/
					}
				});

				//y座標sort(セグ木用)
				/*for(int i = 0; i < first_N; i++){

					D[i].set(point[i].x,point[i].y,point[i].input_index);
				}
				sort(D,D+first_N);
				for(int i = 0; i < first_N; i++){

					INDEX[D[i].input_index] = i;
				}*/

				vector<ll> vec_Y;
				for(int i = 0; i < first_N; i++){

					vec_Y.push_back(point[i].y);
				}
				sort(vec_Y.begin(),vec_Y.end());
				vec_Y.erase(unique(vec_Y.begin(),vec_Y.end()),vec_Y.end());

				map<ll,ll> MAP;
				for(int i = 0; i < vec_Y.size(); i++){

					MAP[vec_Y[i]] = i;
				}

				for(int i = 0; i < first_N; i++){

					Info ret = query(MAP[point[IND[i]].y],first_N,0,0,N-1); //y座標が自分以上のデータの、x+yの最小値を取得
					if(ret.value != HUGE_NUM){


						//edge.push_back(Edge(IND[i],ret.index,abs(point[IND[i]].x-point[ret.index].x)+abs(point[IND[i]].y-point[ret.index].y)));
						edge.push_back(Edge(IND[i],ret.index,max(abs(point[IND[i]].x-point[ret.index].x),abs(point[IND[i]].y-point[ret.index].y))));
					}
					update(MAP[point[IND[i]].y],point[IND[i]].x+point[IND[i]].y,IND[i]);
				}

				for(int i = 0; i < first_N; i++){
					swap(point[i].x,point[i].y);
				}
			}
			for(int i = 0; i < first_N; i++){

				point[i].x *= -1;
			}
		}
		for(int i = 0; i < first_N; i++){

			point[i].y *= -1;
		}
	}
	for(int i = 0; i < first_N; i++){

		boss[i] = i;
		height[i] = 0;
		num_member[i] = 1;
	}

	sort(edge.begin(),edge.end());

	ll ans = 0;

	vector<Edge> ANS;

	for(int i = 0; i < edge.size(); i++){
		if(isSame(edge[i].a,edge[i].b))continue;

		unite(edge[i].a,edge[i].b);
		ANS.push_back(edge[i]);
		ans += edge[i].cost;
	}

	printf("%lld\n",ans);

	return 0;
}
accuracy: 0.359375
time_ms: 20
memory_kb: 4420
final_rank: 14

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 200005

struct Info{
	bool operator<(const struct Info& arg) const{

		return value < arg.value;
	}
	void set(ll arg_value,ll arg_index){
		value = arg_value;
		V.push_back(arg_index);
	}
	ll value;
	vector<int> V;
};

struct DATA{
	bool operator<(const struct DATA &arg) const{

		return y < arg.y;
	}
	void set(ll arg_x,ll arg_y,ll arg_input_index){
		x = arg_x;
		y = arg_y;
		input_index = arg_input_index;
	}
	ll x,y,input_index;
};

struct Point{

	ll x,y,input_index;
};

struct Edge{
	Edge(int arg_a,int arg_b,ll arg_cost){
		a = arg_a;
		b = arg_b;
		cost = arg_cost;
	}
	bool operator<(const struct Edge& arg) const{

		return cost < arg.cost;
	}
	int a,b;
	ll cost;
};

int N;
int boss[SIZE],height[SIZE],num_member[SIZE];
int INDEX[SIZE];
DATA D[SIZE];
Info table[6*SIZE];
Point point[SIZE];
vector<Edge> edge;


void init(int first_N){
	N = 1;
	while(N < first_N)N *= 2;
}

void update(int loc,ll value,ll index){
	loc += N-1;

	table[loc].set(value,index);

	if(N == 1)return;

	int parent = (loc-1)/2;

	while(true){

		int L = 2*parent+1,R = 2*parent+2;
		if(table[L].value < table[R].value){

			table[parent] = table[L];
		}else if(table[L].value > table[R].value){

			table[parent] = table[R];
		}else{

			for(int i = 0; i < table[R].V.size(); i++){

				table[L].V.push_back(table[R].V[i]);
			}
			table[parent] = table[L];
		}

		if(parent == 0)break;
		else{
			parent = (parent-1)/2;
		}
	}
}


Info query(int search_left,int search_right,int node_id,int node_left,int node_right){

	Info ret;

	//今回のノードが検索区間をカバーしていなければ、結果に関係ない値を返す
	if(search_right < node_left || search_left > node_right){

		ret.set(HUGE_NUM,-1);
		return ret;
	}

	//今回のノードの区間が、検索区間の部分区間である場合、今回のノードの値を返す
	if(search_left <= node_left && search_right >= node_right){
		return table[node_id];
	}

	//今回のノードの区間に、一部検索区間と重なっている区間がある場合→再帰的に子どもに尋ねる
	Info left_min = query(search_left,search_right,2*node_id+1,node_left,(node_left+node_right)/2);
	Info right_min = query(search_left,search_right,2*node_id+2,(node_left+node_right)/2+1,node_right);

	if(left_min.value < right_min.value){

		return left_min;
	}else if(left_min.value > right_min.value){

		return right_min;
	}else{

		if(right_min.value != HUGE_NUM){

			for(int i = 0; i < right_min.V.size(); i++){

				left_min.V.push_back(right_min.V[i]);
			}
		}
		return left_min;
	}
}

int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

int isSame(int x,int y){
	return get_boss(x) == get_boss(y);
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[boss_x] > height[boss_y]){

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;

	}else if(height[boss_x] < height[boss_y]){

		num_member[boss_y] += num_member[boss_x];
		boss[boss_x] = boss_y;

	}else{ //height[boss_x] == height[boss_y]

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;
		height[x]++;
	}
}


int main(){

	int first_N;

	scanf("%d",&first_N);

	init(first_N);

	for(int i = 0; i < first_N; i++){

		scanf("%lld %lld",&point[i].x,&point[i].y);
		point[i].input_index = i;
	}

	for(int a = 0; a <= 1; a++){
		for(int b = 0; b <= 1; b++){
			for(int c = 0; c <= 1; c++){
				for(int i = 0; i <= 2*N-2; i++){

					table[i].value = HUGE_NUM;
				}

				std::vector<int> IND(first_N);
				std::iota(IND.begin(), IND.end(), 0);

				std::sort(IND.begin(), IND.end(), [&](int i, int j) {
					if(point[i].y-point[i].x != point[j].y-point[j].x){

						return point[i].y-point[i].x < point[j].y-point[j].x;
					}else if(point[i].y != point[j].y){

						return point[i].y > point[j].y;
					}else{

						//if(a == 0){
							return i > j;
						/*}else{

							return i < j;
						}*/
					}
				});

				//y座標sort(セグ木用)
				for(int i = 0; i < first_N; i++){

					D[i].set(point[i].x,point[i].y,point[i].input_index);
				}
				sort(D,D+first_N);
				for(int i = 0; i < first_N; i++){

					INDEX[D[i].input_index] = i;
				}

				for(int i = 0; i < first_N; i++){

					Info ret = query(INDEX[IND[i]],first_N,0,0,N-1); //y座標が自分以上のデータの、x+yの最小値を取得
					if(ret.value != HUGE_NUM){


						//edge.push_back(Edge(IND[i],ret.index,abs(point[IND[i]].x-point[ret.index].x)+abs(point[IND[i]].y-point[ret.index].y)));
						for(int k = 0; k < ret.V.size(); k++){

							edge.push_back(Edge(IND[i],ret.V[k],max(abs(point[IND[i]].x-point[ret.V[k]].x),abs(point[IND[i]].y-point[ret.V[k]].y))));
						}
						//edge.push_back(Edge(IND[i],ret.index,max(abs(point[IND[i]].x-point[ret.index].x),abs(point[IND[i]].y-point[ret.index].y))));
					}
					update(INDEX[IND[i]],point[IND[i]].x+point[IND[i]].y,IND[i]);
				}

				for(int i = 0; i < first_N; i++){
					swap(point[i].x,point[i].y);
				}
			}
			for(int i = 0; i < first_N; i++){

				point[i].x *= -1;
			}
		}
		for(int i = 0; i < first_N; i++){

			point[i].y *= -1;
		}
	}
	for(int i = 0; i < first_N; i++){

		boss[i] = i;
		height[i] = 0;
		num_member[i] = 1;
	}

	sort(edge.begin(),edge.end());

	ll ans = 0;

	vector<Edge> ANS;

	for(int i = 0; i < edge.size(); i++){
		if(isSame(edge[i].a,edge[i].b))continue;

		unite(edge[i].a,edge[i].b);
		ANS.push_back(edge[i]);
		ans += edge[i].cost;
	}

	printf("%lld\n",ans);
	/*for(int i = 0; i < ANS.size(); i++){

		printf("%d %d\n",ANS[i].a,ANS[i].b);
	}*/
	return 0;
}
accuracy: 0.65625
time_ms: 80
memory_kb: 46136
final_rank: 9

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 200005

struct Info{
	bool operator<(const struct Info& arg) const{

		return value < arg.value;
	}
	void set(ll arg_value,ll arg_index){
		value = arg_value;
		V.push_back(arg_index);
	}
	ll value;
	vector<int> V;
};

struct DATA{
	bool operator<(const struct DATA &arg) const{

		return y < arg.y;
	}
	void set(ll arg_x,ll arg_y,ll arg_input_index){
		x = arg_x;
		y = arg_y;
		input_index = arg_input_index;
	}
	ll x,y,input_index;
};

struct Point{

	ll x,y,input_index;
};

struct Edge{
	Edge(int arg_a,int arg_b,ll arg_cost){
		a = arg_a;
		b = arg_b;
		cost = arg_cost;
	}
	bool operator<(const struct Edge& arg) const{

		return cost < arg.cost;
	}
	int a,b;
	ll cost;
};

int N;
int boss[SIZE],height[SIZE],num_member[SIZE];
int INDEX[SIZE];
DATA D[SIZE];
Info table[6*SIZE];
Point point[SIZE];
vector<Edge> edge;


void init(int first_N){
	N = 1;
	while(N < first_N)N *= 2;
}

void update(int loc,ll value,ll index){
	loc += N-1;

	table[loc].set(value,index);

	if(N == 1)return;

	int parent = (loc-1)/2;

	while(true){

		int L = 2*parent+1,R = 2*parent+2;
		if(table[L].value < table[R].value){

			table[parent] = table[L];
		}else if(table[L].value > table[R].value){

			table[parent] = table[R];
		}else{

			for(int i = 0; i < table[R].V.size(); i++){

				table[L].V.push_back(table[R].V[i]);
			}
			table[parent] = table[L];
		}

		if(parent == 0)break;
		else{
			parent = (parent-1)/2;
		}
	}
}


Info query(int search_left,int search_right,int node_id,int node_left,int node_right){

	Info ret;

	//今回のノードが検索区間をカバーしていなければ、結果に関係ない値を返す
	if(search_right < node_left || search_left > node_right){

		ret.set(HUGE_NUM,-1);
		return ret;
	}

	//今回のノードの区間が、検索区間の部分区間である場合、今回のノードの値を返す
	if(search_left <= node_left && search_right >= node_right){
		return table[node_id];
	}

	//今回のノードの区間に、一部検索区間と重なっている区間がある場合→再帰的に子どもに尋ねる
	Info left_min = query(search_left,search_right,2*node_id+1,node_left,(node_left+node_right)/2);
	Info right_min = query(search_left,search_right,2*node_id+2,(node_left+node_right)/2+1,node_right);

	if(left_min.value < right_min.value){

		return left_min;
	}else if(left_min.value > right_min.value){

		return right_min;
	}else{

		if(right_min.value != HUGE_NUM){

			for(int i = 0; i < right_min.V.size(); i++){

				left_min.V.push_back(right_min.V[i]);
			}
		}
		return left_min;
	}
}

int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

int isSame(int x,int y){
	return get_boss(x) == get_boss(y);
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[boss_x] > height[boss_y]){

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;

	}else if(height[boss_x] < height[boss_y]){

		num_member[boss_y] += num_member[boss_x];
		boss[boss_x] = boss_y;

	}else{ //height[boss_x] == height[boss_y]

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;
		height[x]++;
	}
}


int main(){

	int first_N;

	scanf("%d",&first_N);

	init(first_N);

	for(int i = 0; i < first_N; i++){

		scanf("%lld %lld",&point[i].x,&point[i].y);
		point[i].input_index = i;
	}

	for(int a = 0; a <= 1; a++){
		for(int b = 0; b <= 1; b++){
			for(int c = 0; c <= 1; c++){
				for(int i = 0; i <= 2*N-2; i++){

					table[i].value = HUGE_NUM;
				}

				std::vector<int> IND(first_N);
				std::iota(IND.begin(), IND.end(), 0);

				std::sort(IND.begin(), IND.end(), [&](int i, int j) {
					if(point[i].y-point[i].x != point[j].y-point[j].x){

						return point[i].y-point[i].x < point[j].y-point[j].x;
					}else if(point[i].y != point[j].y){

						return point[i].y > point[j].y;
					}else{

						if(a == 0){
							return i > j;
						}else{

							return i < j;
						}
					}
				});

				//y座標sort(セグ木用)
				for(int i = 0; i < first_N; i++){

					D[i].set(point[i].x,point[i].y,point[i].input_index);
				}
				sort(D,D+first_N);
				for(int i = 0; i < first_N; i++){

					INDEX[D[i].input_index] = i;
				}

				for(int i = 0; i < first_N; i++){

					Info ret = query(INDEX[IND[i]],first_N,0,0,N-1); //y座標が自分以上のデータの、x+yの最小値を取得
					if(ret.value != HUGE_NUM){


						//edge.push_back(Edge(IND[i],ret.index,abs(point[IND[i]].x-point[ret.index].x)+abs(point[IND[i]].y-point[ret.index].y)));
						for(int k = 0; k < ret.V.size(); k++){

							edge.push_back(Edge(IND[i],ret.V[k],max(abs(point[IND[i]].x-point[ret.V[k]].x),abs(point[IND[i]].y-point[ret.V[k]].y))));
						}
						//edge.push_back(Edge(IND[i],ret.index,max(abs(point[IND[i]].x-point[ret.index].x),abs(point[IND[i]].y-point[ret.index].y))));
					}
					update(INDEX[IND[i]],point[IND[i]].x+point[IND[i]].y,IND[i]);
				}

				for(int i = 0; i < first_N; i++){
					swap(point[i].x,point[i].y);
				}
			}
			for(int i = 0; i < first_N; i++){

				point[i].x *= -1;
			}
		}
		for(int i = 0; i < first_N; i++){

			point[i].y *= -1;
		}
	}
	for(int i = 0; i < first_N; i++){

		boss[i] = i;
		height[i] = 0;
		num_member[i] = 1;
	}

	sort(edge.begin(),edge.end());

	ll ans = 0;

	vector<Edge> ANS;

	for(int i = 0; i < edge.size(); i++){
		if(isSame(edge[i].a,edge[i].b))continue;

		unite(edge[i].a,edge[i].b);
		ANS.push_back(edge[i]);
		ans += edge[i].cost;
	}

	printf("%lld\n",ans);
	/*for(int i = 0; i < ANS.size(); i++){

		printf("%d %d\n",ANS[i].a,ANS[i].b);
	}*/
	return 0;
}
accuracy: 0.65625
time_ms: 80
memory_kb: 46000
final_rank: 8

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 200005

struct Info{
	bool operator<(const struct Info& arg) const{

		if(value != arg.value){
			return value < arg.value;
		}else{

			return index < arg.index;
		}
	}
	void set(ll arg_value,ll arg_index){
		value = arg_value;
		index = arg_index;
	}
	ll value,index;
};

struct DATA{
	bool operator<(const struct DATA &arg) const{

		return y < arg.y;
	}
	void set(ll arg_x,ll arg_y,ll arg_input_index){
		x = arg_x;
		y = arg_y;
		input_index = arg_input_index;
	}
	ll x,y,input_index;
};

struct Point{

	ll x,y,input_index;
};

struct Edge{
	Edge(int arg_a,int arg_b,ll arg_cost){
		a = arg_a;
		b = arg_b;
		cost = arg_cost;
	}
	bool operator<(const struct Edge& arg) const{

		return cost < arg.cost;
	}
	int a,b;
	ll cost;
};

int N;
int boss[SIZE],height[SIZE],num_member[SIZE];
int INDEX[SIZE];
DATA D[SIZE];
Info table[6*SIZE];
Point point[SIZE];
vector<Edge> edge;


void init(int first_N){
	N = 1;
	while(N < first_N)N *= 2;
}

void update(int loc,ll value,ll index){
	loc += N-1;

	table[loc].set(value,index);

	if(N == 1)return;

	int parent = (loc-1)/2;

	while(true){

		table[parent] = min(table[2*parent+1],table[2*parent+2]);

		if(parent == 0)break;
		else{
			parent = (parent-1)/2;
		}
	}
}


Info query(int search_left,int search_right,int node_id,int node_left,int node_right){

	Info ret;

	//今回のノードが検索区間をカバーしていなければ、結果に関係ない値を返す
	if(search_right < node_left || search_left > node_right){

		ret.set(HUGE_NUM,-1);
		return ret;
	}

	//今回のノードの区間が、検索区間の部分区間である場合、今回のノードの値を返す
	if(search_left <= node_left && search_right >= node_right){
		return table[node_id];
	}

	//今回のノードの区間に、一部検索区間と重なっている区間がある場合→再帰的に子どもに尋ねる
	Info left_min = query(search_left,search_right,2*node_id+1,node_left,(node_left+node_right)/2);
	Info right_min = query(search_left,search_right,2*node_id+2,(node_left+node_right)/2+1,node_right);

	return min(left_min,right_min);
}

int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

int isSame(int x,int y){
	return get_boss(x) == get_boss(y);
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[boss_x] > height[boss_y]){

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;

	}else if(height[boss_x] < height[boss_y]){

		num_member[boss_y] += num_member[boss_x];
		boss[boss_x] = boss_y;

	}else{ //height[boss_x] == height[boss_y]

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;
		height[x]++;
	}
}


int main(){

	int first_N;

	scanf("%d",&first_N);

	init(first_N);

	for(int i = 0; i < first_N; i++){

		scanf("%lld %lld",&point[i].x,&point[i].y);
		point[i].input_index = i;
	}


	int count = 0;

	for(int a = 0; a <= 1; a++){
		for(int b = 0; b <= 1; b++){
			for(int c = 0; c <= 1; c++){
				for(int i = 0; i <= 2*N-2; i++){

					table[i].value = HUGE_NUM;
				}

				std::vector<int> IND(first_N);
				std::iota(IND.begin(), IND.end(), 0);

				std::sort(IND.begin(), IND.end(), [&](int i, int j) {
					if(point[i].y-point[i].x != point[j].y-point[j].x){

						return point[i].y-point[i].x < point[j].y-point[j].x;
					}else if(point[i].y != point[j].y){

						return point[i].y > point[j].y;
					}else{

						return i > j;
					}
				});

				//y座標sort(セグ木用)
				for(int i = 0; i < first_N; i++){

					D[i].set(point[i].x,point[i].y,point[i].input_index);
				}
				sort(D,D+first_N);
				for(int i = 0; i < first_N; i++){

					INDEX[D[i].input_index] = i;
				}

				for(int i = 0; i < first_N; i++){

					Info ret = query(INDEX[IND[i]],first_N,0,0,N-1); //y座標が自分以上のデータの、x+yの最小値を取得
					if(ret.value != HUGE_NUM){


						//edge.push_back(Edge(IND[i],ret.index,abs(point[IND[i]].x-point[ret.index].x)+abs(point[IND[i]].y-point[ret.index].y)));
						edge.push_back(Edge(IND[i],ret.index,max(abs(point[IND[i]].x-point[ret.index].x),abs(point[IND[i]].y-point[ret.index].y))));
					}
					update(INDEX[IND[i]],point[IND[i]].x+point[IND[i]].y,IND[i]);
				}

				for(int i = 0; i < first_N; i++){
					swap(point[i].x,point[i].y);
				}

				count++;
			}
			for(int i = 0; i < first_N; i++){

				point[i].x *= -1;
			}
		}
		for(int i = 0; i < first_N; i++){

			point[i].y *= -1;
		}
	}

	for(int i = 0; i < first_N; i++){

		boss[i] = i;
		height[i] = 0;
		num_member[i] = 1;
	}

	sort(edge.begin(),edge.end());

	ll ans = 0;

	vector<Edge> ANS;

	for(int i = 0; i < edge.size(); i++){
		if(isSame(edge[i].a,edge[i].b))continue;

		unite(edge[i].a,edge[i].b);
		ANS.push_back(edge[i]);
		ans += edge[i].cost;
	}

	printf("%lld\n",ans);
	/*for(int i = 0; i < ANS.size(); i++){

		printf("%d %d\n",ANS[i].a,ANS[i].b);
	}*/
	return 0;
}
accuracy: 0.40625
time_ms: 20
memory_kb: 4768
final_rank: 10

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 200005

struct Info{
	bool operator<(const struct Info& arg) const{

		if(value != arg.value){
			return value < arg.value;
		}else{

			return index < arg.index;
		}
	}
	void set(ll arg_value,ll arg_index){
		value = arg_value;
		index = arg_index;
	}
	ll value,index;
};

struct DATA{
	bool operator<(const struct DATA &arg) const{

		return y < arg.y;
	}
	void set(ll arg_x,ll arg_y,ll arg_input_index){
		x = arg_x;
		y = arg_y;
		input_index = arg_input_index;
	}
	ll x,y,input_index;
};

struct Point{

	ll x,y,input_index;
};

struct Edge{
	Edge(int arg_a,int arg_b,ll arg_cost){
		a = arg_a;
		b = arg_b;
		cost = arg_cost;
	}
	bool operator<(const struct Edge& arg) const{

		return cost < arg.cost;
	}
	int a,b;
	ll cost;
};

int N;
int boss[SIZE],height[SIZE],num_member[SIZE];
int INDEX[SIZE];
DATA D[SIZE];
Info table[6*SIZE];
Point point[SIZE];
vector<Edge> edge;


void init(int first_N){
	N = 1;
	while(N < first_N)N *= 2;
}

void update(int loc,ll value,ll index){
	loc += N-1;

	table[loc].set(value,index);

	if(N == 1)return;

	int parent = (loc-1)/2;

	while(true){

		table[parent] = min(table[2*parent+1],table[2*parent+2]);

		if(parent == 0)break;
		else{
			parent = (parent-1)/2;
		}
	}
}


Info query(int search_left,int search_right,int node_id,int node_left,int node_right){

	Info ret;

	//今回のノードが検索区間をカバーしていなければ、結果に関係ない値を返す
	if(search_right < node_left || search_left > node_right){

		ret.set(HUGE_NUM,-1);
		return ret;
	}

	//今回のノードの区間が、検索区間の部分区間である場合、今回のノードの値を返す
	if(search_left <= node_left && search_right >= node_right){
		return table[node_id];
	}

	//今回のノードの区間に、一部検索区間と重なっている区間がある場合→再帰的に子どもに尋ねる
	Info left_min = query(search_left,search_right,2*node_id+1,node_left,(node_left+node_right)/2);
	Info right_min = query(search_left,search_right,2*node_id+2,(node_left+node_right)/2+1,node_right);

	return min(left_min,right_min);
}

int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

int isSame(int x,int y){
	return get_boss(x) == get_boss(y);
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[boss_x] > height[boss_y]){

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;

	}else if(height[boss_x] < height[boss_y]){

		num_member[boss_y] += num_member[boss_x];
		boss[boss_x] = boss_y;

	}else{ //height[boss_x] == height[boss_y]

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;
		height[x]++;
	}
}


int main(){

	int first_N;

	scanf("%d",&first_N);

	init(first_N);

	for(int i = 0; i < first_N; i++){

		scanf("%lld %lld",&point[i].x,&point[i].y);
		point[i].input_index = i;
	}


	int count = 0;

	for(int a = 0; a <= 1; a++){
		for(int b = 0; b <= 1; b++){
			for(int c = 0; c <= 1; c++){
				for(int i = 0; i <= 2*N-2; i++){

					table[i].value = HUGE_NUM;
				}

				std::vector<int> IND(first_N);
				std::iota(IND.begin(), IND.end(), 0);

				std::sort(IND.begin(), IND.end(), [&](int i, int j) {
					if(point[i].y-point[i].x != point[j].y-point[j].x){

						return point[i].y-point[i].x < point[j].y-point[j].x;
					}else if(point[i].y != point[j].y){

						return point[i].y > point[j].y;
					}else{

						if(count%2 == 0){

							return i < j;
						}else{

							return i > j;
						}
					}
				});

				//y座標sort(セグ木用)
				for(int i = 0; i < first_N; i++){

					D[i].set(point[i].x,point[i].y,point[i].input_index);
				}
				sort(D,D+first_N);
				for(int i = 0; i < first_N; i++){

					INDEX[D[i].input_index] = i;
				}

				for(int i = 0; i < first_N; i++){

					Info ret = query(INDEX[IND[i]],first_N,0,0,N-1); //y座標が自分以上のデータの、x+yの最小値を取得
					if(ret.value != HUGE_NUM){


						//edge.push_back(Edge(IND[i],ret.index,abs(point[IND[i]].x-point[ret.index].x)+abs(point[IND[i]].y-point[ret.index].y)));
						edge.push_back(Edge(IND[i],ret.index,max(abs(point[IND[i]].x-point[ret.index].x),abs(point[IND[i]].y-point[ret.index].y))));
					}
					update(INDEX[IND[i]],point[IND[i]].x+point[IND[i]].y,IND[i]);
				}

				for(int i = 0; i < first_N; i++){
					swap(point[i].x,point[i].y);
				}

				count++;
			}
			for(int i = 0; i < first_N; i++){

				point[i].x *= -1;
			}
		}
		for(int i = 0; i < first_N; i++){

			point[i].y *= -1;
		}
	}

	for(int i = 0; i < first_N; i++){

		boss[i] = i;
		height[i] = 0;
		num_member[i] = 1;
	}

	sort(edge.begin(),edge.end());

	ll ans = 0;

	vector<Edge> ANS;

	for(int i = 0; i < edge.size(); i++){
		if(isSame(edge[i].a,edge[i].b))continue;

		unite(edge[i].a,edge[i].b);
		ANS.push_back(edge[i]);
		ans += edge[i].cost;
	}

	printf("%lld\n",ans);
	/*for(int i = 0; i < ANS.size(); i++){

		printf("%d %d\n",ANS[i].a,ANS[i].b);
	}*/
	return 0;
}
accuracy: 0.40625
time_ms: 20
memory_kb: 4828
final_rank: 11

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 200005

struct Info{
	bool operator<(const struct Info& arg) const{

		if(value != arg.value){
			return value < arg.value;
		}else{

			return index < arg.index;
		}
	}
	void set(ll arg_value,ll arg_index){
		value = arg_value;
		index = arg_index;
	}
	ll value,index;
};

struct Input{
	ll x,y;
};

struct DATA{
	bool operator<(const struct DATA &arg) const{

		return y < arg.y;
	}
	void set(ll arg_x,ll arg_y,ll arg_input_index){
		x = arg_x;
		y = arg_y;
		input_index = arg_input_index;
	}
	ll x,y,input_index;
};

struct Point{
	void set(ll arg_x,ll arg_y,ll arg_input_index,ll arg_now_index){
		x = arg_x;
		y = arg_y;
		input_index = arg_input_index;
	}
	bool operator<(const struct Point &arg) const{
		if(y-x != arg.y-arg.x){

			return (y-x) < (arg.y-arg.x);
		}else if(y != arg.y){

			return y > arg.y;
		}else{

			return input_index > arg.input_index;
		}
	}
	ll x,y,input_index;
};

struct Edge{
	Edge(int arg_a,int arg_b,ll arg_cost){
		a = arg_a;
		b = arg_b;
		cost = arg_cost;
	}
	bool operator<(const struct Edge& arg) const{

		return cost < arg.cost;
	}
	int a,b;
	ll cost;
};

int N;
int boss[SIZE],height[SIZE],num_member[SIZE];
int INDEX[SIZE];
DATA D[SIZE];
Info table[6*SIZE];
Input input[SIZE];
Point point[SIZE];
vector<Edge> edge;


void init(int first_N){
	N = 1;
	while(N < first_N)N *= 2;
}

void update(int loc,ll value,ll index){
	loc += N-1;

	table[loc].set(value,index);

	if(N == 1)return;

	int parent = (loc-1)/2;

	while(true){

		table[parent] = min(table[2*parent+1],table[2*parent+2]);

		if(parent == 0)break;
		else{
			parent = (parent-1)/2;
		}
	}
}


Info query(int search_left,int search_right,int node_id,int node_left,int node_right){

	Info ret;

	//今回のノードが検索区間をカバーしていなければ、結果に関係ない値を返す
	if(search_right < node_left || search_left > node_right){

		ret.set(HUGE_NUM,-1);
		return ret;
	}

	//今回のノードの区間が、検索区間の部分区間である場合、今回のノードの値を返す
	if(search_left <= node_left && search_right >= node_right){
		return table[node_id];
	}

	//今回のノードの区間に、一部検索区間と重なっている区間がある場合→再帰的に子どもに尋ねる
	Info left_min = query(search_left,search_right,2*node_id+1,node_left,(node_left+node_right)/2);
	Info right_min = query(search_left,search_right,2*node_id+2,(node_left+node_right)/2+1,node_right);

	return min(left_min,right_min);
}

int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

int isSame(int x,int y){
	return get_boss(x) == get_boss(y);
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[boss_x] > height[boss_y]){

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;

	}else if(height[boss_x] < height[boss_y]){

		num_member[boss_y] += num_member[boss_x];
		boss[boss_x] = boss_y;

	}else{ //height[boss_x] == height[boss_y]

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;
		height[x]++;
	}
}


int main(){

	int first_N;

	scanf("%d",&first_N);

	init(first_N);

	for(int i = 0; i < first_N; i++){

		scanf("%lld %lld",&input[i].x,&input[i].y);
		point[i].set(input[i].x,input[i].y,i,i);
	}


	for(int a = 0; a <= 1; a++){
		for(int b = 0; b <= 1; b++){
			for(int c = 0; c <= 1; c++){
				for(int i = 0; i <= 2*N-2; i++){

					table[i].value = HUGE_NUM;
				}

				std::vector<int> IND(first_N);
				std::iota(IND.begin(), IND.end(), 0);

				std::sort(IND.begin(), IND.end(), [&](int i, int j) {
				  return (point[i].y - point[i].x < point[j].y - point[j].x) ||
						 (point[i].y - point[i].x == point[j].y - point[j].x && point[i].y > point[j].y) ||
						 (point[i].y - point[i].x == point[j].y - point[j].x && point[i].y == point[j].y && i > j);
				});

				//y座標sort(セグ木用)
				for(int i = 0; i < first_N; i++){

					D[i].set(point[i].x,point[i].y,point[i].input_index);
				}
				sort(D,D+first_N);
				for(int i = 0; i < first_N; i++){

					INDEX[D[i].input_index] = i;
				}

				for(int i = 0; i < first_N; i++){

					Info ret = query(INDEX[IND[i]],first_N,0,0,N-1); //y座標が自分以上のデータの、x+yの最小値を取得
					if(ret.value != HUGE_NUM){


						//edge.push_back(Edge(IND[i],ret.index,abs(point[IND[i]].x-point[ret.index].x)+abs(point[IND[i]].y-point[ret.index].y)));
						edge.push_back(Edge(IND[i],ret.index,max(abs(point[IND[i]].x-point[ret.index].x),abs(point[IND[i]].y-point[ret.index].y))));
					}
					update(INDEX[IND[i]],point[IND[i]].x+point[IND[i]].y,IND[i]);
				}

				for(int i = 0; i < first_N; i++){
					swap(point[i].x,point[i].y);
				}
			}
			for(int i = 0; i < first_N; i++){

				point[i].x *= -1;
			}
		}
		for(int i = 0; i < first_N; i++){

			point[i].y *= -1;
		}
	}

	for(int i = 0; i < first_N; i++){

		boss[i] = i;
		height[i] = 0;
		num_member[i] = 1;
	}

	sort(edge.begin(),edge.end());

	ll ans = 0;

	vector<Edge> ANS;

	for(int i = 0; i < edge.size(); i++){
		if(isSame(edge[i].a,edge[i].b))continue;

		unite(edge[i].a,edge[i].b);
		ANS.push_back(edge[i]);
		ans += edge[i].cost;
	}

	printf("%lld\n",ans);
	/*for(int i = 0; i < ANS.size(); i++){

		printf("%d %d\n",ANS[i].a,ANS[i].b);
	}*/
	return 0;
}
accuracy: 0.40625
time_ms: 20
memory_kb: 4900
final_rank: 12

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 200005

struct Info{
	bool operator<(const struct Info& arg) const{

		if(value != arg.value){
			return value < arg.value;
		}else{

			return index > arg.index;
		}
	}
	void set(ll arg_value,ll arg_index){
		value = arg_value;
		index = arg_index;
	}
	ll value,index;
};

struct Input{
	ll x,y;
};

struct DATA{
	bool operator<(const struct DATA &arg) const{

		return y < arg.y;
	}
	void set(ll arg_x,ll arg_y,ll arg_input_index){
		x = arg_x;
		y = arg_y;
		input_index = arg_input_index;
	}
	ll x,y,input_index;
};

struct Point{
	void set(ll arg_x,ll arg_y,ll arg_input_index,ll arg_now_index){
		x = arg_x;
		y = arg_y;
		input_index = arg_input_index;
	}
	bool operator<(const struct Point &arg) const{
		if(y-x != arg.y-arg.x){

			return (y-x) < (arg.y-arg.x);
		}else if(y != arg.y){

			return y > arg.y;
		}else{

			return input_index > arg.input_index;
		}
	}
	ll x,y,input_index;
};

struct Edge{
	Edge(int arg_a,int arg_b,ll arg_cost){
		a = arg_a;
		b = arg_b;
		cost = arg_cost;
	}
	bool operator<(const struct Edge& arg) const{

		return cost < arg.cost;
	}
	int a,b;
	ll cost;
};

int N;
int boss[SIZE],height[SIZE],num_member[SIZE];
int INDEX[SIZE];
DATA D[SIZE];
Info table[6*SIZE];
Input input[SIZE];
Point point[SIZE];
vector<Edge> edge;


void init(int first_N){
	N = 1;
	while(N < first_N)N *= 2;
}

void update(int loc,ll value,ll index){
	loc += N-1;

	table[loc].set(value,index);

	if(N == 1)return;

	int parent = (loc-1)/2;

	while(true){

		table[parent] = min(table[2*parent+1],table[2*parent+2]);

		if(parent == 0)break;
		else{
			parent = (parent-1)/2;
		}
	}
}


Info query(int search_left,int search_right,int node_id,int node_left,int node_right){

	Info ret;

	//今回のノードが検索区間をカバーしていなければ、結果に関係ない値を返す
	if(search_right < node_left || search_left > node_right){

		ret.set(HUGE_NUM,-1);
		return ret;
	}

	//今回のノードの区間が、検索区間の部分区間である場合、今回のノードの値を返す
	if(search_left <= node_left && search_right >= node_right){
		return table[node_id];
	}

	//今回のノードの区間に、一部検索区間と重なっている区間がある場合→再帰的に子どもに尋ねる
	Info left_min = query(search_left,search_right,2*node_id+1,node_left,(node_left+node_right)/2);
	Info right_min = query(search_left,search_right,2*node_id+2,(node_left+node_right)/2+1,node_right);

	return min(left_min,right_min);
}

int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

int isSame(int x,int y){
	return get_boss(x) == get_boss(y);
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[boss_x] > height[boss_y]){

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;

	}else if(height[boss_x] < height[boss_y]){

		num_member[boss_y] += num_member[boss_x];
		boss[boss_x] = boss_y;

	}else{ //height[boss_x] == height[boss_y]

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;
		height[x]++;
	}
}


int main(){

	int first_N;

	scanf("%d",&first_N);

	init(first_N);

	for(int i = 0; i < first_N; i++){

		scanf("%lld %lld",&input[i].x,&input[i].y);
		point[i].set(input[i].x,input[i].y,i,i);
	}


	for(int a = 0; a <= 1; a++){
		for(int b = 0; b <= 1; b++){
			for(int c = 0; c <= 1; c++){
				for(int i = 0; i <= 2*N-2; i++){

					table[i].value = HUGE_NUM;
				}

				std::vector<int> IND(first_N);
				std::iota(IND.begin(), IND.end(), 0);

				std::sort(IND.begin(), IND.end(), [&](int i, int j) {
				  return (point[i].y - point[i].x < point[j].y - point[j].x) ||
						 (point[i].y - point[i].x == point[j].y - point[j].x && point[i].y > point[j].y) ||
						 (point[i].y - point[i].x == point[j].y - point[j].x && point[i].y == point[j].y && i > j);
				});

				//y座標sort(セグ木用)
				for(int i = 0; i < first_N; i++){

					D[i].set(point[i].x,point[i].y,point[i].input_index);
				}
				sort(D,D+first_N);
				for(int i = 0; i < first_N; i++){

					INDEX[D[i].input_index] = i;
				}

				for(int i = 0; i < first_N; i++){

					Info ret = query(INDEX[IND[i]],first_N,0,0,N-1); //y座標が自分以上のデータの、x+yの最小値を取得
					if(ret.value != HUGE_NUM){


						//edge.push_back(Edge(IND[i],ret.index,abs(point[IND[i]].x-point[ret.index].x)+abs(point[IND[i]].y-point[ret.index].y)));
						edge.push_back(Edge(IND[i],ret.index,max(abs(point[IND[i]].x-point[ret.index].x),abs(point[IND[i]].y-point[ret.index].y))));
					}
					update(INDEX[IND[i]],point[IND[i]].x+point[IND[i]].y,IND[i]);
				}

				for(int i = 0; i < first_N; i++){
					swap(point[i].x,point[i].y);
				}
			}
			for(int i = 0; i < first_N; i++){

				point[i].x *= -1;
			}
		}
		for(int i = 0; i < first_N; i++){

			point[i].y *= -1;
		}
	}

	for(int i = 0; i < first_N; i++){

		boss[i] = i;
		height[i] = 0;
		num_member[i] = 1;
	}

	sort(edge.begin(),edge.end());

	ll ans = 0;

	vector<Edge> ANS;

	for(int i = 0; i < edge.size(); i++){
		if(isSame(edge[i].a,edge[i].b))continue;

		unite(edge[i].a,edge[i].b);
		ANS.push_back(edge[i]);
		ans += edge[i].cost;
	}

	printf("%lld\n",ans);
	/*for(int i = 0; i < ANS.size(); i++){

		printf("%d %d\n",ANS[i].a,ANS[i].b);
	}*/
	return 0;
}
accuracy: 0.359375
time_ms: 20
memory_kb: 4900
final_rank: 15

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 200005

struct Info{
	bool operator<(const struct Info& arg) const{

		return value < arg.value;
	}
	void set(ll arg_value,ll arg_index){
		value = arg_value;
		index = arg_index;
	}
	ll value,index;
};

struct Input{
	ll x,y;
};

struct DATA{
	bool operator<(const struct DATA &arg) const{

		return y < arg.y;
	}
	void set(ll arg_x,ll arg_y,ll arg_input_index){
		x = arg_x;
		y = arg_y;
		input_index = arg_input_index;
	}
	ll x,y,input_index;
};

struct Point{
	void set(ll arg_x,ll arg_y,ll arg_input_index,ll arg_now_index){
		x = arg_x;
		y = arg_y;
		input_index = arg_input_index;
	}
	bool operator<(const struct Point &arg) const{
		if(y-x != arg.y-arg.x){

			return (y-x) < (arg.y-arg.x);
		}else if(y != arg.y){

			return y > arg.y;
		}else{

			return input_index > arg.input_index;
		}
	}
	ll x,y,input_index;
};

struct Edge{
	Edge(int arg_a,int arg_b,ll arg_cost){
		a = arg_a;
		b = arg_b;
		cost = arg_cost;
	}
	bool operator<(const struct Edge& arg) const{

		return cost < arg.cost;
	}
	int a,b;
	ll cost;
};

int N;
int boss[SIZE],height[SIZE],num_member[SIZE];
int INDEX[SIZE];
DATA D[SIZE];
Info table[6*SIZE];
Input input[SIZE];
Point point[SIZE];
vector<Edge> edge;


void init(int first_N){
	N = 1;
	while(N < first_N)N *= 2;
}

void update(int loc,ll value,ll index){
	loc += N-1;

	table[loc].set(value,index);

	if(N == 1)return;

	int parent = (loc-1)/2;

	while(true){

		int L = 2*parent+1,R = 2*parent+2;
		if(table[L].value <= table[R].value){

			table[parent] = table[L];
		}else{

			table[parent] = table[R];
		}

		if(parent == 0)break;
		else{
			parent = (parent-1)/2;
		}
	}
}


Info query(int search_left,int search_right,int node_id,int node_left,int node_right){

	Info ret;

	//今回のノードが検索区間をカバーしていなければ、結果に関係ない値を返す
	if(search_right < node_left || search_left > node_right){

		ret.set(HUGE_NUM,-1);
		return ret;
	}

	//今回のノードの区間が、検索区間の部分区間である場合、今回のノードの値を返す
	if(search_left <= node_left && search_right >= node_right){
		return table[node_id];
	}

	//今回のノードの区間に、一部検索区間と重なっている区間がある場合→再帰的に子どもに尋ねる
	Info left_min = query(search_left,search_right,2*node_id+1,node_left,(node_left+node_right)/2);
	Info right_min = query(search_left,search_right,2*node_id+2,(node_left+node_right)/2+1,node_right);

	if(left_min.value <= right_min.value){

		return left_min;
	}else{

		return right_min;
	}
}

int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

int isSame(int x,int y){
	return get_boss(x) == get_boss(y);
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[boss_x] > height[boss_y]){

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;

	}else if(height[boss_x] < height[boss_y]){

		num_member[boss_y] += num_member[boss_x];
		boss[boss_x] = boss_y;

	}else{ //height[boss_x] == height[boss_y]

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;
		height[x]++;
	}
}


int main(){

	int first_N;

	scanf("%d",&first_N);

	init(first_N);

	for(int i = 0; i < first_N; i++){

		scanf("%lld %lld",&input[i].x,&input[i].y);
		point[i].set(input[i].x,input[i].y,i,i);
	}


	for(int a = 0; a <= 1; a++){
		for(int b = 0; b <= 1; b++){
			for(int c = 0; c <= 1; c++){
				for(int i = 0; i <= 2*N-2; i++){

					table[i].value = HUGE_NUM;
				}

				std::vector<int> IND(first_N);
				std::iota(IND.begin(), IND.end(), 0);

				std::sort(IND.begin(), IND.end(), [&](int i, int j) {
				  return (point[i].y - point[i].x < point[j].y - point[j].x) ||
						 (point[i].y - point[i].x == point[j].y - point[j].x && point[i].y > point[j].y) ||
						 (point[i].y - point[i].x == point[j].y - point[j].x && point[i].y == point[j].y && i > j);
				});

				//y座標sort(セグ木用)
				for(int i = 0; i < first_N; i++){

					D[i].set(point[i].x,point[i].y,point[i].input_index);
				}
				sort(D,D+first_N);
				for(int i = 0; i < first_N; i++){

					INDEX[D[i].input_index] = i;
				}

				for(int i = 0; i < first_N; i++){

					Info ret = query(INDEX[IND[i]],first_N,0,0,N-1); //y座標が自分以上のデータの、x+yの最小値を取得
					if(ret.value != HUGE_NUM){


						//edge.push_back(Edge(IND[i],ret.index,abs(point[IND[i]].x-point[ret.index].x)+abs(point[IND[i]].y-point[ret.index].y)));
						edge.push_back(Edge(IND[i],ret.index,max(abs(point[IND[i]].x-point[ret.index].x),abs(point[IND[i]].y-point[ret.index].y))));
					}
					update(INDEX[IND[i]],point[IND[i]].x+point[IND[i]].y,IND[i]);
				}

				for(int i = 0; i < first_N; i++){
					swap(point[i].x,point[i].y);
				}
			}
			for(int i = 0; i < first_N; i++){

				point[i].x *= -1;
			}
		}
		for(int i = 0; i < first_N; i++){

			point[i].y *= -1;
		}
	}

	for(int i = 0; i < first_N; i++){

		boss[i] = i;
		height[i] = 0;
		num_member[i] = 1;
	}

	sort(edge.begin(),edge.end());

	ll ans = 0;

	vector<Edge> ANS;

	for(int i = 0; i < edge.size(); i++){
		if(isSame(edge[i].a,edge[i].b))continue;

		unite(edge[i].a,edge[i].b);
		ANS.push_back(edge[i]);
		ans += edge[i].cost;
	}

	printf("%lld\n",ans);
	/*for(int i = 0; i < ANS.size(); i++){

		printf("%d %d\n",ANS[i].a,ANS[i].b);
	}*/
	return 0;
}
accuracy: 0.359375
time_ms: 10
memory_kb: 4988
final_rank: 13

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 200005

struct Info{
	bool operator<(const struct Info& arg) const{

		return value < arg.value;
	}
	void set(ll arg_value,ll arg_index){
		value = arg_value;
		index = arg_index;
	}
	ll value,index;
};

struct Input{
	ll x,y;
};

struct DATA{
	bool operator<(const struct DATA &arg) const{

		return y < arg.y;
	}
	void set(ll arg_x,ll arg_y,ll arg_input_index){
		x = arg_x;
		y = arg_y;
		input_index = arg_input_index;
	}
	ll x,y,input_index;
};

struct Point{
	void set(ll arg_x,ll arg_y,ll arg_input_index,ll arg_now_index){
		x = arg_x;
		y = arg_y;
		input_index = arg_input_index;
		now_index = arg_now_index;
	}
	bool operator<(const struct Point &arg) const{
		if(y-x != arg.y-arg.x){

			return (y-x) < (arg.y-arg.x);
		}else if(y != arg.y){

			return y > arg.y;
		}else{

			return input_index > arg.input_index;
		}
	}
	ll x,y,input_index,now_index;
};

struct Edge{
	Edge(int arg_a,int arg_b,ll arg_cost){
		a = arg_a;
		b = arg_b;
		cost = arg_cost;
	}
	bool operator<(const struct Edge& arg) const{

		return cost < arg.cost;
	}
	int a,b;
	ll cost;
};

int N;
int boss[SIZE],height[SIZE],num_member[SIZE];
int INDEX[SIZE];
DATA D[SIZE];
Info table[6*SIZE];
Input input[SIZE];
Point point[SIZE];
vector<Edge> edge;


void init(int first_N){
	N = 1;
	while(N < first_N)N *= 2;
}

void update(int loc,ll value,ll index){
	loc += N-1;

	table[loc].set(value,index);

	if(N == 1)return;

	int parent = (loc-1)/2;

	while(true){
		table[parent] = min(table[2*parent+1],table[2*parent+2]);

		if(parent == 0)break;
		else{
			parent = (parent-1)/2;
		}
	}
}


Info query(int search_left,int search_right,int node_id,int node_left,int node_right){

	Info ret;

	//今回のノードが検索区間をカバーしていなければ、結果に関係ない値を返す
	if(search_right < node_left || search_left > node_right){

		ret.set(HUGE_NUM,-1);
		return ret;
	}

	//今回のノードの区間が、検索区間の部分区間である場合、今回のノードの値を返す
	if(search_left <= node_left && search_right >= node_right){
		return table[node_id];
	}

	//今回のノードの区間に、一部検索区間と重なっている区間がある場合→再帰的に子どもに尋ねる
	Info left_min = query(search_left,search_right,2*node_id+1,node_left,(node_left+node_right)/2);
	Info right_min = query(search_left,search_right,2*node_id+2,(node_left+node_right)/2+1,node_right);

	return min(left_min,right_min);
}




int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

int isSame(int x,int y){
	return get_boss(x) == get_boss(y);
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[boss_x] > height[boss_y]){

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;

	}else if(height[boss_x] < height[boss_y]){

		num_member[boss_y] += num_member[boss_x];
		boss[boss_x] = boss_y;

	}else{ //height[boss_x] == height[boss_y]

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;
		height[x]++;
	}
}


int main(){

	int first_N;

	scanf("%d",&first_N);

	init(first_N);

	for(int i = 0; i < first_N; i++){

		scanf("%lld %lld",&input[i].x,&input[i].y);
		point[i].set(input[i].x,input[i].y,i,i);
	}


	for(int a = 0; a <= 1; a++){
		for(int b = 0; b <= 1; b++){
			for(int c = 0; c <= 1; c++){

				/*
				for(int i = 0; i < first_N; i++){

					point[i].now_index = i;
				}

				sort(point,point+first_N);*/

				for(int i = 0; i <= 2*N-2; i++){

					table[i].value = HUGE_NUM;
				}

				std::vector<int> IND(first_N);
				std::iota(IND.begin(), IND.end(), 0);

				std::sort(IND.begin(), IND.end(), [&](int i, int j) {
				  return (point[i].y - point[i].x < point[j].y - point[j].x) ||
						 (point[i].y - point[i].x == point[j].y - point[j].x && point[i].y > point[j].y) ||
						 (point[i].y - point[i].x == point[j].y - point[j].x && point[i].y == point[j].y && i > j);
				});

				//y座標sort(セグ木用)
				for(int i = 0; i < first_N; i++){

					D[i].set(point[i].x,point[i].y,point[i].input_index);
				}
				sort(D,D+first_N);
				for(int i = 0; i < first_N; i++){

					INDEX[D[i].input_index] = i;
				}

				for(int i = 0; i < first_N; i++){

					Info ret = query(INDEX[IND[i]],first_N,0,0,N-1); //y座標が自分以上のデータの、x+yの最小値を取得
					if(ret.value != HUGE_NUM){

						//edge.push_back(Edge(a,b,abs(input[a].x-input[b].x)+abs(input[a].y-input[b].y)));
						//edge.push_back(Edge(IND[i],ret.index,abs(point[IND[i]].x-point[ret.index].x)+abs(point[IND[i]].y-point[ret.index].y)));
						edge.push_back(Edge(IND[i],ret.index,max(abs(point[IND[i]].x-point[ret.index].x),abs(point[IND[i]].y-point[ret.index].y))));
					}
					update(INDEX[IND[i]],point[IND[i]].x+point[IND[i]].y,IND[i]);
				}

				for(int i = 0; i < first_N; i++){
					swap(point[i].x,point[i].y);
				}
			}
			for(int i = 0; i < first_N; i++){

				point[i].x *= -1;
			}
		}
		for(int i = 0; i < first_N; i++){

			point[i].y *= -1;
		}
	}

	for(int i = 0; i < first_N; i++){

		boss[i] = i;
		height[i] = 0;
		num_member[i] = 1;
	}

	sort(edge.begin(),edge.end());

	ll ans = 0;

	vector<Edge> ANS;

	for(int i = 0; i < edge.size(); i++){
		if(isSame(edge[i].a,edge[i].b))continue;

		unite(edge[i].a,edge[i].b);
		ANS.push_back(edge[i]);
		ans += edge[i].cost;
	}

	printf("%lld\n",ans);
	/*for(int i = 0; i < ANS.size(); i++){

		printf("%d %d\n",ANS[i].a,ANS[i].b);
	}*/
	return 0;
}
accuracy: 0.359375
time_ms: 20
memory_kb: 5052
final_rank: 16

code_snippet: //Let's join Kaede Takagaki Fan Club !!
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
//#define int long long
typedef long long ll;
typedef pair<int,int> P;
typedef pair<int,P> P1;
typedef pair<P,P> P2;
#define pu push
#define pb push_back
#define eb emplace_back
#define mp make_pair
#define eps 1e-7
#define INF 1000000000
#define a first
#define b second
#define fi first
#define sc second
#define rng(i,a,b) for(int i=int(a);i<int(b);i++)
#define rep(i,x) for(int i=0;i<x;i++)
#define repn(i,x) for(int i=1;i<=x;i++)
#define SORT(x) sort(x.begin(),x.end())
#define ERASE(x) x.erase(unique(x.begin(),x.end()),x.end())
#define POSL(x,v) (lower_bound(x.begin(),x.end(),v)-x.begin())
#define POSU(x,v) (upper_bound(x.begin(),x.end(),v)-x.begin())
#define all(x) x.begin(),x.end()
#define si(x) int(x.size())

#ifdef LOCAL
#define dmp(x) cerr<<__LINE__<<" "<<#x<<" "<<x<<endl
#else
#define dmp(x) void(0)
#endif

template<class t,class u> bool chmax(t&a,u b){if(a<b){a=b;return true;}else return false;}
template<class t,class u> bool chmin(t&a,u b){if(b<a){a=b;return true;}else return false;}

template<class t> using vc=vector<t>;

template<class t,class u>
ostream& operator<<(ostream& os,const pair<t,u>& p){
	return os<<"{"<<p.fi<<","<<p.sc<<"}";
}

template<class t> ostream& operator<<(ostream& os,const vc<t>& v){
	os<<"{";
	for(auto e:v)os<<e<<",";
	return os<<"}";
}

template<class T>
void g(T &a){
	cin >> a;
}
template<class T>
void o(const T &a,bool space=false){
	cout << a << (space?' ':'\n');
}
//ios::sync_with_stdio(false);
const ll mod = 1000000007;//998244353
mt19937_64 mt(chrono::steady_clock::now().time_since_epoch().count());
template<class T>
void add(T&a,T b){
	a+=b;
	if(a >= mod) a-=mod;
}
ll modpow(ll x,ll n){
	ll res=1;
	while(n>0){
		if(n&1) res=res*x%mod;
		x=x*x%mod;
		n>>=1;
	}
	return res;
}
struct uf{
	vc<int>par, ran;
	uf(){}
	uf(int n){
		par.resize(n+1, 0);
		iota(all(par), 0);
		ran.resize(n+1, 0);
	}
	int find(int x){ if(x == par[x]) return x; else return par[x] = find(par[x]); }
	void unite(int x,int y){
		x = find(x); y = find(y); if(x==y) return;
		if(ran[x] < ran[y]) par[x] = y;
		else{
			par[y] = x;
			if(ran[x] == ran[y]) ran[x]++;
		}
	}
	bool same(int x,int y){ return find(x)==find(y); }
};
template<class T>
vc<P>mn_mst(vc<T>pt){
	vc<pair<ll, P>>ret;
	int n = pt.size();
	vector<P> es;
	
	rep(s, 2){
		rep(t, 2){
			map<int, int> z;
			vc<int> idx(n);
			iota(all(idx), 0);
			sort(all(idx), [&](int i, int j){
				return pt[i].a + pt[i].b < pt[j].a + pt[j].b;
			});
			for(auto i:idx){
				for(auto itr=z.lower_bound(-pt[i].b);itr != z.end(); itr = z.erase(itr)){
					int j = itr -> b;
					if(pt[i].b-pt[j].b > pt[i].a-pt[j].a) break;
					ret.pb(mp(pt[i].a+pt[i].b-pt[j].a-pt[j].b, mp(i, j)));
				}
				z[-pt[i].b] = i;
			}
			for(auto &p:pt) swap(p.a, p.b);
		}
		for(auto &p:pt) p.a *= -1;
	}
	SORT(ret);
	uf x(n);
	vc<P>ans;
	for(auto e:ret){
		if(x.same(e.b.a, e.b.b) == false){
			ans.pb(e.b);
			x.unite(e.b.a, e.b.b);
		}
	}
	return ans;
}
void solve(){
	int n; cin >> n;
	vc<pair<ll, ll>>za(n);
	rep(i, n) cin >> za[i].a >> za[i].b;
	rep(i, n){
		ll u = za[i].a * 2;
		ll v = za[i].b * 2;
		za[i].a = (u + v) / 2;
		za[i].b = (u - v) / 2;
	}
	auto ret = mn_mst(za);
	ll sum = 0;
	for(auto e:ret){
		sum += abs(za[e.a].a - za[e.b].a);
		sum += abs(za[e.a].b - za[e.b].b);
	}
	o(sum/2);
	//for(auto e:ret) cout << e.a << " " << e.b << '\n';
}
signed main(){
	cin.tie(0);
	ios::sync_with_stdio(0);
	cout<<fixed<<setprecision(20);
	int t; t = 1; //cin >> t;
	while(t--) solve();
}
accuracy: 1
time_ms: 140
memory_kb: 15140
final_rank: 2