Problem:
Colorful Rectangle
You are given a set of points on a plane. Each point is colored either red, blue, or green.
A rectangle is called
colorful
if it contains one or more points of every color inside or on its edges. Your task is to find an axis-parallel colorful rectangle with the shortest perimeter. An axis-parallel line segment is considered as a degenerated rectangle and its perimeter is twice the length of the line segment.
Input
The input consists of a single test case of the following format.
$n$
$x_1$ $y_1$ $c_1$
...
$x_n$ $y_n$ $c_n$
The first line contains an integer $n$ ($3 \leq n \leq 10^5$) representing the number of points on the plane. Each of the following $n$ lines contains three integers $x_i$, $y_i$, and $c_i$ satisfying $0 \leq x_i \leq 10^8$, $0 \leq y_i \leq 10^8$, and $0 \leq c_i \leq 2$. Each line represents that there is a point of color $c_i$ (0: red, 1: blue, 2: green) at coordinates ($x_i$, $y_i$). It is guaranteed that there is at least one point of every color and no two points have the same coordinates.
Output
Output a single integer in a line which is the shortest perimeter of an axis-parallel colorful
rectangle.
Sample Input 1
4
0 2 0
1 0 0
1 3 1
2 4 2
Sample Output 1
8
Sample Input 2
4
0 0 0
0 1 1
0 2 2
1 2 0
Sample Output 2
4

Submitted solutions:

code_snippet: #ifdef NACHIA
#define _GLIBCXX_DEBUG
#else
#define NDEBUG
#endif
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
using ll = long long;
const ll INF = 1ll << 60;
#define REP(i,n) for(ll i=0; i<ll(n); i++)
template <class T> using V = vector<T>;
template <class A, class B> void chmax(A& l, const B& r){ if(l < r) l = r; }
template <class A, class B> void chmin(A& l, const B& r){ if(r < l) l = r; }

struct Segtree {
  using S = ll;
  static S op(S l, S r){ return min(l, r); }
  static S e(){ return INF; }
  V<S> A;
  ll N;
  Segtree(ll n = 0){
    N = 1;
    while(N < n) N *= 2;
    A.assign(N*2, e());
  }
  S prod(ll l, ll r){
    S ql = e(), qr = e();
    l += N; r += N;
    while(l < r){
      if(l%2) ql = op(ql, A[l++]);
      if(r%2) qr = op(A[--r], qr);
      l /= 2; r /= 2;
    }
    return op(ql, qr);
  }
  void upd(ll p){
    A[p] = op(A[p*2], A[p*2+1]);
  }
  void set(ll p, S v){
    p += N;
    A[p] = v;
    while(p > 1) upd(p/=2);
  }
};

struct LazySegtree {
  struct S{ ll o, i; };
  using F = ll;
  static S op(S l, S r){ return { min(l.o, r.o), min(l.i, r.i) }; }
  static S mapping(F f, S x){ return { x.o, min(x.i, x.o + f) }; }
  static F composition(F f, F x){ return min(f, x); }
  static S e(){ return { INF, INF }; }
  static F id(){ return INF; }
  V<S> A;
  V<F> B;
  ll N;
  LazySegtree(ll n = 0){
    N = 1;
    while(N < n) N *= 2;
    A.assign(N*2, e());
    B.assign(N*2, id());
  }
  void upd(ll p){
    A[p] = op(A[p*2], A[p*2+1]);
  }
  void mapp(ll p, F f){
    A[p] = mapping(f, A[p]);
    B[p] = composition(f, B[p]);
  }
  void push(ll p){
    mapp(p*2, B[p]);
    mapp(p*2+1, B[p]);
    B[p] = id();
  }
  void apply(ll l, ll r, F f, ll a = -1, ll b = -1, ll i = -1){
    if(i < 0){ a = 0; b = N; i = 1; }
    if(l <= a && b <= r){ mapp(i,f); return; }
    if(r <= a || b <= l) return;
    push(i);
    apply(l, r, f, a, (a+b)/2, i*2);
    apply(l, r, f, (a+b)/2, b, i*2+1);
    upd(i);
  }
  S prod(ll l, ll r, ll a = -1, ll b = -1, ll i = -1){
    if(i < 0){ a = 0; b = N; i = 1; }
    if(l <= a && b <= r){ return A[i]; }
    if(r <= a || b <= l) return e();
    push(i);
    return op(prod(l, r, a, (a+b)/2, i*2), prod(l, r, (a+b)/2, b, i*2+1));
  }
  void set(ll p, S v, ll a = -1, ll b = -1, ll i = -1){
    if(i < 0){ a = 0; b = N; i = 1; }
    if(a + 1 == b){ A[i] = v; return; }
    ll m = (a + b) / 2;
    push(i);
    if(p < m) set(p, v, a, m, i*2); else set(p, v, m, b, i*2+1);
    upd(i);
  }
};

struct Pt { ll x, y, c, xi, yi; };

ll query(V<Pt> A){
  ll N = A.size();
  Segtree ds1(N), ds2(N);
  ll ans = INF;
  for(auto p : A){
    if(p.c == 0){
      ds1.set(p.xi, {-p.x-p.y});
    }
    if(p.c == 1){
      ds2.set(p.xi, ds1.prod(0, p.xi));
    }
    if(p.c == 2){
      chmin(ans, p.x + p.y + ds2.prod(0, p.xi));
    }
  }
  LazySegtree ds3(N);
  for(auto p : A){
    if(p.c == 0){
      ds3.set(p.xi, {-p.y, INF});
    }
    if(p.c == 1){
      ds3.apply(p.xi+1, N, -p.x);
    }
    if(p.c == 2){
      chmin(ans, p.x + p.y + ds3.prod(0, p.xi).i);
    }
  }
  LazySegtree ds4(N);
  for(auto p : A){
    if(p.c == 0){
      ds4.set(p.xi, {-p.y, INF});
    }
    if(p.c == 1){
      ds4.apply(0, p.xi, p.x);
    }
    if(p.c == 2){
      chmin(ans, -p.x + p.y + ds4.prod(p.xi+1, N).i);
    }
  }
  return ans;
}

void testcase(){
  ll N; cin >> N;
  V<Pt> A(N); for(auto& p : A) cin >> p.x >> p.y >> p.c;
  sort(A.begin(), A.end(), [&](auto l, auto r){ return l.x < r.x; });
  REP(i,N) A[i].xi = i;
  sort(A.begin(), A.end(), [&](auto l, auto r){ return l.y < r.y; });
  REP(i,N) A[i].yi = i;

  ll C[3] = {0,1,2};
  ll ans = INF;
  REP(ff,2){
    do{
      auto B = A;
      for(auto& q : B) q.c = C[q.c];
      chmin(ans, query(move(B)));
    } while(next_permutation(C, C+3));
    reverse(A.begin(), A.end());
    for(auto& a : A) a.y *= -1;
  }
  ans *= 2;
  cout << ans << "\n";
}

int main(){
  cin.tie(0)->sync_with_stdio(0);
  testcase();
  return 0;
}
accuracy: 1
time_ms: 620
memory_kb: 27712
final_rank: 3

code_snippet: #ifdef NACHIA
#define _GLIBCXX_DEBUG
#else
#define NDEBUG
#endif
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
using ll = long long;
const ll INF = 1ll << 60;
#define REP(i,n) for(ll i=0; i<ll(n); i++)
template <class T> using V = vector<T>;
template <class A, class B> void chmax(A& l, const B& r){ if(l < r) l = r; }
template <class A, class B> void chmin(A& l, const B& r){ if(r < l) l = r; }

struct Segtree {
  using S = ll;
  static S op(S l, S r){ return min(l, r); }
  static S e(){ return INF; }
  V<S> A;
  ll N;
  Segtree(ll n = 0){
    N = 1;
    while(N < n) N *= 2;
    A.assign(N*2, e());
  }
  S prod(ll l, ll r){
    S ql = e(), qr = e();
    l += N; r += N;
    while(l < r){
      if(l%2) ql = op(ql, A[l++]);
      if(r%2) qr = op(A[--r], qr);
      l /= 2; r /= 2;
    }
    return op(ql, qr);
  }
  void upd(ll p){
    A[p] = op(A[p*2], A[p*2+1]);
  }
  void set(ll p, S v){
    p += N;
    A[p] = v;
    while(p > 1) upd(p/=2);
  }
};

struct LazySegtree {
  struct S{ ll o, i; };
  using F = ll;
  static S op(S l, S r){ return { min(l.o, r.o), min(l.i, r.i) }; }
  static S mapping(F f, S x){ return { x.o, min(x.i, x.o + f) }; }
  static F composition(F f, F x){ return min(f, x); }
  static S e(){ return { INF, INF }; }
  static F id(){ return INF; }
  V<S> A;
  V<F> B;
  ll N;
  LazySegtree(ll n = 0){
    N = 1;
    while(N < n) N *= 2;
    A.assign(N*2, e());
    B.assign(N*2, id());
  }
  void upd(ll p){
    A[p] = op(A[p*2], A[p*2+1]);
  }
  void mapp(ll p, F f){
    A[p] = mapping(f, A[p]);
    B[p] = composition(f, B[p]);
  }
  void push(ll p){
    mapp(p*2, B[p]);
    mapp(p*2+1, B[p]);
    B[p] = id();
  }
  void apply(ll l, ll r, F f, ll a = -1, ll b = -1, ll i = -1){
    if(i < 0){ a = 0; b = N; i = 1; }
    if(l <= a && b <= r){ mapp(i,f); return; }
    if(r <= a || b <= l) return;
    push(i);
    apply(l, r, f, a, (a+b)/2, i*2);
    apply(l, r, f, (a+b)/2, b, i*2+1);
    upd(i);
  }
  S prod(ll l, ll r, ll a = -1, ll b = -1, ll i = -1){
    if(i < 0){ a = 0; b = N; i = 1; }
    if(l <= a && b <= r){ return A[i]; }
    if(r <= a || b <= l) return e();
    push(i);
    return op(prod(l, r, a, (a+b)/2, i*2),
    prod(l, r, (a+b)/2, b, i*2+1));
  }
  void set(ll p, S v, ll a = -1, ll b = -1, ll i = -1){
    if(i < 0){ a = 0; b = N; i = 1; }
    if(a + 1 == b){ A[i] = v; return; }
    ll m = (a + b) / 2;
    push(i);
    if(p < m) set(p, v, a, m, i*2); else set(p, v, m, b, i*2+1);
    upd(i);
  }
};

