hdu6800
#include <iostream>
#include <string.h>
#include <queue>
#include <stack>
#include <map>
#include <stdio.h>
#include <algorithm>
#include <math.h>
#include <unordered_map>
using namespace std;
typedef long long LL;
typedef pair<int, int> P;
const int maxn = 1e5 + 10;
const int maxm=maxn*18+10,maxl=maxm*8+10;
struct node{
LL a[4];
node & operator = (const node &n2)
{
a[0]=n2.a[0];
a[1]=n2.a[1];
a[2]=n2.a[2];
a[3]=n2.a[3];
return *this;
}
};
int pool[maxm],*pool_tail;
node info[maxl],*info_tail;
inline void reset()
{
pool_tail=pool;
info_tail=info;
}
inline int * ask32(int len)
{
int *ret=pool_tail;
pool_tail+=len;
return ret;
}
inline node * ask256(int len)
{
node *ret=info_tail;
info_tail+=len;
return ret;
}
int n,qtot;
LL dp[maxn];
P seq[maxn],que[maxn];
inline void upd_min(LL &x,LL y)
{
if(x>y)
x=y;
}
inline bool cmp_y(int const &u,int const &v)
{
return que[u].second<que[v].second;
}
struct Segment{
int ytot,*yque;
node *info;
}seg[maxn<<1|1];
inline int seg_idx(int L,int R)
{
return (L+R)|(L<R);
}
void seg_init_inner(Segment &rt,int L, int R)
{
if(L==R)
{
return;
}
int M=(L+R)>>1;
seg_init_inner(rt, L, M);
seg_init_inner(rt, M+1, R);
node *cur=rt.info+seg_idx(L, R);
node *lft=rt.info+seg_idx(L, M);
node *rht=rt.info+seg_idx(M+1, R);
cur->a[0]=min(lft->a[0],rht->a[0]);
cur->a[1]=min(lft->a[1],rht->a[1]);
cur->a[2]=min(lft->a[2],rht->a[2]);
cur->a[3]=min(lft->a[3],rht->a[3]);
}
void seg_init_outer(int L,int R)
{
static int ord[maxn];
if(L<R)
{
int M=(L+R)>>1;
seg_init_outer(L, M);
seg_init_outer(M+1, R);
inplace_merge(ord+L, ord+M+1, ord+R+1, cmp_y);
}
else
{
ord[L]=L;
}
Segment &rt=seg[seg_idx(L, R)];
rt.ytot=1;
for(int i=L+1;i<=R;i++)
{
rt.ytot+=cmp_y(ord[i-1], ord[i]);
}
rt.yque=ask32(rt.ytot);
rt.info=ask256( 2*rt.ytot-1);
for(int i=L,j=0;i<=R;j++)
{
int u=ord[i++],y=que[u].second,xL=que[u].first,xR=xL;
for(int v;i<=R&&!cmp_y(u, v=ord[i]);i++)
{
int tmp=que[v].first;
if(tmp<xL)
{
xL=tmp;
}else if(tmp>xR)
{
xR=tmp;
}
}
rt.yque[j]=y;
node *val=rt.info+(seg_idx(j, j));
val->a[0]=xL+y;
val->a[1]=-xR+y;
val->a[2]=-xR-y;
val->a[3]=xL-y;
}
seg_init_inner(rt, 0, rt.ytot-1);
}
inline void seg_update_inner(Segment &rt,int y,node val)
{
for(int L=0,R=rt.ytot-1;L<=R;)
{
node * cur=rt.info+seg_idx(L, R);
upd_min(cur->a[0], val.a[0]);
upd_min(cur->a[1], val.a[1]);
upd_min(cur->a[2], val.a[2]);
upd_min(cur->a[3], val.a[3]);
if(L==R)
break;
int M=(L+R)>>1;
if(y<=rt.yque[M])
R=M;
else
L=M+1;
}
}
inline void seg_update_outer(int pos)
{
int x=que[pos].first,y=que[pos].second;
LL v=dp[pos];
node val;
val.a[0]=v+x+y;
val.a[1]=v-x+y;
val.a[2]=v-x-y;
val.a[3]=v+x-y;
for(int L=0,R=qtot-1;L<=R;)
{
seg_update_inner(seg[seg_idx(L, R)], y, val);
if(L==R)
break;
int M=(L+R)>>1;
if(pos<=M)
R=M;
else
L=M+1;
}
}
inline LL seg_query_left_inner(Segment &rt, int x, int y) {
LL ret = LLONG_MAX;
for(int L = 0, R = rt.ytot - 1; L <= R; ) {
node *cur = rt.info + seg_idx(L, R);
if(y <= rt.yque[L]) {
upd_min(ret, cur->a[1] - y);
break;
} else if(y >= rt.yque[R]) {
upd_min(ret, cur->a[2] + y);
break;
}
int M = (L + R) >> 1;
if(y <= rt.yque[M]) {
node *rht = rt.info + seg_idx(M + 1, R);
upd_min(ret, rht->a[1] - y);
R = M;
} else {
node *lft = rt.info + seg_idx(L, M);
upd_min(ret, lft->a[2] + y);
L = M + 1;
}
}
if(ret != LLONG_MAX)
ret += x;
return ret;
}
inline LL seg_query_right_inner(Segment &rt, int x, int y) {
LL ret = LLONG_MAX;
for(int L = 0, R = rt.ytot - 1; L <= R; ) {
node *cur = rt.info + seg_idx(L, R);
if(y <= rt.yque[L]) {
upd_min(ret, cur->a[0] - y);
break;
} else if(y >= rt.yque[R]) {
upd_min(ret, cur->a[3] + y);
break;
}//已经可以确定在哪个象限有答案了
int M = (L + R) >> 1;
if(y <= rt.yque[M]) {
node *rht = rt.info + seg_idx(M + 1, R);
//在右上方的点的贡献也可以算了
upd_min(ret, rht->a[0] - y);
R = M;//从新区间L-M再来
} else {
node *lft = rt.info + seg_idx(L, M);
upd_min(ret, lft->a[3] + y);
L = M + 1;
}
}
if(ret != LLONG_MAX)
ret -= x;
return ret;
}
inline LL seg_query_outer(int pos) {
int x = que[pos].first, y = que[pos].second;
LL ret = dp[pos];
for(int L = 0, R = qtot - 1; L < R; ) {
int M = (L + R) >> 1;
if(pos <= M) {
upd_min(ret, seg_query_right_inner(seg[seg_idx(M + 1, R)], x, y));
R = M;
} else {
upd_min(ret, seg_query_left_inner(seg[seg_idx(L, M)], x, y));
L = M + 1;
}
}
return ret;
}
void solve() {
scanf("%d", &n);
for(int i = 0; i < n; ++i) {
scanf("%d%d", &seq[i].first, &seq[i].second);
que[i] = seq[i];
dp[i] = 0;
}
sort(que, que + n);
qtot = unique(que, que + n) - que;
reset();
seg_init_outer(0, qtot - 1);//线段树初始化
LL ans = 0, sum = 0;
int las = lower_bound(que, que + qtot, seq[0]) - que;
for(int i = 1; i < n; ++i) {
LL adt = abs(seq[i].first - seq[i - 1].first) + abs(seq[i].second - seq[i - 1].second);
int pos = lower_bound(que, que + qtot, seq[i]) - que;
LL best = seg_query_outer(pos) - adt;//以换手的代价跑到pos,省了多少的代价
if(dp[las] > best) {//比已经省下的多
ans=min(ans , dp[las] = best );
seg_update_outer(las);
}
sum += adt;
las = pos;
}
printf("%lld\n", ans + sum);
}
int main() {
int T;
scanf("%d", &T);
for(int Case = 1; Case <= T; ++Case) {
// printf("Case #%d:\n", Case);
solve();
}
return 0;
}