Problem:
Score : 2200 points

Problem Statement

You are given positions (X_i, Y_i) of N enemy rooks on an infinite chessboard.
No two rooks attack each other (at most one rook per row or column).

You're going to replace one rook with a king and then move the king repeatedly to beat as many rooks as possible.

You can't enter a cell that is being attacked by a rook.
Additionally, you can't move diagonally to an empty cell (but you can beat a rook diagonally).

(So this king moves like a superpawn that beats diagonally in 4 directions and moves horizontally/vertically in 4 directions.)

For each rook, consider replacing it with a king, and find the minimum possible number of moves
needed to beat the maximum possible number of rooks.

Constraints

2 \leq N \leq 200\,000

1 \leq X_i, Y_i \leq 10^6

X_i \neq X_j

Y_i \neq Y_j

All values in input are integers.

Input

Input is given from Standard Input in the following format.

N
X_1 Y_1
X_2 Y_2
\vdots
X_N Y_N

Output

Print N lines.
The i-th line is for scenario of replacing the rook at (X_i, Y_i) with your king.
This line should contain one integer: the minimum number of moves to beat M_i rooks
where M_i denotes the maximum possible number of beaten rooks in this scenario (in infinite time).

Sample Input 1

6
1 8
6 10
2 7
4 4
9 3
5 1

Sample Output 1

5
0
7
5
0
0

See the drawing below.
If we replace rook 3 with a king, we can beat at most two other rooks.
The red path is one of optimal sequences of moves: beat rook 1,
then keep going down and right until you can beat rook 4.
There are 7 steps and that's the third number in the output.

x-coordinate increases from left to right,
while y increases bottom to top.

Starting from rook 2, 5 or 6, we can't beat any other rook.
The optimal number of moves is 0.

Sample Input 2

5
5 5
100 100
70 20
81 70
800 1

Sample Output 2

985
985
1065
1034
0

Sample Input 3

10
2 5
4 4
13 12
12 13
14 17
17 19
22 22
16 18
19 27
25 26

Sample Output 3

2
2
9
9
3
3
24
5
0
25

Solution in C++ (GCC 9.2.1) (judge verdict: Wrong Answer)

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
typedef double db;
mt19937 mrand(random_device{}()); 
const ll mod=1000000007;
int rnd(int x) { return mrand() % x;}
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
// head

const int N = 400010;
int n, m, a[N];
ll ans[N],disL[N],disR[N];
int cc[N];
vector<array<int,3>> pos;
VI vy;
int x[N],y[N],ww[N],posl[N],posr[N];
bool sg[N];