struct Pt { ll x, y, c, xi, yi; };

ll query(V<Pt> A){
  ll N = A.size();
  Segtree ds1(N), ds2(N);
  ll ans = INF;
  for(auto p : A){
    if(p.c == 0){
      ds1.set(p.xi, {-p.x-p.y});
    }
    if(p.c == 1){
      ds2.set(p.xi, ds1.prod(0, p.xi));
    }
    if(p.c == 2){
      chmin(ans, p.x + p.y + ds2.prod(0, p.xi));
    }
  }
  LazySegtree ds3(N);
  for(auto p : A){
    if(p.c == 0){
      ds3.set(p.xi, {-p.y, INF});
    }
    if(p.c == 1){
      ds3.apply(p.xi+1, N, -p.x);
    }
    if(p.c == 2){
      chmin(ans, p.x + p.y + ds3.prod(0, p.xi).i);
    }
  }
  LazySegtree ds4(N);
  for(auto p : A){
    if(p.c == 0){
      ds4.set(p.xi, {-p.y, INF});
    }
    if(p.c == 1){
      ds4.apply(0, p.xi, p.x);
    }
    if(p.c == 2){
      chmin(ans, -p.x + p.y + ds4.prod(p.xi+1, N).i);
    }
  }
  return ans;
}

void testcase(){
  ll N; cin >> N;
  V<Pt> A(N); for(auto& p : A) cin >> p.x >> p.y >> p.c;
  sort(A.begin(), A.end(), [&](auto l, auto r){ return l.x < r.x; });
  REP(i,N) A[i].xi = i;
  sort(A.begin(), A.end(), [&](auto l, auto r){ return l.y < r.y; });
  REP(i,N) A[i].yi = i;

  ll C[3] = {0,1,2};
  ll ans = INF;
  REP(ff,2){
    do{
      auto B = A;
      for(auto& q : B) q.c = C[q.c];
      chmin(ans, query(move(B)));
    } while(next_permutation(C, C+3));
    for(auto& q : A){
      q.xi = N-1-q.xi;
      q.x *= -1;
    }
  }
  ans *= 2;
  cout << ans << "\n";
}

int main(){
  cin.tie(0)->sync_with_stdio(0);
  testcase();
  return 0;
}
accuracy: 0.05319148936170213
time_ms: 40
memory_kb: 6272
final_rank: 11

code_snippet: #ifdef NACHIA
#define _GLIBCXX_DEBUG
#else
#define NDEBUG
#endif
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
using ll = long long;
const ll INF = 1ll << 60;
#define REP(i,n) for(ll i=0; i<ll(n); i++)
template <class T> using V = vector<T>;
template <class A, class B> void chmax(A& l, const B& r){ if(l < r) l = r; }
template <class A, class B> void chmin(A& l, const B& r){ if(r < l) l = r; }

struct Segtree {
  using S = ll;
  static S op(S l, S r){ return min(l, r); }
  static S e(){ return INF; }
  V<S> A;
  ll N;
  Segtree(ll n = 0){
    N = 1;
    while(N < n) N *= 2;
    A.assign(N*2, e());
  }
  S prod(ll l, ll r){
    S ql = e(), qr = e();
    l += N; r += N;
    while(l < r){
      if(l%2) ql = op(ql, A[l++]);
      if(r%2) qr = op(A[--r], qr);
      l /= 2; r /= 2;
    }
    return op(ql, qr);
  }
  void upd(ll p){
    A[p] = op(A[p*2], A[p*2+1]);
  }
  void set(ll p, S v){
    p += N;
    A[p] = v;
    while(p > 1) upd(p/=2);
  }
};

struct LazySegtree {
  struct S{ ll o, i; };
  using F = ll;
  static S op(S l, S r){ return { min(l.o, r.o), min(l.i, r.i) }; }
  static S mapping(F f, S x){ return { x.o, min(x.i, x.o + f) }; }
  static F composition(F f, F x){ return min(f, x); }
  static S e(){ return { INF, INF }; }
  static F id(){ return INF; }
  V<S> A;
  V<F> B;
  ll N;
  LazySegtree(ll n = 0){
    N = 1;
    while(N < n) N *= 2;
    A.assign(N*2, e());
    B.assign(N*2, id());
  }
  void upd(ll p){
    A[p] = op(A[p*2], A[p*2+1]);
  }
  void mapp(ll p, F f){
    A[p] = mapping(f, A[p]);
    B[p] = composition(f, B[p]);
  }
  void push(ll p){
    mapp(p*2, B[p]);
    mapp(p*2+1, B[p]);
    B[p] = id();
  }
  void apply(ll l, ll r, F f, ll a = -1, ll b = -1, ll i = -1){
    if(i < 0){ a = 0; b = N; i = 1; }
    if(l <= a && b <= r){ mapp(i,f); return; }
    if(r <= a || b <= l) return;
    push(i);
    apply(l, r, f, a, (a+b)/2, i*2);
    apply(l, r, f, (a+b)/2, b, i*2+1);
    upd(i);
  }
  S prod(ll l, ll r, ll a = -1, ll b = -1, ll i = -1){
    if(i < 0){ a = 0; b = N; i = 1; }
    if(l <= a && b <= r){ return A[i]; }
    if(r <= a || b <= l) return e();
    push(i);
    return op(prod(l, r, a, (a+b)/2, i*2),
    prod(l, r, (a+b)/2, b, i*2+1));
  }
  void set(ll p, S v, ll a = -1, ll b = -1, ll i = -1){
    if(i < 0){ a = 0; b = N; i = 1; }
    if(a + 1 == b){ A[i] = v; return; }
    ll m = (a + b) / 2;
    push(i);
    if(p < m) set(p, v, a, m, i*2); else set(p, v, m, b, i*2+1);
    upd(i);
  }
};

struct Pt { ll x, y, c, xi, yi; };

ll query(V<Pt> A){
  ll N = A.size();
  Segtree ds1(N), ds2(N);
  ll ans = INF;
  for(auto p : A){
    if(p.c == 0){
      ds1.set(p.xi, {-p.x-p.y});
    }
    if(p.c == 1){
      ds2.set(p.xi, ds1.prod(0, p.xi));
    }
    if(p.c == 2){
      chmin(ans, p.x + p.y + ds2.prod(0, p.xi));
    }
  }
  LazySegtree ds3(N);
  for(auto p : A){
    if(p.c == 0){
      ds3.set(p.xi, {-p.y, INF});
    }
    if(p.c == 1){
      ds3.apply(p.xi+1, N, -p.x);
    }
    if(p.c == 2){
      chmin(ans, p.x + p.y + ds3.prod(0, p.xi).i);
    }
  }
  return ans;
}

void testcase(){
  ll N; cin >> N;
  V<Pt> A(N); for(auto& p : A) cin >> p.x >> p.y >> p.c;
  sort(A.begin(), A.end(), [&](auto l, auto r){ return l.x < r.x; });
  REP(i,N) A[i].xi = i;
  sort(A.begin(), A.end(), [&](auto l, auto r){ return l.y < r.y; });
  REP(i,N) A[i].yi = i;

  ll C[3] = {0,1,2};
  ll ans = INF;
  REP(ff,2){
    do{
      auto B = A;
      for(auto& q : B) q.c = C[q.c];
      chmin(ans, query(move(B)));
    } while(next_permutation(C, C+3));
    for(auto& q : A){
      q.xi = N-1-q.xi;
      q.x *= -1;
    }
  }
  ans *= 2;
  cout << ans << "\n";
}

int main(){
  cin.tie(0)->sync_with_stdio(0);
  testcase();
  return 0;
}
accuracy: 0.05319148936170213
time_ms: 20
memory_kb: 5504
final_rank: 9

code_snippet: #include <bits/stdc++.h>
#define sz(x) ((int)(x).size())
#define all(x) begin(x), end(x)
#define rep(i, l, r) for (int i = (l), i##end = (r); i <= i##end; ++i)
#define per(i, l, r) for (int i = (l), i##end = (r); i >= i##end; --i)
#ifdef memset0
#define log(...) fprintf(stderr, __VA_ARGS__)
#else
#define log(...) (void(0))
#define endl '\n'
#endif
using namespace std;
using ll = long long;
using lf = long double;
using lll = __int128;
using ull = unsigned long long;

inline void updmin(int &x, int y) {
  if (y < x) x = y;
}

const int N = 1e5 + 9, inf = 5e8;
int n, m, ans;
vector<int> val;

