Cod sursa(job #2892146)

Utilizator Alex_tz307Lorintz Alexandru Alex_tz307 Data 20 aprilie 2022 23:00:29
Problema Metrou4 Scor 100
Compilator cpp-64 Status done
Runda Arhiva ICPC Marime 3.39 kb
#include <bits/stdc++.h>

using namespace std;

ifstream fin("metrou4.in");
ofstream fout("metrou4.out");

const int kN = 1e5 + 5e4;
const int INF = 2e9 + 1;

struct point {
  int x, y, index;

  void read() {
    fin >> x >> y;
  }

  bool operator < (const point &rhs) const {
    if (x != rhs.x) {
      return x > rhs.x;
    }
    return y > rhs.y;
  }
} p[kN], aux[kN];

struct ST {
  int n;
  vector<pair<int, int>> t;

  ST(int N) : n(N) {
    int dim = 1;
    while (dim < n) {
      dim *= 2;
    }
    t.resize(dim * 2, {INF, INF});
  }

  void update(int x, int lx, int rx, int pos, pair<int, int> v) {
    if (lx == rx) {
      t[x] = min(t[x], v);
      return;
    }
    int mid = (lx + rx) / 2;
    if (pos <= mid) {
      update(x * 2, lx, mid, pos, v);
    } else {
      update(x * 2 + 1, mid + 1, rx, pos, v);
    }
    t[x] = min(t[x * 2], t[x * 2 + 1]);
  }

  void update(int pos, pair<int, int> v) {
    update(1, 1, n, pos, v);
  }

  pair<int, int> query(int x, int lx, int rx, int st, int dr) {
    if (st <= lx && rx <= dr) {
      return t[x];
    }
    int mid = (lx + rx) / 2;
    pair<int, int> ans{INF, INF};
    if (st <= mid) {
      ans = min(ans, query(x * 2, lx, mid, st, dr));
    }
    if (mid < dr) {
      ans = min(ans, query(x * 2 + 1, mid + 1, rx, st, dr));
    }
    return ans;
  }

  pair<int, int> query(int st, int dr) {
    return query(1, 1, n, st, dr);
  }
};

struct DSU {
  vector<int> p, sz;

  DSU(int n) {
    p.resize(n);
    iota(p.begin(), p.end(), 0);
    sz.assign(n, 1);
  }

  int root(int x) {
    if (x == p[x]) {
      return x;
    }
    return p[x] = root(p[x]);
  }

  bool unite(int u, int v) {
    int x = root(u), y = root(v);
    if (x == y) {
      return false;
    }
    if (sz[y] < sz[x]) {
      swap(x, y);
    }
    p[x] = y;
    sz[y] += sz[x];
    return true;
  }
};

void testCase() {
  int n;
  fin >> n;
  for (int i = 0; i < n; ++i) {
    p[i].read();
    p[i].index = i;
  }
  vector<tuple<int, int, int>> edges;
  for (int rot = 0; rot < 8; ++rot) {
    for (int i = 0; i < n; ++i) {
      aux[i] = p[i];
    }
    vector<int> diff(n);
    for (int i = 0; i < n; ++i) {
      if (rot & 1) {
        p[i].x *= -1;
      }
      if (rot & 2) {
        p[i].y *= -1;
      }
      if (rot & 4) {
        swap(p[i].x, p[i].y);
      }
      diff[i] = p[i].x - p[i].y;
    }
    sort(diff.begin(), diff.end());
    diff.erase(unique(diff.begin(), diff.end()), diff.end());
    sort(p, p + n);
    int N = diff.size();
    ST t(N);
    for (int i = 0; i < n; ++i) {
      int index = distance(diff.begin(), upper_bound(diff.begin(), diff.end(), p[i].x - p[i].y));
      pair<int, int> ret = t.query(1, index);
      if (ret.first != INF) {
        edges.emplace_back(ret.first - (p[i].x + p[i].y), p[i].index, ret.second);
      }
      t.update(index, {p[i].x + p[i].y, p[i].index});
    }
    for (int i = 0; i < n; ++i) {
      p[i] = aux[i];
    }
  }
  sort(edges.begin(), edges.end());
  DSU dsu(n);
  int64_t ans = 0;
  for (auto it : edges) {
    int w, u, v;
    tie(w, u, v) = it;
    if (dsu.unite(u, v)) {
      ans += w;
    }
  }
  fout << ans << '\n';
}

int main() {
  int tests;
  fin >> tests;
  for (int tc = 1; tc <= tests; ++tc) {
    testCase();
  }
  fin.close();
  fout.close();
  return 0;
}