namespace xihetree {
#define rg register

int st1[N], st2[N], tp1, tp2, rt;
int L[N], R[N], M[N], id[N], cnt, typ[N], bin[20], st[N], tp;
//本篇代码原题应为 CERC2017 Intrinsic Interval
// a数组即为原题中对应的排列
// st1和st2分别两个单调栈，tp1、tp2为对应的栈顶，rt为析合树的根
// L、R数组表示该析合树节点的左右端点，M数组的作用在析合树构造时有提到
// id存储的是排列中某一位置对应的节点编号，typ用于标记析点还是合点
// st为存储析合树节点编号的栈，tp为其栈顶
struct RMQ {  // 预处理 RMQ（Max & Min）
  int lg[N], mn[N][17], mx[N][17];
  void chkmn(int& x, int y) {
    if (x > y) x = y;
  }
  void chkmx(int& x, int y) {
    if (x < y) x = y;
  }
  void build() {
    for (int i = bin[0] = 1; i < 20; ++i) bin[i] = bin[i - 1] << 1;
    for (int i = 2; i <= n; ++i) lg[i] = lg[i >> 1] + 1;
    for (int i = 1; i <= n; ++i) mn[i][0] = mx[i][0] = a[i];
    for (int i = 1; i < 17; ++i)
      for (int j = 1; j + bin[i] - 1 <= n; ++j)
        mn[j][i] = min(mn[j][i - 1], mn[j + bin[i - 1]][i - 1]),
        mx[j][i] = max(mx[j][i - 1], mx[j + bin[i - 1]][i - 1]);
  }
  int ask_mn(int l, int r) {
    int t = lg[r - l + 1];
    return min(mn[l][t], mn[r - bin[t] + 1][t]);
  }
  int ask_mx(int l, int r) {
    int t = lg[r - l + 1];
    return max(mx[l][t], mx[r - bin[t] + 1][t]);
  }
} D;
// 维护 L_i

struct SEG {  // 线段树
#define ls (k << 1)
#define rs (k << 1 | 1)
  int mn[N << 1], ly[N << 1];  // 区间加；区间最小值
  void pushup(int k) { mn[k] = min(mn[ls], mn[rs]); }
  void mfy(int k, int v) { mn[k] += v, ly[k] += v; }
  void pushdown(int k) {
    if (ly[k]) mfy(ls, ly[k]), mfy(rs, ly[k]), ly[k] = 0;
  }
  void update(int k, int l, int r, int x, int y, int v) {
    if (l == x && r == y) {
      mfy(k, v);
      return;
    }
    pushdown(k);
    int mid = (l + r) >> 1;
    if (y <= mid)
      update(ls, l, mid, x, y, v);
    else if (x > mid)
      update(rs, mid + 1, r, x, y, v);
    else
      update(ls, l, mid, x, mid, v), update(rs, mid + 1, r, mid + 1, y, v);
    pushup(k);
  }
  int query(int k, int l, int r) {  // 询问 0 的位置
    if (l == r) return l;
    pushdown(k);
    int mid = (l + r) >> 1;
    if (!mn[ls])
      return query(ls, l, mid);
    else
      return query(rs, mid + 1, r);
    // 如果不存在 0 的位置就会自动返回当前你查询的位置
  }
} T;

int o = 1, hd[N], dep[N], fa[N][18];
int tot=0;
struct Edge {
  int v, nt;
} E[N << 1];
int disto(int u,int v) {
	return abs(x[u]-x[v])+abs(y[u]-y[v]);
}
void add(int u, int v) {  // 树结构加边
  E[o] = (Edge){v, hd[u]};
  hd[u] = o++;
}

void ddfs(int u) {
	int sg=L[u]==R[u];
	L[u]=tot+1;
	if (sg) tot++;
	VI child;
	  for (int i = hd[u]; i; i = E[i].nt) {
	    int v = E[i].v;
	    child.pb(v);
	}
	reverse(all(child));
	for (auto v:child) {
	    ddfs(v);
	  }
	R[u]=tot;
}
void dfs(int u) {
	//printf("u %d L %d R %d type %d\n",u,L[u],R[u],typ[u]);
	//printf("disL %lld disR %lld cnt %d\n",disL[u],disR[u],cc[u]);
	if (L[u]==R[u]) {
		ans[ww[L[u]]]=min(disL[u],disR[u])-cc[u];
		return;
	}
	if (typ[u]==1) {
		VI child;
	  	for (int i = hd[u]; i; i = E[i].nt) {
	    	int v = E[i].v;
	    	child.pb(v);
	    	sg[v]=L[v]==R[v];
		}
		reverse(all(child));
		int gol=0;
		rep(i,0,SZ(child)) {
			if (!sg[child[i]]) {
				posl[i]=gol;
				gol=i+1;
			} else {
				posl[i]=gol;
			}
		}
		int gor=SZ(child)-1;
		per(i,0,SZ(child)) {
			if (!sg[child[i]]) {
				posr[i]=gor;
				gor=i-1;
				//printf("nsg %d %d\n",u,i);
			} else {
				posr[i]=gor;
			}
		}
		rep(i,0,SZ(child)) {
			int v=child[i];
			int l=L[child[posl[i]]],r=R[child[posr[i]]];
			//printf("zzzzz %d %d %d\n",v,posl[i],posr[i]);;
			if (posl[i]==0&&posr[i]==SZ(child)-1) {
				cc[v]=cc[u]+r-l-(R[v]-L[v]);
				if (i!=0&&i!=SZ(child)-1) {
					disL[v]=min(disL[u]+disto(L[v],r),disR[u]+disto(L[v],l))+disto(r,l);
					disR[v]=min(disL[u]+disto(R[v],r),disR[u]+disto(R[v],l))+disto(r,l);
				} else if (i==0) {
					disL[v]=min(disL[u]+disto(L[v],r),disR[u]+disto(L[v],l))+disto(r,l);
					disR[v]=min(disL[u]+disto(R[v],r)+disto(r,l),disR[u]+disto(R[v],r));	
				} else {
					disL[v]=min(disL[u]+disto(L[v],l),disR[u]+disto(L[v],l)+disto(r,l));
					disR[v]=min(disL[u]+disto(R[v],r),disR[u]+disto(R[v],l))+disto(r,l);

				}
				//printf("gggggg %d %d %d\n",r,l,disto(r,l));
				//printf("zzz %d %d %d %d\n",cc[u],r-l,R[v]-L[v],cc[u]+r-l-(R[v]-L[v]));
			} else {
				cc[v]=r-l-(R[v]-L[v]);
				if (posl[i]!=i&&posr[i]!=i) {
					disL[v]=min(disto(L[v],r),disto(L[v],l))+disto(r,l);
					disR[v]=min(disto(R[v],r),disto(R[v],l))+disto(r,l);
				} else if (posr[i]!=i) {
					disL[v]=disto(L[v],r);
					disR[v]=disto(R[v],r);
				} else if (posl[i]!=i) {
					disL[v]=disto(L[v],l);
					disR[v]=disto(R[v],l);					
				} else {
					//printf("fuck ")
				}
			}
		}
	}
	//if (typ[u]==)
  for (int i = hd[u]; i; i = E[i].nt) {
    int v = E[i].v;
    //printf("edge %d %d\n",u,v);
    dep[v] = dep[u] + 1;
    dfs(v);
  }
}

// 判断当前区间是否为连续段
bool judge(int l, int r) { return D.ask_mx(l, r) - D.ask_mn(l, r) == r - l; }

// 建树
void build() {
  for (int i = 1; i <= n; ++i) {
    // 单调栈
    // 在区间 [st1[tp1-1]+1,st1[tp1]] 的最小值就是 a[st1[tp1]]
    // 现在把它出栈，意味着要把多减掉的 Min 加回来。
    // 线段树的叶结点位置 j 维护的是从 j 到当前的 i 的
    // Max{j,i}-Min{j,i}-(i-j)
    // 区间加只是一个 Tag。
    // 维护单调栈的目的是辅助线段树从 i-1 更新到 i。
    // 更新到 i 后，只需要查询全局最小值即可知道是否有解

    while (tp1 && a[i] <= a[st1[tp1]])  // 单调递増的栈，维护 Min
      T.update(1, 1, n, st1[tp1 - 1] + 1, st1[tp1], a[st1[tp1]]), tp1--;
    while (tp2 && a[i] >= a[st2[tp2]])
      T.update(1, 1, n, st2[tp2 - 1] + 1, st2[tp2], -a[st2[tp2]]), tp2--;

    T.update(1, 1, n, st1[tp1] + 1, i, -a[i]);
    st1[++tp1] = i;
    T.update(1, 1, n, st2[tp2] + 1, i, a[i]);
    st2[++tp2] = i;

    id[i] = ++cnt;
    L[cnt] = R[cnt] = i;  // 这里的 L,R 是指值域的上下界
    int le = T.query(1, 1, n), now = cnt;
    while (tp && L[st[tp]] >= le) {
      if (typ[st[tp]] && judge(M[st[tp]], i)) {
        // 判断是否能成为儿子，如果能就做
        R[st[tp]] = i, add(st[tp], now), now = st[tp--];
      } else if (judge(L[st[tp]], i)) {
        typ[++cnt] = 1;  // 合点一定是被这样建出来的
        L[cnt] = L[st[tp]], R[cnt] = i, M[cnt] = L[now];
        // 这里M数组的作用是保证合点的儿子排列是单调的
        add(cnt, st[tp--]), add(cnt, now);
        now = cnt;
      } else {
        add(++cnt, now);  // 新建一个结点，把 now 添加为儿子
        // 如果从当前结点开始不能构成连续段，就合并。
        // 直到找到一个结点能构成连续段。而且我们一定能找到这样
        // 一个结点。
        do
          add(cnt, st[tp--]);
        while (tp && !judge(L[st[tp]], i));
        L[cnt] = L[st[tp]], R[cnt] = i, add(cnt, st[tp--]);
        now = cnt;
      }
    }
    st[++tp] = now;  // 增量结束，把当前点压栈

    T.update(1, 1, n, 1, i, -1);  // 因为区间右端点向后移动一格，因此整体 -1
  }

  rt = st[1];  // 栈中最后剩下的点是根结点
}
void gao() {
  D.build();
  build();
  ddfs(rt);
  dfs(rt);
}
}

int main() {
	scanf("%d",&n);
	rep(i,1,n+1) {
		scanf("%d%d",x+i,y+i);
		pos.pb({x[i],y[i],i});
		vy.pb(y[i]);
	}
	sort(all(pos));
	sort(all(vy));
	rep(i,0,n) {
		ww[i+1]=pos[i][2];
		x[i+1]=pos[i][0];
		y[i+1]=pos[i][1];
		a[i+1]=lower_bound(all(vy),pos[i][1])-vy.begin()+1;
	//	printf("%d ",a[i+1]);
	}
	//puts("");
	xihetree::gao();
	rep(i,1,n+1) printf("%lld\n",ans[i]);
}