struct atom {
  int x, y, ty, c, oc;
  bool operator<(const atom &rhs) const {
    if (x != rhs.x) return x < rhs.x;
    if (c != rhs.c) return c < rhs.c;
    return y < rhs.y;
  }
} a[N];

struct segment {
  int l, r, mid;
  int x2, xy2, s12, y1;
} p[N << 2];

void maintain(int u) {
  updmin(p[u].x2, min(p[u << 1].x2, p[u << 1 | 1].x2));
  updmin(p[u].xy2, min(p[u << 1].xy2, p[u << 1 | 1].xy2));
  updmin(p[u].s12, min(p[u << 1].s12, p[u << 1 | 1].s12));
}
void pushup(int u, int y1) {
  updmin(p[u].y1, y1);
  updmin(p[u].s12, y1 + p[u].x2);
}
void pushdown(int u) {
  if (p[u].y1 != inf && p[u].l != p[u].r) {
    pushup(u << 1, p[u].y1);
    pushup(u << 1 | 1, p[u].y1);
  }
  p[u].y1 = inf;
}

void build(int u, int l, int r) {
  p[u].l = l, p[u].r = r, p[u].mid = (l + r) >> 1;
  p[u].x2 = p[u].xy2 = p[u].s12 = p[u].y1 = inf;
  if (l == r) {
    return;
  }
  build(u << 1, l, p[u].mid);
  build(u << 1 | 1, p[u].mid + 1, r);
}

void modify12(int u, int k, int it) {
  pushdown(u);
  if (p[u].l == p[u].r) {
    updmin(p[u].s12, it);
    return;
  }
  modify12(k <= p[u].mid ? u << 1 : u << 1 | 1, k, it);
  maintain(u);
}
void modify2(int u, int k, const pair<int, int> &it) {
  pushdown(u);
  if (p[u].l == p[u].r) {
    updmin(p[u].x2, it.first);
    updmin(p[u].xy2, it.second);
    return;
  }
  modify2(k <= p[u].mid ? u << 1 : u << 1 | 1, k, it);
  maintain(u);
}
void modify1(int u, int l, int r, int it) {
  pushdown(u);
  if (p[u].l == l && p[u].r == r) {
    pushup(u, it);
    return;
  }
  if (r <= p[u].mid) {
    modify1(u << 1, l, r, it);
  } else if (l > p[u].mid) {
    modify1(u << 1 | 1, l, r, it);
  } else {
    modify1(u << 1, l, p[u].mid, it);
    modify1(u << 1 | 1, p[u].mid + 1, r, it);
  }
  maintain(u);
}

int query2(int u, int l, int r) {
  pushdown(u);
  if (p[u].l == l && p[u].r == r) return p[u].xy2;
  if (r <= p[u].mid) return query2(u << 1, l, r);
  if (l > p[u].mid) return query2(u << 1 | 1, l, r);
  return min(query2(u << 1, l, p[u].mid), query2(u << 1 | 1, p[u].mid + 1, r));
}
int query12(int u, int l, int r) {
  pushdown(u);
  if (p[u].l == l && p[u].r == r) return p[u].s12;
  if (r <= p[u].mid) return query12(u << 1, l, r);
  if (l > p[u].mid) return query12(u << 1 | 1, l, r);
  return min(query12(u << 1, l, p[u].mid), query12(u << 1 | 1, p[u].mid + 1, r));
}

void solve(int x, int y, int z) {
  // log("\n\n\n=== solve %d %d %d ===\n", x, y, z);
  for (int i = 1; i <= n; i++) {
    a[i].c = a[i].oc == x ? 0 : (a[i].oc == y ? 1 : 2);
  }
  sort(a + 1, a + n + 1);
  build(1, 1, sz(val));
  for (int i = n; i >= 1; i--) {
    if (a[i].c == 2) {
      // log("modify2 %d << %d %d\n", a[i].ty, a[i].x, a[i].x + a[i].y);
      modify2(1, a[i].ty, make_pair(a[i].x, a[i].x + a[i].y));
    } else if (a[i].c == 1) {
      // log("modify12 %d >> %d\n", a[i].ty, query2(1, a[i].ty, sz(val)));
      modify12(1, a[i].ty, query2(1, a[i].ty, sz(val)));
      modify1(1, 1, a[i].ty, a[i].y);
    } else if (a[i].c == 0) {
      // log("query12 %d >> %d (- %d)\n", a[i].ty, query12(1, a[i].ty, sz(val)), a[i].x + a[i].y);
      updmin(ans, query12(1, a[i].ty, sz(val)) - a[i].x - a[i].y);
    }
    // log("i=%d >> (%d %d %d) >> ans=%d\n", i, a[i].x, a[i].y, a[i].c, ans);
    // assert(ans > 0);
  }
}

int main() {
#ifdef memset0
  // freopen("D.in", "r", stdin);
  freopen("data.txt", "r", stdin);
#endif
  cin.tie(0)->sync_with_stdio(0);
  cin >> n;
  for (int i = 1; i <= n; i++) {
    cin >> a[i].x >> a[i].y >> a[i].oc;
  }
  ans = inf;
  for (int t = 0; t < 1; t++) {
    for (int r = 0; r < 4; r++) {
      val.clear();
      for (int i = 1; i <= n; i++) {
        val.push_back(a[i].y);
      }
      sort(all(val));
      val.erase(unique(all(val)), val.end());
      for (int i = 1; i <= n; i++) {
        a[i].ty = lower_bound(all(val), a[i].y) - val.begin() + 1;
      }
      solve(0, 1, 2);
      solve(0, 2, 1);
      solve(1, 0, 2);
      solve(1, 2, 0);
      solve(2, 0, 1);
      solve(2, 1, 0);
      for (int i = 1; i <= n; i++) {
        swap(a[i].x, a[i].y), a[i].y *= -1;
      }
    }
    for (int i = 1; i <= n; i++) {
      a[i].y *= -1;
    }
  }
  cout << (ans << 1) << endl;
}
accuracy: 1
time_ms: 1180
memory_kb: 14544
final_rank: 2

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

using ui = unsigned;
using ll = long long;
using ull = unsigned long long;
using ld = long double;
#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,l,r) for(int i=(l);i>=(r);--i)
#define repn(i,n) for(int i=0;i<(n);++i)
#define sizc(x) ((int)(x).size())
#define allc(x) (x).begin(),(x).end()
#define fir first
#define sec second

constexpr int N = 1e5+5;
constexpr ll inf = 1e18;
void Min(ll &x,ll y){if(y<x)x=y;}

int n;
struct qwq{
    ll x,y;
    int c;
    bool operator<(const qwq &o)const{
        return x<o.x;
    }
}a[N];
int lsh[N];
int ord[3];
ll ans=inf;

vector<int> vl[N],vr[N];

void dc(int l,int r){
    if(r-l+1<3)return;
    int mid=l+r>>1;
    dc(l,mid),dc(mid+1,r);
    set<pair<ll,int>> sy1;
    per(i,mid,l){
        if(ord[a[i].c]==1)sy1.emplace(a[i].y,i);
        if(ord[a[i].c]==0){
            auto it=sy1.lower_bound({a[i].y,0});
            if(it!=sy1.end())
                vl[it->sec].push_back(i);
            if(it!=sy1.begin())
                vl[prev(it)->sec].push_back(i);
        }
    }
    sy1.clear();
    rep(i,mid+1,r){
        if(ord[a[i].c]==1)sy1.emplace(a[i].y,i);
        if(ord[a[i].c]==2){
            auto it=sy1.lower_bound({a[i].y,0});
            if(it!=sy1.end())
                vr[it->sec].push_back(i);
            if(it!=sy1.begin())
                vr[prev(it)->sec].push_back(i);
        }
    }
}
struct segt{
    ll c[N<<1];
    void init(){
        rep(i,1,2*n-1)c[i]=inf;
    }
    void ins(int x,ll y){
        x+=n-1;
        while(x&&c[x]>y)c[x]=y,x>>=1;
    }
    ll qry(int l,int r){
        ll ret=1e18;
        l+=n-1,r+=n-1;
        while(l<=r){
            if(l&1)Min(ret,c[l++]);
            if(~r&1)Min(ret,c[r--]);
            l>>=1,r>>=1;
        }
        return ret;
    }
}t1,t2,t3;

signed main(){
	// freopen("square.in","r",stdin);
	// freopen("square.out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

    cin>>n;
    rep(i,1,n)cin>>a[i].x>>a[i].y>>a[i].c;
    sort(a+1,a+n+1);
    rep(i,1,n)lsh[i]=a[i].y;
    sort(lsh+1,lsh+n+1);
    rep(i,1,n)a[i].y=lower_bound(lsh+1,lsh+n+1,a[i].y)-lsh;
    repn(i,3)ord[i]=i;
    do{
        rep(i,1,n)vl[i]=vr[i]={};
        dc(1,n);
        t1.init(),t2.init(),t3.init();
        rep(i,1,n){
            if(ord[a[i].c]==0){
                ll vy=lsh[a[i].y];
                t1.ins(a[i].y,-vy-a[i].x);
                t2.ins(a[i].y,-a[i].x);
                t3.ins(a[i].y,vy-a[i].x);
            }
            if(ord[a[i].c]==1){
                for(auto j:vr[i]){
                    ll xr=a[j].x;
                    int l=a[i].y,r=a[j].y;
                    if(l>r)swap(l,r);
                    Min(ans,xr+t1.qry(1,l-1)+lsh[r]);
                    Min(ans,xr+t2.qry(l,r)+lsh[r]-lsh[l]);
                    Min(ans,xr+t3.qry(r+1,n)-lsh[l]);
                }
            }
        }
        t1.init(),t2.init(),t3.init();
        per(i,n,1){
            if(ord[a[i].c]==2){
                ll vy=lsh[a[i].y];
                t1.ins(a[i].y,-vy+a[i].x);
                t2.ins(a[i].y,a[i].x);
                t3.ins(a[i].y,vy+a[i].x);
            }
            if(ord[a[i].c]==1){
                for(auto j:vl[i]){
                    ll xr=a[j].x;
                    int l=a[i].y,r=a[j].y;
                    if(l>r)swap(l,r);
                    Min(ans,-xr+t1.qry(1,l-1)+lsh[r]);
                    Min(ans,-xr+t2.qry(l,r)+lsh[r]-lsh[l]);
                    Min(ans,-xr+t3.qry(r+1,n)-lsh[l]);
                }
            }
        }
    }while(next_permutation(ord,ord+3));
    cout<<ans*2<<'\n';
}
accuracy: 1
time_ms: 1170
memory_kb: 36876
final_rank: 5

