#include <fstream>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
ifstream fin("metrou4.in");
ofstream fout("metrou4.out");
const int dim = 150005;
struct Point {
int x, y, index;
Point(int x = 0, int y = 0, int index = 0) :
x(x), y(y), index(index) {}
bool operator < (const Point& obj) {
return (x == obj.x ? y < obj.y : x < obj.x);
}
};
struct Edge {
int a, b, cost;
Edge(int a = 0, int b = 0, int cost = 0) :
a(a), b(b), cost(cost) {}
bool operator < (const Edge& obj) {
return cost < obj.cost;
}
};
class SegmentTree {
private:
int n;
pair<int, int> nodes[4 * dim];
void _Update(int node, int lef, int rig, int pos, const Point& point) {
if (nodes[node].second == 0 || nodes[node].first < point.x + point.y)
nodes[node] = make_pair(point.x + point.y, point.index);
if (lef == rig)
return;
int mid = (lef + rig) / 2;
if (pos <= mid)
_Update(2 * node, lef, mid, pos, point);
else
_Update(2 * node + 1, mid + 1, rig, pos, point);
}
pair<int, int> _Query(int node, int lef, int rig, int pos) {
if (rig <= pos)
return nodes[node];
int mid = (lef + rig) / 2;
pair<int, int> ret(0, 0);
if (pos <= mid)
ret = _Query(2 * node, lef, mid, pos);
else {
ret = _Query(2 * node, lef, mid, pos);
pair<int, int> aux = _Query(2 * node + 1, mid + 1, rig, pos);
if (ret.second == 0 || (aux.second != 0 && ret.first < aux.first))
ret = aux;
}
return ret;
}
public:
SegmentTree() {}
void Reset(int n) {
this->n = n;
for (int i = 1; i <= 4 * n; ++i)
nodes[i] = { 0, 0 };
}
void Update(int pos, const Point& point) {
_Update(1, 1, n, pos, point);
}
pair<int, int> Query(int pos) {
return _Query(1, 1, n, pos);
}
};
class DisJoint {
private:
int parent[dim];
public:
void Reset() {
memset(parent, -1, sizeof parent);
}
DisJoint() {
Reset();
}
int GetRoot(int x) {
int aux = x;
while (parent[x] > 0)
x = parent[x];
int root = x;
x = aux;
while (x != root) {
aux = parent[x];
parent[x] = root;
x = aux;
}
return root;
}
bool Join(int x, int y) {
x = GetRoot(x);
y = GetRoot(y);
if (x == y)
return false;
if (parent[x] < parent[y]) {
parent[x] += parent[y];
parent[y] = x;
}
else {
parent[y] += parent[x];
parent[x] = y;
}
return true;
}
};
int n;
Point points[dim];
void Reflect() {
for (int i = 1; i <= n; ++i)
points[i].x *= -1;
}
void Rotate() {
for (int i = 1; i <= n; ++i) {
int x = points[i].x, y = points[i].y;
points[i].x = -y;
points[i].y = x;
}
}
SegmentTree segmentTree;
vector<int> coords;
vector<Edge> edges;
void BuildEdges() {
coords.clear();
for (int i = 1; i <= n; ++i)
coords.push_back(points[i].y - points[i].x);
sort(coords.begin(), coords.end());
coords.erase(unique(coords.begin(), coords.end()), coords.end());
segmentTree.Reset((int)coords.size());
sort(points + 1, points + n + 1);
for (int i = 1; i <= n; ++i) {
int pos = lower_bound(coords.begin(), coords.end(), points[i].y - points[i].x) - coords.begin() + 1;
pair<int, int> ans = segmentTree.Query(pos);
if (ans.second != 0)
edges.push_back(Edge(points[i].index, ans.second, points[i].x + points[i].y - ans.first));
segmentTree.Update(pos, points[i]);
}
}
void InitEdges() {
edges.clear();
for (int i = 1; i <= 2; ++i) {
for (int j = 1; j <= 4; ++j) {
BuildEdges();
Rotate();
}
Reflect();
}
}
DisJoint disJoint;
long long Kruskal() {
disJoint.Reset();
sort(edges.begin(), edges.end());
long long ret = 0;
for (auto& curr : edges)
if (disJoint.Join(curr.a, curr.b))
ret += curr.cost;
return ret;
}
int main() {
int testCount;
fin >> testCount;
while (testCount--) {
fin >> n;
for (int i = 1; i <= n; ++i) {
fin >> points[i].x >> points[i].y;
points[i].index = i;
}
InitEdges();
fout << Kruskal() << '\n';
}
return 0;
}
//Trust me, I'm the Doctor!