code_snippet: // Yokohama 2020 D(2). Colorful Rectangle
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f, NN = 1e5 + 4;
using VI = vector<int>;
struct BIT {  // 维护前缀最小值的BIT
  int C[NN], sz;
  void init(int n) { sz = n, fill_n(C, sz + 1, INF); }
  void upd(int x, int v) {
    while (x <= sz) C[x] = min(C[x], v), x += x & -x;
  }
  int minv(int x) {
    int r = INF;
    while (x) r = min(r, C[x]), x -= x & -x;
    return r;
  }
} B0, B1;
struct SegTree {  // ml:min{Tᵢ|i≤x}, mr:min{Tᵢ|i≥x}, lr:ml+mr
  int ml[NN * 4], mr[NN * 4], lr[NN * 4], sz;
  void init(int n) {
    sz = n;
    fill_n(ml, 4 * sz, INF), fill_n(mr, 4 * sz, INF), fill_n(lr, 4 * sz, INF);
  }
  inline void up_min(int& x, int v) { x = min(x, v); }
  inline void nd_upd(int o, int vl, int vr) {
    up_min(lr[o], ml[o] + vr), up_min(ml[o], vl), up_min(mr[o], vr);
  }
  inline void push_down(int o) {
    int lc = 2 * o, rc = lc + 1;
    nd_upd(lc, ml[o], mr[o]), nd_upd(rc, ml[o], mr[o]), mr[o] = INF;
  }
  // 更新[qL,qR]中的值域范围为(vl,vr)
  void upd(int qL, int qR, int vl, int vr, int o = 1, int L = 1, int R = -1) {
    if (R == -1) R = sz;  // 参数默认值
    if (qL <= L && R <= qR) return nd_upd(o, vl, vr);
    push_down(o);
    int m = (L + R) / 2;
    if (qL <= m) upd(qL, qR, vl, vr, 2 * o, L, m);
    if (m < qR) upd(qL, qR, vl, vr, 2 * o + 1, m + 1, R);
  }
  int qry(int x, int o = 1, int L = 1, int R = -1) {
    if (R == -1) R = sz;  // 参数默认值
    int m = (L + R) / 2, &v = lr[o];
    if (L == R) return v;
    push_down(o);
    return min(v, x <= m ? qry(x, 2 * o, L, m) : qry(x, 2 * o + 1, m + 1, R));
  }
} T;
struct Pt {
  int x, y, c;
  bool operator<(const Pt& p) const { return x != p.x ? x < p.x : y < p.y; }
};
int solve(vector<Pt>& A) {
  int ans = INF;
  VI ys{0};
  for (const Pt& p : A) ys.push_back(p.y);
  auto pb = begin(ys), pe = end(ys);
  sort(pb + 1, pe);                      // y值离散化到[1,my]中
  int my = unique(pb + 1, pe) - pb - 1;  // 离散化后最大的Y值
  for (Pt& p : A) p.y = lower_bound(pb + 1, pb + my + 1, p.y) - pb;
  sort(begin(A), end(A));                // y值离散化之后所有点排序
  B0.init(my), B1.init(my), T.init(my);  // BIT和SegTree初始化
  for (const Pt& p : A) {
    const int c = p.c, x = p.x, yi = p.y, y = ys[yi], xy = x + y;
    // 0类点，左下角, 记录-(x₀+y₀)的最小值
    if (c == 0) B0.upd(yi, -xy);
    // 1类点,在0↗2的矩形内,更新满足y₀≤y₁的(x₀+y₀)的最小值
    if (c == 1) B1.upd(yi, B0.minv(yi));
    // 2类点, 先找到≤y₂的最小的y₁,然后找到满足y₀≤y₁的-(x₀+y₀)的最小值
    if (c == 2) ans = min(ans, xy + B1.minv(yi));

    // 0类点，左下角, 对于所有的yi≤y≤my，记录它左下方的-(x₀+y₀)的最小值
    if (c == 0) T.upd(yi, my, -xy, INF);
    // ?
    if (c == 1) T.upd(1, yi, INF, y);
    // ?
    if (c == 2) ans = min(ans, T.qry(yi) + x);
  }
  return ans;
}
int main() {
  ios::sync_with_stdio(false), cin.tie(0);
  int n, ans = INF;
  cin >> n;
  vector<Pt> A(n), B(n);
  for (Pt& p : B) cin >> p.x >> p.y >> p.c;
  for (int t = 4; t--;) {
    VI o{0, 1, 2};
    do {  // 三种颜色的顺序打乱
      A = B;
      for (Pt& a : A) a.c = o[a.c];
      ans = min(solve(A), ans);
    } while (next_permutation(begin(o), end(o)));
    for (Pt& b : B) swap(b.x, b.y), b.y = -b.y;  // 旋转
  }
  return printf("%d\n", ans * 2), 0;
}
/*
第一种情况：
--------g
|       |
|  b    |
r-------|
第二种情况：
---b-----
|       |
|       g
r-------|
对于当前的g(xg,yg)，潜在的矩形周长是xg-xr+yb-yr
最小化满足yb≥yg的min{yb}以及yr≤yb的min{-(xr+yr)}
所以需要一个线段树T:
对于任意x，可以查询min{Tᵢ|i≤x}+min{Tᵢ|i≥x}
*/
accuracy: 1
time_ms: 800
memory_kb: 11748
final_rank: 1

code_snippet: #include <bits/stdc++.h>

int ri() {
	int n;
	scanf("%d", &n);
	return n;
}

#define INF 1000000000

struct MinSegTree {
	int n;
	std::vector<int> data;
	std::vector<int> written;
	MinSegTree (int n_) {
		for (n = 1; n < (int) n_; n <<= 1);
		data.resize(n << 1, INF);
	}
	void chmin(int i, int x) {
		for (i += n; i; i >>= 1) data[i] = std::min(data[i], x), written.push_back(i);
	}
	int min(int l, int r) {
		int res = INF;
		for (l += n, r += n; l < r; l >>= 1, r >>= 1) {
			if (r & 1) res = std::min(res, data[--r]);
			if (l & 1) res = std::min(res, data[l++]);
		}
		return res;
	}
	void reset() {
		for (auto i : written) data[i] = INF;
		written.clear();
	}
};
struct MinAddSegTree {
	int n;
	std::vector<int> added;
	std::vector<int> min;
	std::vector<bool> updated;
	std::vector<int> written;
	MinAddSegTree () = default;
	MinAddSegTree (int n_) {
		for (n = 1; n < n_; n <<= 1);
		added.resize(n << 1, 0);
		min.resize(n << 1, INF);
		updated.resize(n << 1);
	}
	void write(int i) {
		if (!updated[i]) {
			updated[i] = true;
			written.push_back(i);
		}
	}
	void flush(int i) {
		if (added[i]) {
			min[i] += added[i];
			if (i < n) {
				added[i << 1] += added[i];
				added[i << 1 | 1] += added[i];
				write(i << 1);
				write(i << 1 | 1);
			}
			added[i] = 0;
		}
	}
	void fetch(int i) {
		write(i);
		min[i] = std::min(min[i << 1], min[i << 1 | 1]);
	}
	template<typename T> void dive(int l, int r, int node, int nodel, int noder, const T &func) {
		flush(node);
		if (r <= nodel || l >= noder) return;
		if (l <= nodel && r >= noder) func(node);
		else {
			int nodem = nodel + (noder - nodel) / 2;
			dive(l, r, node << 1, nodel, nodem, func);
			dive(l, r, node << 1 | 1, nodem, noder, func);
			fetch(node);
		}
	}
	
	void add(int l, int r, int x) {
		dive(l, r, 1, 0, n, [&] (int node) { write(node); added[node] += x; flush(node); });
	}
	int get_min(int l, int r) {
		int res = INF;
		dive(l, r, 1, 0, n, [&] (int node) { res = std::min(res, min[node]); });
		return res;
	}
	void chmin(int i, int x) {
		dive(i, i + 1, 1, 0, n, [&] (int node) { write(node); min[node] = std::min(min[node], x); });
	}
	void reset() {
		for (auto i : written) min[i] = INF, added[i] = 0, updated[i] = false;
		written.clear();
	}
};

struct Point {
	int X;
	int Y;
	int x;
	int y;
	int c;
	bool t;
};
int n;

int solve0(std::vector<Point> points) { // x sorted
	std::sort(points.begin(), points.end(), [] (auto &i, auto &j) {
		if (i.x != j.x) return i.x < j.x;
		return i.y < j.y;
	});
	std::vector<std::array<int, 2> > tmp(n);
	
	int res = INF;
	std::vector<MinSegTree> tree(3, MinSegTree(n));
	for (int i = 0; i < n; i++) {
		int head = 0;
		auto &pt = points[i];
		for (int j = 0; j < 3; j++) if (j != pt.c) 
			tmp[i][head++] = tree[j].min(0, pt.y + 1);
		tree[pt.c].chmin(pt.y, -(pt.X + pt.Y));
	}
	tree.assign(3, MinSegTree(n));
	for (int i = n; i--; ) {
		int head = 0;
		auto &pt = points[i];
		for (int j = 0; j < 3; j++) if (j != pt.c) res = std::min(res, tree[j].min(pt.y, n) + tmp[i][!(head++)]);
		tree[pt.c].chmin(pt.y, pt.X + pt.Y);
	}
	return res;
}
int solve1_1(std::vector<Point> a, std::vector<Point> b) {
	for (auto &i : a) i.t = 0;
	for (auto &i : b) i.t = 1;
	auto c = a;
	c.insert(c.end(), b.begin(), b.end());
	std::sort(c.begin(), c.end(), [&] (auto &i, auto &j) {
		if (i.y != j.y) return i.y > j.y;
		return i.t > j.t;
	});
	
	int cur_xy[3] = {INF, INF, INF};
	static std::vector<MinSegTree> tree;
	if (!tree.size()) tree.assign(3, MinSegTree(n));
	else for (auto &i : tree) i.reset();
	
	int res = INF;
	for (auto i : c) {
		if (i.t) {
			cur_xy[(i.c + 1) % 3] = std::min(cur_xy[(i.c + 1) % 3], i.X + tree[(i.c + 2) % 3].min(0, i.x + 1));
			cur_xy[(i.c + 2) % 3] = std::min(cur_xy[(i.c + 2) % 3], i.X + tree[(i.c + 1) % 3].min(0, i.x + 1));
			tree[i.c].chmin(i.x, i.Y);
		} else res = std::min(res, cur_xy[i.c] - (i.X + i.Y));
	}
	return res;
}
int solve1_2(std::vector<Point> a, std::vector<Point> b) {
	std::vector<int> uncompress[3];
	for (auto &i : b) uncompress[i.c].push_back(i.y);
	for (auto &i : uncompress) std::sort(i.begin(), i.end());
	std::array<std::array<MinAddSegTree, 3>, 3> trees;
	for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) if (i != j)
		trees[i][j] = MinAddSegTree(uncompress[j].size());
	
	auto compress = [&] (int c, int y) {
		return std::lower_bound(uncompress[c].begin(), uncompress[c].end(), y) - uncompress[c].begin();
	};
	for (auto i : b) for (int j = 0; j < 3; j++) if (i.c != j) trees[j][i.c].chmin(compress(i.c, i.y), i.X);
	
	std::sort(a.begin(), a.end(), [] (auto &i, auto &j) {
		if (i.x != j.x) return i.x > j.x;
		return i.y > j.y;
	});
	std::map<int, int> ys[3][3];
	for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) if (i != j) {
		trees[i][j].add(0, uncompress[j].size(), INF);
		ys[i][j][-1] = 0;
		ys[i][j][n] = INF;
	}
	int res = INF;
	for (auto i : a) {
		int r0 = (i.c + 1) % 3, r1 = (i.c + 2) % 3;
		res = std::min(res, trees[r0][r1].get_min(compress(r1, i.y), uncompress[r1].size()) - (i.X + i.Y));
		res = std::min(res, trees[r1][r0].get_min(compress(r0, i.y), uncompress[r0].size()) - (i.X + i.Y));
		
		for (int j = 0; j < 3; j++) if (j != i.c) {
			auto itr = ys[i.c][j].lower_bound(i.y);
			trees[i.c][j].add(compress(j, std::prev(itr)->first + 1), compress(j, i.y + 1), i.Y - itr->second);
			ys[i.c][j][i.y] = i.Y;
		}
	}
	return res;
}
int solve1_rec(const std::vector<Point> &a) {
	int k = a.size();
	if (k < 3) return INF;
	int k2 = k / 2;
	
	std::vector<Point> left(a.begin(), a.begin() + k2), right(a.begin() + k2, a.end());
	int res = std::min(solve1_rec(left), solve1_rec(right));
	res = std::min(res, solve1_1(left, right));
	res = std::min(res, solve1_2(left, right));
	return res;
}
int solve1(std::vector<Point> a) {
	std::sort(a.begin(), a.end(), [] (auto &i, auto &j) {
		if (i.x != j.x) return i.x < j.x;
		return i.y < j.y;
	});
	return solve1_rec(a);
}

int main() {
	n = ri();
	std::vector<Point> points(n);
	std::vector<int> xs, ys;
	for (auto &i : points) {
		i.X = ri();
		i.Y = ri();
		xs.push_back(i.X);
		ys.push_back(i.Y);
		i.c = ri();
	}
	
	std::sort(xs.begin(), xs.end());
	std::sort(ys.begin(), ys.end());
	for (auto &i : points) {
		i.x = std::lower_bound(xs.begin(), xs.end(), i.X) - xs.begin();
		i.y = std::lower_bound(ys.begin(), ys.end(), i.Y) - ys.begin();
	}
	auto rev_y = [&] () { 
		for (auto &i : points) i.y = n - 1 - i.y, i.Y = 100000000 - i.Y;
	};
	auto rev_x = [&] () { 
		for (auto &i : points) i.x = n - 1 - i.x, i.X = 100000000 - i.X;
		std::reverse(points.begin(), points.end());
	};
	
	int res = INF;
	res = std::min(res, solve0(points));
	rev_y();
	res = std::min(res, solve0(points));
	rev_y();
	
	res = std::min(res, solve1(points));
	rev_y();
	res = std::min(res, solve1(points));
	rev_x();
	res = std::min(res, solve1(points));
	rev_y();
	res = std::min(res, solve1(points));
	rev_x();
	
	
	printf("%d\n", res * 2);
	
	return 0;
}
accuracy: 1
time_ms: 4810
memory_kb: 35160
final_rank: 6

code_snippet: #include <bits/stdc++.h>

int ri() {
	int n;
	scanf("%d", &n);
	return n;
}

#define INF 1000000000

struct MinSegTree {
	int n;
	std::vector<int> data;
	std::vector<int> written;
	MinSegTree (int n_) {
		for (n = 1; n < (int) n_; n <<= 1);
		data.resize(n << 1, INF);
	}
	void chmin(int i, int x) {
		for (i += n; i; i >>= 1) data[i] = std::min(data[i], x), written.push_back(i);
	}
	int min(int l, int r) {
		int res = INF;
		for (l += n, r += n; l < r; l >>= 1, r >>= 1) {
			if (r & 1) res = std::min(res, data[--r]);
			if (l & 1) res = std::min(res, data[l++]);
		}
		return res;
	}
	void reset() {
		for (auto i : written) data[i] = INF;
		written.clear();
	}
};
struct MinAddSegTree {
	int n;
	std::vector<int> added;
	std::vector<int> min;
	std::vector<bool> updated;
	std::vector<int> written;
	MinAddSegTree () = default;
	MinAddSegTree (int n_) {
		for (n = 1; n < n_; n <<= 1);
		added.resize(n << 1, 0);
		min.resize(n << 1, INF);
		updated.resize(n << 1);
	}
	void write(int i) {
		if (!updated[i]) {
			updated[i] = true;
			written.push_back(i);
		}
	}
	void flush(int i) {
		if (added[i]) {
			min[i] += added[i];
			if (i < n) {
				added[i << 1] += added[i];
				added[i << 1 | 1] += added[i];
				write(i << 1);
				write(i << 1 | 1);
			}
			added[i] = 0;
		}
	}
	void fetch(int i) {
		write(i);
		min[i] = std::min(min[i << 1], min[i << 1 | 1]);
	}
	template<typename T> void dive(int l, int r, int node, int nodel, int noder, const T &func) {
		flush(node);
		if (r <= nodel || l >= noder) return;
		if (l <= nodel && r >= noder) func(node);
		else {
			int nodem = nodel + (noder - nodel) / 2;
			dive(l, r, node << 1, nodel, nodem, func);
			dive(l, r, node << 1 | 1, nodem, noder, func);
			fetch(node);
		}
	}
	
	void add(int l, int r, int x) {
		dive(l, r, 1, 0, n, [&] (int node) { write(node); added[node] += x; flush(node); });
	}
	int get_min(int l, int r) {
		int res = INF;
		dive(l, r, 1, 0, n, [&] (int node) { res = std::min(res, min[node]); });
		return res;
	}
	void chmin(int i, int x) {
		dive(i, i + 1, 1, 0, n, [&] (int node) { write(node); min[node] = std::min(min[node], x); });
	}
	void reset() {
		for (auto i : written) min[i] = INF, added[i] = 0, updated[i] = false;
		written.clear();
	}
};

struct Point {
	int X;
	int Y;
	int x;
	int y;
	int c;
	bool t;
};
int n;

int solve0(std::vector<Point> points) { // x sorted
	std::sort(points.begin(), points.end(), [] (auto &i, auto &j) {
		if (i.x != j.x) return i.x < j.x;
		return i.y < j.y;
	});
	std::vector<std::array<int, 2> > tmp(n);
	
	int res = INF;
	std::vector<MinSegTree> tree(3, MinSegTree(n));
	for (int i = 0; i < n; i++) {
		int head = 0;
		auto &pt = points[i];
		for (int j = 0; j < 3; j++) if (j != pt.c) 
			tmp[i][head++] = tree[j].min(0, pt.y + 1);
		tree[pt.c].chmin(pt.y, -(pt.X + pt.Y));
	}
	tree.assign(3, MinSegTree(n));
	for (int i = n; i--; ) {
		int head = 0;
		auto &pt = points[i];
		for (int j = 0; j < 3; j++) if (j != pt.c) res = std::min(res, tree[j].min(pt.y, n) + tmp[i][!(head++)]);
		tree[pt.c].chmin(pt.y, pt.X + pt.Y);
	}
	return res;
}
int solve1_1(std::vector<Point> a, std::vector<Point> b) {
	for (auto &i : a) i.t = 0;
	for (auto &i : b) i.t = 1;
	auto c = a;
	c.insert(c.end(), b.begin(), b.end());
	std::sort(c.begin(), c.end(), [&] (auto &i, auto &j) {
		if (i.y != j.y) return i.y > j.y;
		return i.t > j.t;
	});
	
	int cur_xy[3] = {INF, INF, INF};
	static std::vector<MinSegTree> tree;
	if (!tree.size()) tree.assign(3, MinSegTree(n));
	else for (auto &i : tree) i.reset();
	
	int res = INF;
	for (auto i : c) {
		if (i.t) {
			cur_xy[(i.c + 1) % 3] = std::min(cur_xy[(i.c + 1) % 3], i.X + tree[(i.c + 2) % 3].min(0, i.x + 1));
			cur_xy[(i.c + 2) % 3] = std::min(cur_xy[(i.c + 2) % 3], i.X + tree[(i.c + 1) % 3].min(0, i.x + 1));
			tree[i.c].chmin(i.x, i.Y);
		} else res = std::min(res, cur_xy[i.c] - (i.X + i.Y));
	}
	return res;
}
int solve1_2(std::vector<Point> a, std::vector<Point> b) {
	std::vector<int> uncompress[3];
	for (auto &i : b) uncompress[i.c].push_back(i.y);
	for (auto &i : uncompress) std::sort(i.begin(), i.end());
	std::array<std::array<MinAddSegTree, 3>, 3> trees;
	for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) if (i != j)
		trees[i][j] = MinAddSegTree(uncompress[j].size());
	
	auto compress = [&] (int c, int y) {
		return std::lower_bound(uncompress[c].begin(), uncompress[c].end(), y) - uncompress[c].begin();
	};
	for (auto i : b) for (int j = 0; j < 3; j++) if (i.c != j) trees[j][i.c].chmin(compress(i.c, i.y), i.X);
	
	std::sort(a.begin(), a.end(), [] (auto &i, auto &j) {
		if (i.x != j.x) return i.x > j.x;
		return i.y > j.y;
	});
	std::map<int, int> ys;
	ys[-1] = 0;
	ys[n] = INF;
	for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) if (i != j) trees[i][j].add(0, uncompress[j].size(), INF);
	int res = INF;
	for (auto i : a) {
		int r0 = (i.c + 1) % 3, r1 = (i.c + 2) % 3;
		res = std::min(res, trees[r0][r1].get_min(compress(r1, i.y), uncompress[r1].size()) - (i.X + i.Y));
		res = std::min(res, trees[r1][r0].get_min(compress(r0, i.y), uncompress[r0].size()) - (i.X + i.Y));
		
		auto itr = ys.lower_bound(i.y);
		for (int j = 0; j < 3; j++) if (j != i.c) trees[i.c][j].add(compress(j, std::prev(itr)->first + 1), compress(j, i.y + 1), i.Y - itr->second);
		ys[i.y] = i.Y;
	}
	return res;
}
int solve1_rec(const std::vector<Point> &a) {
	int k = a.size();
	if (k < 3) return INF;
	int k2 = k / 2;
	
	std::vector<Point> left(a.begin(), a.begin() + k2), right(a.begin() + k2, a.end());
	int res = std::min(solve1_rec(left), solve1_rec(right));
	res = std::min(res, solve1_1(left, right));
	res = std::min(res, solve1_2(left, right));
	return res;
}
int solve1(std::vector<Point> a) {
	std::sort(a.begin(), a.end(), [] (auto &i, auto &j) {
		if (i.x != j.x) return i.x < j.x;
		return i.y < j.y;
	});
	return solve1_rec(a);
}

int main() {
	n = ri();
	std::vector<Point> points(n);
	std::vector<int> xs, ys;
	for (auto &i : points) {
		i.X = ri();
		i.Y = ri();
		xs.push_back(i.X);
		ys.push_back(i.Y);
		i.c = ri();
	}
	
	std::sort(xs.begin(), xs.end());
	std::sort(ys.begin(), ys.end());
	for (auto &i : points) {
		i.x = std::lower_bound(xs.begin(), xs.end(), i.X) - xs.begin();
		i.y = std::lower_bound(ys.begin(), ys.end(), i.Y) - ys.begin();
	}
	auto rev_y = [&] () { 
		for (auto &i : points) i.y = n - 1 - i.y, i.Y = 100000000 - i.Y;
	};
	auto rev_x = [&] () { 
		for (auto &i : points) i.x = n - 1 - i.x, i.X = 100000000 - i.X;
		std::reverse(points.begin(), points.end());
	};
	
	int res = INF;
	res = std::min(res, solve0(points));
	rev_y();
	res = std::min(res, solve0(points));
	rev_y();
	
	res = std::min(res, solve1(points));
	rev_y();
	res = std::min(res, solve1(points));
	rev_x();
	res = std::min(res, solve1(points));
	rev_y();
	res = std::min(res, solve1(points));
	rev_x();
	
	
	printf("%d\n", res * 2);
	
	return 0;
}
accuracy: 0.4574468085106383
time_ms: 3570
memory_kb: 35212
final_rank: 7

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define rep(i, n) for (int i = 0; i < (n); ++i)
#define all(c) std::begin(c), std::end(c)

#ifdef LOCAL
#define debug(...) debug_impl(#__VA_ARGS__, __VA_ARGS__)
template <class T, class ... Args> void debug_impl(string s, T&& first, Args &&...args) {
    string opn = sizeof...(args) == 0 ? "" : "(";
    string cls = sizeof...(args) == 0 ? "" : ")";
    cerr << "[\033[32mDEBUG\033[m] " << opn << s << cls << ": " << opn << forward<T>(first);
    ((cerr << ", " << forward<Args>(args)), ..., (cerr << cls << '\n'));
}
#else
#define debug(...) void(0)
#endif

template <typename T> bool chmax(T& a, const T& b) { return b > a ? (a = b, true) : false; }
template <typename T> bool chmin(T& a, const T& b) { return b < a ? (a = b, true) : false; }

template <class T> istream& operator>>(istream& in, vector<T>& v) {
    for (auto& e : v) in >> e;
    return in;
}
template <class ...Args> void read(Args &...args) {
    (cin >> ... >> args);
}
template <class T> ostream& operator<<(ostream& out, const vector<T>& v) {
    int n = v.size();
    rep(i, n) {
        out << v[i];
        if (i + 1 != n) out << ' ';
    }
    return out;
}
template <class H, class ...T> void print(H&& h, T &&...t) {
    cout << h, ((cout << ' ' << forward<T>(t)), ..., (cout << '\n'));
}

template <typename T, T(*op)(T, T), T(*e)()>
struct segtree {
    int n;
    vector<T> dat;

    segtree(int n = 0) : n(n), dat(2 * n, e()) {}

    T prod(int l, int r) {
        T res = e();
        for (l += n, r += n; l < r; l >>= 1, r >>= 1) {
            if (l & 1) res = op(res, dat[l++]);
            if (r & 1) res = op(res, dat[--r]);
        }
        return res;
    }
    void set(int i, T v) {
        i += n;
        dat[i] = v;
        while (i >>= 1) dat[i] = op(dat[2 * i], dat[2 * i + 1]);
    }
    T get(int i) {
        return dat[i + n];
    }
};

constexpr long long inf = numeric_limits<long long>::max() / 100;

namespace ns_maxseg_pair {
    using S = pair<long long, long long>;
    S op(S x, S y) {
        return max(x, y);
    }
    S e() {
        return { -inf, -inf };
    }
};
using maxseg_pair = segtree<ns_maxseg_pair::S, ns_maxseg_pair::op, ns_maxseg_pair::e>;

namespace ns_maxseg {
    long long op(long long x, long long y) {
        return max(x, y);
    }
    long long e() {
        return -inf;
    }
};
using maxseg = segtree<long long, ns_maxseg::op, ns_maxseg::e>;

namespace ns_minseg {
    long long op(long long x, long long y) {
        return min(x, y);
    }
    long long e() {
        return +inf;
    }
};
using minseg = segtree<long long, ns_minseg::op, ns_minseg::e>;

template <typename T>
struct Compressor {
    vector<T> vs;
    void add(T x) { vs.push_back(x); }
    void build() {
        sort(all(vs));
        vs.erase(unique(all(vs)), vs.end());
    }
    int size() const {
        return vs.size();
    }
    int operator[](int v) const {
        return lower_bound(all(vs), v) - vs.begin();
    }
    int comp(int v) const {
        return (*this)[v];
    }
    int decomp(int i) const {
        return vs[i];
    }
};

constexpr int MAXV = 100000000;

long long solve_case2(array<vector<pair<int, int>>, 3> points) {
    long long res = numeric_limits<long long>::max();

    rep(xloop, 2) {
        rep(yloop, 2) {
            Compressor<int> comp;
            rep(c, 3) {
                for (auto [x, y] : points[c]) {
                    comp.add(y);
                }
            }
            comp.build();
            const int m = comp.size();

            maxseg_pair xmax1(m), ymax2(m);

            int j = 0, k = 0;
            rep(i, int(points[0].size())) {
                for (; j < int(points[1].size()) and points[1][j].first <= points[0][i].first; ++j) {
                    auto [x, y] = points[1][j];
                    int idx = comp[y];
                    xmax1.set(idx, ns_maxseg_pair::op(xmax1.get(idx), { x, y }));
                }
                for (; k < int(points[2].size()) and points[2][k].first <= points[0][i].first; ++k) {
                    auto [x, y] = points[2][k];
                    int idx = comp[y];
                    ymax2.set(idx, ns_maxseg_pair::op(ymax2.get(idx), { y, x }));
                }

                auto [x, y] = points[0][i];
                int idx_r = comp[y];

                auto [x1, y1] = xmax1.prod(0, idx_r + 1);
                auto [y2, x2] = ymax2.prod(0, idx_r + 1);

                if (y1 < y2) continue;
                if (x2 < x1) continue;

                chmin(res, ((x - x1) + (y - y2)) * 2);
            }

            rep(c, 3) for (auto& [x, y] : points[c]) {
                y = MAXV - y;
            }
        }

        Compressor<int> comp;
        rep(c, 3) {
            for (auto [x, y] : points[c]) {
                comp.add(y);
            }
        }
        comp.build();
        const int m = comp.size();

        const int t = points[0].size();
        vector<long long> ans(t);

        maxseg xymax2(m);

        int k = 0;
        rep(i, int(points[0].size())) {
            for (; k < int(points[2].size()) and points[2][k].first <= points[0][i].first; ++k) {
                auto [x, y] = points[2][k];
                int idx = comp[y];
                xymax2.set(idx, ns_maxseg::op(xymax2.get(idx), x + y));
            }
            auto [x, y] = points[0][i];
            int idx_r = comp[y];

            auto xy = xymax2.prod(0, idx_r + 1);
            ans[i] += (x + y) - xy;
        }

        minseg xymin1(m);

        int j = points[1].size() - 1;
        for (int i = points[0].size() - 1; i >= 0; --i) {
            for (; j >= 0 and points[1][j].first >= points[0][i].first; --j) {
                auto [x, y] = points[1][j];
                int idx = comp[y];
                xymin1.set(idx, ns_minseg::op(xymin1.get(idx), x + y));
            }
            auto [x, y] = points[0][i];
            int idx_l = comp[y];

            auto xy = xymin1.prod(idx_l, m);
            ans[i] += xy - (x + y);
        }

        rep(i, t) {
            long long v = ans[i];
            chmin(res, 2 * v);
        }
        rep(c, 3) {
            for (auto& [x, y] : points[c]) {
                x = MAXV - x;
            }
            reverse(all(points[c]));
        }
    }

    return res;
}

int main() {
    int n;
    read(n);

    array<vector<pair<int, int>>, 3> points{};
    rep(i, n) {
        int x, y, c;
        read(x, y, c);
        points[c].emplace_back(x, y);
    }

    rep(c, 3) {
        sort(all(points[c]));
    }

    vector<int> p(3);
    iota(all(p), 0);

    long long ans = numeric_limits<long long>::max();

    do {
        array<vector<pair<int, int>>, 3> points2;
        rep(i, 3) {
            points2[p[i]] = points[i];
        }
        chmin(ans, solve_case2(points2));
    } while (next_permutation(all(p)));

    print(ans);
}
accuracy: 0.05319148936170213
time_ms: 70
memory_kb: 4040
final_rank: 8

code_snippet: #include <iostream>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <vector>
#include <numeric>
#include <algorithm>
#include <queue>
#include <string>
#include <random>
#include <array>
#include <climits>
#include <map>
#include <cassert>
#include <stack>
#include <iomanip>
#include <cfloat>
#include <bitset>
#include <fstream>
#include <chrono>
struct Point {
	int x, y, color;
};

class MaxBit {
	std::vector<int> vec;
public:
	MaxBit(const int size) :vec(size, INT_MIN) {};
	int get(int position) const {
		int result = INT_MIN;
		while (0 <= position) {
			result = std::max(result, vec[position]);
			position -= ~position & (position + 1);
		}
		return result;
	}
	void add(int position, const int value) {
		while (position < vec.size()) {
			vec[position] = std::max(vec[position], value);
			position += ~position & (position + 1);
		}
	}
};

int main() {
	int n; std::cin >> n;
	std::vector<Point> points(n);
	for (auto& [x, y, color] : points) {
		std::cin >> x >> y >> color;
	}
	std::vector<int> all_x, all_y;
	std::transform(points.begin(), points.end(), std::back_inserter(all_x), [](const auto a) {return a.x; });
	std::transform(points.begin(), points.end(), std::back_inserter(all_y), [](const auto a) {return a.y; });
	std::sort(all_x.begin(), all_x.end()); all_x.erase(std::unique(all_x.begin(), all_x.end()), all_x.end());
	std::sort(all_y.begin(), all_y.end()); all_y.erase(std::unique(all_y.begin(), all_y.end()), all_y.end());
	for (auto& [x, y, _] : points) {
		x = std::distance(all_x.begin(), std::lower_bound(all_x.begin(), all_x.end(), x));
		y = std::distance(all_y.begin(), std::lower_bound(all_y.begin(), all_y.end(), y));
	}
	int result = INT_MAX;
	for (auto _i = 0; _i < 4; ++_i) {
		for (auto& [x, y, _]: points) {
			const auto next_x = y;
			const auto next_y = all_x.size() - 1 - x;
			x = next_x;
			y = next_y;
		}
		std::swap(all_x, all_y);
		std::reverse(all_y.begin(), all_y.end());
		for (auto& y : all_y) {
			y *= -1;
		}
		std::vector<std::vector<Point>> by_x(n);
		for (const auto& point : points) {
			by_x[point.x].push_back(point);
		}
		std::vector<std::map<int, int>> most_right_y(3);
		std::vector<std::vector<std::vector<std::pair<int, int>>>> left_tops(n, std::vector<std::vector<std::pair<int, int>>>(3));
		std::vector<MaxBit> max_single(3, MaxBit(n)), max_double(3, MaxBit(n));
		for (auto& line : by_x) {
			std::sort(line.begin(), line.end(), [](const auto a, const auto b) {return a.y < b.y; });
			for (const auto point : line) {
				auto& set = most_right_y[point.color];
				for (auto iter = set.upper_bound(point.y); iter != set.end(); iter = set.erase(iter));
				set.insert_or_assign(point.y, point.x);
				max_single[point.color].add(point.y, all_x[point.x] + all_y[point.y]);
				for (auto left_color = 0; left_color < 3; ++left_color) {
					if (point.color == left_color) continue;
					const auto left_iter = most_right_y[left_color].upper_bound(point.y);
					if (left_iter != most_right_y[left_color].begin()) {
						const auto [y, x] = *std::prev(left_iter);
						left_tops[point.x][3 - point.color - left_color].emplace_back(y, all_y[point.y] - all_x[x]);
					}
					const auto left_bottom = max_single[left_color].get(point.y);
					if (left_bottom != INT_MIN) {
						max_double[3 - point.color - left_color].add(point.y, left_bottom);
					}
				}
				const auto left_bottom = max_double[point.color].get(point.y);
				if (left_bottom != INT_MIN) {
					const auto perimeter = (all_x[point.x] + all_y[point.y] - left_bottom) * 2;
					result = std::min(result, perimeter);
				}
			}
		}
		std::vector<MaxBit> right_bottom(3, MaxBit(n));
		std::reverse(by_x.begin(), by_x.end());
		for (const auto& line : by_x) {
			if (line.empty()) continue;
			for (const auto point : line) {
				right_bottom[point.color].add(point.y, all_y[point.y] - all_x[point.x]);
			}
			const auto& left_top = left_tops[line.front().x];
			for (auto color = 0; color < 3; ++color) {
				for (const auto [y, yx] : left_top[color]) {
					const auto rb = right_bottom[color].get(y);
					if (rb != INT_MIN) {
						const auto perimeter = (yx - rb) * 2;
						result = std::min(result, perimeter);
					}
				}
			}
		}
	}
	std::cout << result << '\n';
}
accuracy: 0.05319148936170213
time_ms: 20
memory_kb: 6308
final_rank: 10

code_snippet: //Let's join Kaede Takagaki Fan Club !!
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cassert>
#include <string>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <functional>
#include <iostream>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <cassert>
#include <iomanip>
#include <chrono>
#include <random>
#include <bitset>
#include <complex>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

#include <algorithm>

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace atcoder {

namespace internal {

// @param n `0 <= n`
// @return minimum non-negative `x` s.t. `n <= 2**x`
int ceil_pow2(int n) {
    int x = 0;
    while ((1U << x) < (unsigned int)(n)) x++;
    return x;
}

// @param n `1 <= n`
// @return minimum non-negative `x` s.t. `(n & (1 << x)) != 0`
int bsf(unsigned int n) {
#ifdef _MSC_VER
    unsigned long index;
    _BitScanForward(&index, n);
    return index;
#else
    return __builtin_ctz(n);
#endif
}

}  // namespace internal

}  // namespace atcoder

#include <cassert>
#include <iostream>
#include <vector>
namespace atcoder {

template <class S,
          S (*op)(S, S),
          S (*e)(),
          class F,
          S (*mapping)(F, S),
          F (*composition)(F, F),
          F (*id)()>
struct lazy_segtree {
  public:
    lazy_segtree() : lazy_segtree(0) {}
    lazy_segtree(int n) : lazy_segtree(std::vector<S>(n, e())) {}
    lazy_segtree(const std::vector<S>& v) : _n(int(v.size())) {
        log = internal::ceil_pow2(_n);
        size = 1 << log;
        d = std::vector<S>(2 * size, e());
        lz = std::vector<F>(size, id());
        for (int i = 0; i < _n; i++) d[size + i] = v[i];
        for (int i = size - 1; i >= 1; i--) {
            update(i);
        }
    }

    void set(int p, S x) {
        assert(0 <= p && p < _n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        d[p] = x;
        for (int i = 1; i <= log; i++) update(p >> i);
    }

    S get(int p) {
        assert(0 <= p && p < _n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        return d[p];
    }

    S prod(int l, int r) {
        assert(0 <= l && l <= r && r <= _n);
        if (l == r) return e();

        l += size;
        r += size;

        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push(r >> i);
        }

        S sml = e(), smr = e();
        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1;
            r >>= 1;
        }

        return op(sml, smr);
    }

    S all_prod() { return d[1]; }

    void apply(int p, F f) {
        assert(0 <= p && p < _n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        d[p] = mapping(f, d[p]);
        for (int i = 1; i <= log; i++) update(p >> i);
    }
    void apply(int l, int r, F f) {
        assert(0 <= l && l <= r && r <= _n);
        if (l == r) return;

        l += size;
        r += size;

        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push((r - 1) >> i);
        }

        {
            int l2 = l, r2 = r;
            while (l < r) {
                if (l & 1) all_apply(l++, f);
                if (r & 1) all_apply(--r, f);
                l >>= 1;
                r >>= 1;
            }
            l = l2;
            r = r2;
        }

        for (int i = 1; i <= log; i++) {
            if (((l >> i) << i) != l) update(l >> i);
            if (((r >> i) << i) != r) update((r - 1) >> i);
        }
    }

    template <bool (*g)(S)> int max_right(int l) {
        return max_right(l, [](S x) { return g(x); });
    }
    template <class G> int max_right(int l, G g) {
        assert(0 <= l && l <= _n);
        assert(g(e()));
        if (l == _n) return _n;
        l += size;
        for (int i = log; i >= 1; i--) push(l >> i);
        S sm = e();
        do {
            while (l % 2 == 0) l >>= 1;
            if (!g(op(sm, d[l]))) {
                while (l < size) {
                    push(l);
                    l = (2 * l);
                    if (g(op(sm, d[l]))) {
                        sm = op(sm, d[l]);
                        l++;
                    }
                }
                return l - size;
            }
            sm = op(sm, d[l]);
            l++;
        } while ((l & -l) != l);
        return _n;
    }

    template <bool (*g)(S)> int min_left(int r) {
        return min_left(r, [](S x) { return g(x); });
    }
    template <class G> int min_left(int r, G g) {
        assert(0 <= r && r <= _n);
        assert(g(e()));
        if (r == 0) return 0;
        r += size;
        for (int i = log; i >= 1; i--) push((r - 1) >> i);
        S sm = e();
        do {
            r--;
            while (r > 1 && (r % 2)) r >>= 1;
            if (!g(op(d[r], sm))) {
                while (r < size) {
                    push(r);
                    r = (2 * r + 1);
                    if (g(op(d[r], sm))) {
                        sm = op(d[r], sm);
                        r--;
                    }
                }
                return r + 1 - size;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }

  private:
    int _n, size, log;
    std::vector<S> d;
    std::vector<F> lz;

    void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); }
    void all_apply(int k, F f) {
        d[k] = mapping(f, d[k]);
        if (k < size) lz[k] = composition(f, lz[k]);
    }
    void push(int k) {
        all_apply(2 * k, lz[k]);
        all_apply(2 * k + 1, lz[k]);
        lz[k] = id();
    }
};

}  // namespace atcoder

using namespace std;
using namespace atcoder;
#define int long long
//#define L __int128
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())
#define pcnt(x) __builtin_popcountll(x)

#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<<"}";
}
 
 //https://codeforces.com/blog/entry/62393
struct custom_hash {
	static uint64_t splitmix64(uint64_t x) {
		// http://xorshift.di.unimi.it/splitmix64.c
		x += 0x9e3779b97f4a7c15;
		x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
		x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
		return x ^ (x >> 31);
	}
 
	size_t operator()(uint64_t x) const {
		static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
		return splitmix64(x + FIXED_RANDOM);
	}
	//don't make x negative!
	size_t operator()(pair<int,int> x)const{
		return operator()(uint64_t(x.first)<<32|x.second);
	}
};
//unordered_set -> dtype, null_type
//unordered_map -> dtype(key), dtype(value)
using namespace __gnu_pbds;
template<class t,class u>
using hash_table=gp_hash_table<t,u,custom_hash>;

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 = 998244353;
//const ll mod = 1000000007;
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 BIT{
	#define bsz 100005
	int val[bsz];
	void init(){
		fill(val, val+bsz, 1e18);
	}
	void update(int pos, int v){
		pos ++;
		for(;pos<bsz;pos+=pos&-pos) chmin(val[pos], v);
	}
	int get(int pos){
		pos ++;
		int ret = 1e18;
		while(pos){
			chmin(ret, val[pos]);
			pos -= pos&-pos;
		}
		return ret;
	}
}bit[7];

using S = array<int, 6>;
using F = array<int, 3>;
S op(S a, S b){
	rep(i, 6) chmin(a[i], b[i]);
	return a;
}
S e(){ return S{INF, INF, INF, INF, INF, INF}; }
S mapping(F f, S x){
	rep(i, 3){
		if(f[i] == INF) continue;
		rep(j, 3){
			if(i == j) continue;
			chmin(x[2+i+j], x[j]+f[i]);
		}
	}
	return x;
}
F composition(F f, F g){
	rep(i, 3) chmin(f[i], g[i]);
	return f;
}
F id(){ return F{INF, INF, INF}; }

int sol(vc<P1>pt){
	int minx=INF, miny=INF;
	rep(i, pt.size()){
		chmin(minx, pt[i].b.a);
		chmin(miny, pt[i].b.b);
	}
	//cout<<pt<<endl;
	rep(i, pt.size()){
		pt[i].b.a -= minx;
		pt[i].b.b -= miny;
	}
	//cout<<pt<<endl;
	sort(all(pt), [](P1 a, P1 b){
		return a.b < b.b;
	});
	vc<int>zx, zy;
	int n = pt.size();
	rep(i, n){
		zx.pb(pt[i].b.a);
		zy.pb(pt[i].b.b);
	}
	SORT(zx); SORT(zy);
	ERASE(zx); ERASE(zy);
	rep(i, n){
		pt[i].b.a = POSL(zx, pt[i].b.a);
		pt[i].b.b = POSL(zy, pt[i].b.b);
	}
	int ret = 1e18;
	//order
	rep(b, 7) bit[b].init();
	rep(i, n){
		//set one
		bit[(1<<pt[i].a)].update(pt[i].b.b, -zx[pt[i].b.a]-zy[pt[i].b.b]);
		//set two
		rep(j, 3){
			if(j == pt[i].a) continue;
			int mask = (1<<j) + (1<<pt[i].a);
			int up = bit[(1<<j)].get(pt[i].b.b);
			bit[mask].update(pt[i].b.b, up);
		}
		//set three
		{
			int mask = 7-(1<<pt[i].a);
			int up = bit[mask].get(pt[i].b.b);
			up += zx[pt[i].b.a] + zy[pt[i].b.b];
			chmin(ret, up);
		}
	}
	//cout << ret << endl;

	//ret = 1e18;
	//difficult
	lazy_segtree<S, op, e, F, mapping, composition, id> seg(n);
	for(int i=n-1;i>=0;i--){
		//set three
		auto up = seg.prod(pt[i].b.b, n);
		chmin(ret, up[5-pt[i].a]-zx[pt[i].b.a]-zy[pt[i].b.b]);
		//set two
		auto ff = id();
		ff[pt[i].a] = zy[pt[i].b.b];
		seg.apply(0, pt[i].b.b, ff);
		//set one
		auto now = seg.get(pt[i].b.b);
		chmin(now[pt[i].a], zx[pt[i].b.a]);
		seg.set(pt[i].b.b, now);
	}
	//cout << ret << endl;
	return ret;
}
void solve(){
	int n; 
	cin >> n; //n=100000; //cin >> n;
	vc<P1>vec(n);
	rep(i, n){
		//vec[i].b.a=mt()%100000000;
		//vec[i].b.b=mt()%100000000;
		//vec[i].a=mt()%3;
		cin >> vec[i].b.a >> vec[i].b.b >> vec[i].a;
	}
	int ans = 1e18;
	chmin(ans, sol(vec));
	for(int i=0;i<n;i++){
		vec[i].b.a *= -1;
	}
	chmin(ans, sol(vec));
	for(int i=0;i<n;i++){
		vec[i].b.b *= -1;
	}
	chmin(ans, sol(vec));
	for(int i=0;i<n;i++){
		vec[i].b.a *= -1;
	}
	chmin(ans, sol(vec));
	o(ans*2);
}
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: 600
memory_kb: 36468
final_rank: 4