Problem:
Problem K: Move on Ice
Problem
ペンギンのフロロは無限に広い氷の上のマス($sx$,$sy$)にいる。
マス($tx$,$ty$)に穴があり、そこから水に入ることができる。
氷の上に$n$個の氷の塊があり、それぞれマス($x_i$,$y_i$)にある。
フロロは上下左右の4方向に移動できる。
氷の上は滑りやすいので、移動すると氷の塊にぶつかるまで動き続ける。
氷の塊にぶつかると氷の塊のあるマスの1マス手前で止まる。
穴のマスを通過することで穴に入ることができる。
フロロは1度だけ全力で踏ん張ることにより途中で止まることができる。
氷の塊にぶつかると痛いのでできるだけぶつかる回数を少なくしたい。
穴のあるマス($tx$,$ty$)へ移動するまでにぶつかる回数の最小値を求めよ。
辿り着けない場合は$-$1を出力せよ。
Input
入力は以下の形式で与えられる。
$sx$ $sy$
$tx$ $ty$
$n$
$x_1$ $y_1$
...
$x_n$ $y_n$
入力はすべて整数で与えられる。
1行目にフロロがいるマスの座標が空白区切りで与えられる。
2行目に穴があるマスの座標が空白区切りで与えられる。
3行目に氷の塊の数$n$が与えられる。
続く$n$行目に氷の塊があるマスの座標が空白区切りで与えられる。
Constraints
入力は以下の条件を満たす。
$0 \leq n \leq 10^5$
$0 \leq sx$,$sy$,$tx$,$ty$,$x_i$,$y_i \leq 10^9$
与えられる座標はすべて異なる
Output
穴に移動するまでにぶつかる回数の最小値を出力せよ。
辿り着けない場合は$-$1を出力せよ。
Sample Input 1
0 0
13 33
2
0 34
14 0
Sample Output 1
0
Sample Input 2
0 1
5 0
4
2 1
1 3
4 2
3 0
Sample Output 2
4
Sample Input 3
0 0
0 2
1
0 1
Sample Output 3
-1

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define F first
#define S second
#define rep(i,n) for(int i=0;i<(int)(n);i++)
typedef pair<int,int> P;
typedef pair<int,P> PP;
int dx[4]={0,-1,0,1},dy[4]={-1,0,1,0},INF=1e9+7;
int d[111111][4],d2[111111][4];
map<int,vector<PP> > m[2],m2[2];
P a[111111];
set<int> se[2];
map<int,int> ma[2];
map<int,vector<P> > mm[2];

class RMQ{
public:
  int n,dat[1111111];
  void init(int _n){
    n=1;while(n<_n)n*=2;
    fill(dat,dat+2*n-1,INF);
  }
  void update(int k,int a){
    k+=n-1;dat[k]=a;
    while(k>0){
      k=(k-1)/2;
      dat[k]=min(dat[k*2+1],dat[k*2+2]);
    }
  }
  int query(int a,int b){return query(a,b,0,0,n);}
  int query(int a,int b,int k,int l,int r){
    if(r<=a||b<=l) return INF;
    if(a<=l&&r<=b) return dat[k];
    int vl=query(a,b,k*2+1,l,(l+r)/2);
    int vr=query(a,b,k*2+2,(l+r)/2,r);
    return min(vl,vr);
  }
};

RMQ r;
int main() {
  int n,sx,sy,tx,ty;
  cin >> sx >> sy >> tx >> ty >> n;
  for(int i=0; i<n; i++) cin >> a[i].F >> a[i].S;
  a[n]=P(sx,sy);
  a[n+1]=P(tx,ty);
  rep(i,n+2) {
    if(i==n) continue;
    m[0][a[i].F].push_back(PP(a[i].S,P(i,0)));
    m[0][a[i].F].push_back(PP(a[i].S,P(i,2)));
    m[1][a[i].S].push_back(PP(a[i].F,P(i,1)));
    m[1][a[i].S].push_back(PP(a[i].F,P(i,3)));
  }
  rep(i,2) {
    for(map<int,vector<PP> >::iterator it=m[i].begin();it!=m[i].end();it++) {
      sort(it->S.begin(),it->S.end());
    }
  }
  rep(i,111111)rep(j,4)d[i][j]=INF;
  queue<P> que;
  rep(i,4) {
    que.push(P(n,i));
    d[n][i]=0;
  }
  while(!que.empty()) {
    P p=que.front();que.pop();
    int x=a[p.F].F,y=a[p.F].S,t=p.S;
    if(p.F!=n) x+=dx[t],y+=dy[t];
    if(t%2) {
      if(!m[0].count(x)) continue;
      int k=upper_bound(m[0][x].begin(),m[0][x].end(),PP(y,P(-INF,-INF)))-m[0][x].begin();
      if(k!=m[0][x].size()) {
        PP q=m[0][x][k];
        if(d[q.S.F][q.S.S]>d[p.F][t]+1) {
          d[q.S.F][q.S.S]=d[p.F][t]+1;
          que.push(P(q.S.F,q.S.S));
        }
      }
      k--;
      if(k>=0) {
        PP q=m[0][x][k];
        if(d[q.S.F][q.S.S]>d[p.F][t]+1) {
          d[q.S.F][q.S.S]=d[p.F][t]+1;
          que.push(P(q.S.F,q.S.S));
        }
      }
    } else {
      if(!m[1].count(y)) continue;
      int k=upper_bound(m[1][y].begin(),m[1][y].end(),PP(x,P(-INF,-INF)))-m[1][y].begin();
      if(k!=m[1][y].size()) {
        PP q=m[1][y][k];
        if(d[q.S.F][q.S.S]>d[p.F][t]+1) {
          d[q.S.F][q.S.S]=d[p.F][t]+1;
          que.push(P(q.S.F,q.S.S));
        }
      }
      k--;
      if(k>=0) {
        PP q=m[1][y][k];
        if(d[q.S.F][q.S.S]>d[p.F][t]+1) {
          d[q.S.F][q.S.S]=d[p.F][t]+1;
          que.push(P(q.S.F,q.S.S));
        }
      }
    }
  }
  rep(i,n+2) {
    if(i<n) {
      m2[0][a[i].F-1].push_back(PP(a[i].S,P(i,1)));
      m2[0][a[i].F+1].push_back(PP(a[i].S,P(i,3)));
      m2[1][a[i].S-1].push_back(PP(a[i].F,P(i,0)));
      m2[1][a[i].S+1].push_back(PP(a[i].F,P(i,2)));
      m2[0][a[i].F].push_back(PP(a[i].S-1,P(INF,-1)));
      m2[0][a[i].F].push_back(PP(a[i].S+1,P(-INF,-1)));
      m2[1][a[i].S].push_back(PP(a[i].F-1,P(INF,-1)));
      m2[1][a[i].S].push_back(PP(a[i].F+1,P(-INF,-1)));
    } else {
      m2[0][a[i].F].push_back(PP(a[i].S,P(i,1)));
      m2[0][a[i].F].push_back(PP(a[i].S,P(i,3)));
      m2[1][a[i].S].push_back(PP(a[i].F,P(i,0)));
      m2[1][a[i].S].push_back(PP(a[i].F,P(i,2)));
    }
  }
  rep(i,2) {
    for(map<int,vector<PP> >::iterator it=m2[i].begin();it!=m2[i].end();it++) {
      sort(it->S.begin(),it->S.end());
    }
  }
  rep(i,111111)rep(j,4)d2[i][j]=INF;
  rep(i,4) {
    que.push(P(n+1,i));
    d2[n+1][i]=0;
  }
  while(!que.empty()) {
    P p=que.front();que.pop();
    int x=a[p.F].F,y=a[p.F].S,t=p.S;
    x+=dx[t],y+=dy[t];
    if(t==0) {
      int k=lower_bound(m2[0][x].begin(),m2[0][x].end(),PP(y,P(INF,-1)))-m2[0][x].begin()-1;
      while(k>=0&&m2[0][x][k].S.S!=-1) {
        PP q=m2[0][x][k];
        if(a[q.S.F].S<=y&&d2[q.S.F][q.S.S]>d2[p.F][t]+1) {
          d2[q.S.F][q.S.S]=d2[p.F][t]+1;
          que.push(P(q.S.F,q.S.S));
        }
        k--;
      }
    } else if(t==1) {
      int k=lower_bound(m2[1][y].begin(),m2[1][y].end(),PP(x,P(INF,-1)))-m2[1][y].begin()-1;
      while(k>=0&&m2[1][y][k].S.S!=-1) {
        PP q=m2[1][y][k];
        if(a[q.S.F].F<=x&&d2[q.S.F][q.S.S]>d2[p.F][t]+1) {
          d2[q.S.F][q.S.S]=d2[p.F][t]+1;
          que.push(P(q.S.F,q.S.S));
        }
        k--;
      }
    } else if(t==2) {
      int k=upper_bound(m2[0][x].begin(),m2[0][x].end(),PP(y,P(-INF,-1)))-m2[0][x].begin();
      while(k<m2[0][x].size()&&m2[0][x][k].S.S!=-1) {
        PP q=m2[0][x][k];
        if(y<=a[q.S.F].S&&d2[q.S.F][q.S.S]>d2[p.F][t]+1) {
          d2[q.S.F][q.S.S]=d2[p.F][t]+1;
          que.push(P(q.S.F,q.S.S));
        }
        k++;
      }
    } else {
      int k=upper_bound(m2[1][y].begin(),m2[1][y].end(),PP(x,P(-INF,-1)))-m2[1][y].begin();
      while(k<m2[1][y].size()&&m2[1][y][k].S.S!=-1) {
        PP q=m2[1][y][k];
        if(x<=a[q.S.F].F&&d2[q.S.F][q.S.S]>d2[p.F][t]+1) {
          d2[q.S.F][q.S.S]=d2[p.F][t]+1;
          que.push(P(q.S.F,q.S.S));
        }
        k++;
      }
    }
  }
  int ans=INF;
  rep(i,4) ans=min(ans,d[n+1][i]);
  if(ans!=INF) ans--;
  rep(i,n+2) {
    rep(j,3) {
      se[0].insert(a[i].F-1+j);
      se[1].insert(a[i].S-1+j);
    }
  }
  se[0].insert(-INF);
  se[0].insert(INF);
  se[1].insert(-INF);
  se[1].insert(INF);
  rep(i,2) {
    int k=0;
    for(set<int>::iterator it=se[i].begin();it!=se[i].end();it++) ma[i][*it]=k++;
  }
  rep(t,2) {
    rep(i,2) mm[i].clear();
    if(t) {
      rep(i,n+2) {
        if(i<n) {
          mm[0][a[i].F].push_back(P(a[i].S-1,d[i][0]));
          mm[0][a[i].F].push_back(P(a[i].S+1,d[i][2]));
          mm[0][a[i].F].push_back(P(a[i].S,-1));
        } else {
          mm[0][a[i].F].push_back(P(a[i].S,d[i][0]));
          mm[0][a[i].F].push_back(P(a[i].S,d[i][2]));
        }
        mm[1][a[i].F].push_back(P(a[i].S,i));
      }
    } else {
      rep(i,n+2) {
        if(i<n) {
          mm[0][a[i].S].push_back(P(a[i].F-1,d[i][1]));
          mm[0][a[i].S].push_back(P(a[i].F+1,d[i][3]));
          mm[0][a[i].S].push_back(P(a[i].F,-1));
        } else {
          mm[0][a[i].S].push_back(P(a[i].F,d[i][1]));
          mm[0][a[i].S].push_back(P(a[i].F,d[i][3]));
        }
        mm[1][a[i].S].push_back(P(a[i].F,i));
      }
    }
    for(map<int,vector<P> >::iterator it=mm[1].begin();it!=mm[1].end();it++) {
      if(it->S.size()) {
        it->S.push_back(P(-INF,INF));
        it->S.push_back(P(INF,INF));
        sort(it->S.begin(),it->S.end());
      }
    }
    rep(k,2) {
      map<int,vector<P> >::iterator it2=mm[1].begin();
      r.init(se[t].size());
      for(map<int,vector<P> >::iterator it=mm[0].begin();;it++) {
        while(it2!=mm[1].end()&&(it==mm[0].end()||it2->F<it->F)) {
          vector<P> v=it2->S;
          rep(i,v.size()-1) {
            int x,y;
            if(t) {
              if(v[i].S==INF) x=INF;
              else x=d2[v[i].S][2];
              if(v[i+1].S==INF) y=INF;
              else y=d2[v[i+1].S][0];
            } else {
              if(v[i].S==INF) x=INF;
              else x=d2[v[i].S][3];
              if(v[i+1].S==INF) y=INF;
              else y=d2[v[i+1].S][1];
            }
            ans=min(ans,r.query(ma[t][v[i].F],ma[t][v[i+1].F])+min(x,y));
          }
          it2++;
        }
        if(it==mm[0].end()) break;
        vector<P> v=it->S;
        rep(i,v.size()) {
          int x=ma[t][v[i].F];
          r.update(x,v[i].S==-1?INF:min(r.query(x,x+1),v[i].S));
        }
      }
      map<int,vector<P> > mm2[2];
      rep(i,2)for(map<int,vector<P> >::iterator it=mm[i].begin();it!=mm[i].end();it++) mm2[i][-it->F]=it->S;
      rep(i,2)mm[i]=mm2[i];
    }
  }
  cout << (ans==INF?-1:ans) << endl;
  return 0;
}
accuracy: 1
time_ms: 1730
memory_kb: 150716
final_rank: 6

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<complex>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<utility>
using namespace std;
typedef long long ll;
typedef unsigned int ui;
const ll mod = 1000000007;
const ll INF = (ll)1000000007 * 1000000007;
typedef pair<int, int> P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
typedef long double ld;
typedef complex<ld> Point;
const ld eps = 1e-6;
const ld pi = acos(-1.0);
typedef pair<ll, ll> LP;

int n;
int sx, sy, gx, gy;

struct vertice {
	int x, y, f;
	bool operator<(const vertice &v)const {
		if (x != v.x)return x < v.x;
		if (y != v.y)return y < v.y;
		return f < v.f;
	}
	bool operator==(const vertice &v)const {
		if (x == v.x&&y == v.y&&f == v.f)return true;
		return false;
	}
};

void compress(vector<vertice> &v) {
	int n = v.size();
	vector<LP> x, y;
	rep(i, n) {
		x.push_back({ v[i].x,i });
		y.push_back({ v[i].y,i });
	}
	sort(x.begin(), x.end());
	sort(y.begin(), y.end());
	int cur = 0;
	rep(i, n) {
		v[x[i].second].x = cur;
		while (i + 1 < n&&x[i].first == x[i + 1].first) {
			i++; v[x[i].second].x = cur;
		}
		cur++;
	}
	cur = 0;
	rep(i, n) {
		v[y[i].second].y = cur;
		while (i + 1 < n&&y[i].first == y[i + 1].first) {
			i++; v[y[i].second].y = cur;
		}
		cur++;
	}
}

vector<vertice> v; map<P, int> inv;

const int mn = 500005;
vector<P> cx[mn], cy[mn];

int d[2][mn];
priority_queue<P, vector<P>, greater<P>> q;
vector<int> G[mn];
void dijkstra(int id, int root) {
	d[id][root] = 0;
	q.push({ 0,root });
	while (!q.empty()) {
		P p = q.top(); q.pop();
		int i = p.second; int dist = p.first;
		int x = v[i].x, y = v[i].y;
		//x軸
		int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
		loc--;
		if (loc >= 0 && loc < cx[x].size()) {
			int ni = cx[x][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{x, cx[x][loc].first + 1}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					G[ni].push_back(i);
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
				G[ni].push_back(i);
			}
		}
		loc++;
		if (v[i].f >= 2)loc++;
		if (loc < cx[x].size()) {
			int ni = cx[x][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{x, cx[x][loc].first - 1}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
					G[ni].push_back(i);
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
				G[ni].push_back(i);
			}
		}
		//y軸
		loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
		loc--;
		if (loc >= 0 && loc<cy[y].size()) {
			int ni = cy[y][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{cy[y][loc].first + 1, y}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
					G[ni].push_back(i);
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
				G[ni].push_back(i);
			}
		}
		loc++;
		if (v[i].f >= 2)loc++;
		if (loc < cy[y].size()) {
			int ni = cy[y][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{cy[y][loc].first - 1, y}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
					G[ni].push_back(i);
				}
			}
			if (dist + 1 < d[id][ni]) {
				d[id][ni] = min(d[id][ni], dist);
				G[ni].push_back(i);
			}
		}
	}
}
int sid;
void invdijkstra(int root) {
	d[1][root] = 0;
	q.push({ 0,root });
	while (!q.empty()) {
		P p = q.top(); q.pop();
		int i = p.second;
		rep(j, G[i].size()) {
			int to = G[i][j];
			if (to == sid)d[1][sid] = min(d[1][sid], p.first);
			else {
				if (p.first + 1 < d[1][to]) {
					d[1][to] = p.first + 1;
					q.push({ d[1][to],to });
				}
			}
		}
	}
}
int ans = mod;

struct SegT {
private:
	int sz; vector<int> node;
	const int init_c = mod;
public:
	SegT(int n) {
		sz = 1;
		while (sz < n)sz *= 2;
		node.resize(2 * sz - 1, init_c);
	}
	int f(int a, int b) {
		return min(a, b);
	}
	void update(int k, int a) {
		k += sz - 1;
		node[k] = a;
		while (k > 0) {
			k = (k - 1) / 2;
			node[k] = f(node[k * 2 + 1], node[k * 2 + 2]);
		}
	}
	int query(int a, int b, int k = 0, int l = 0, int r = -1) {
		if (r < 0)r = sz;
		if (r <= a || b <= l)return init_c;
		else if (a <= l && r <= b)return node[k];
		else {
			int vl = query(a, b, k * 2 + 1, l, (l + r) / 2);
			int vr = query(a, b, k * 2 + 2, (l + r) / 2, r);
			return f(vl, vr);
		}
	}
};
int len;

//全頂点が入ってるほう
vector<P> ux[mn], uy[mn];
//下から
void calc1() {
	SegT st(mn);
	rep(i, mn) {
		rep(j, ux[i].size()) {
			int le = 0, ri = mn;
			int x = i, y = ux[i][j].first;
			int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
			loc--;
			if (loc >= 0 && loc<cx[x].size()) {
				le = cx[x][loc].first + 1;
			}
			loc++;
			int nowi = ux[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cx[x].size()) {
				ri = cx[x][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][ux[i][j].second]);
		}
		rep(j, cx[i].size()) {
			int id = cx[i][j].second;
			if (v[id].f == 2)continue;
			if (v[id].f == 3) {
				st.update(cx[i][j].first, d[1][id]);
			}
			else {
				st.update(cx[i][j].first, d[1][id] + 1);
			}
		}
	}
}
//上から
void calc2() {
	SegT st(mn);
	per(i, mn) {
		rep(j, ux[i].size()) {
			int le = 0, ri = mn;
			int x = i, y = ux[i][j].first;
			int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
			loc--;
			if (loc >= 0 && loc<cx[x].size()) {
				le = cx[x][loc].first + 1;
			}
			loc++;
			int nowi = ux[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cx[x].size()) {
				ri = cx[x][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][ux[i][j].second]);
		}
		rep(j, cx[i].size()) {
			int id = cx[i][j].second;
			if (v[id].f == 2)continue;
			if (v[id].f == 3) {
				st.update(cx[i][j].first, d[1][id]);
			}
			else {
				st.update(cx[i][j].first, d[1][id] + 1);
			}
		}
	}
}
void calc3() {
	SegT st(mn);
	rep(i, mn) {
		rep(j, uy[i].size()) {
			int le = 0, ri = mn;
			int x = uy[i][j].first, y = i;
			int loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
			loc--;
			if (loc >= 0 && loc<cy[y].size()) {
				le = cy[y][loc].first + 1;
			}
			loc++;
			int nowi = uy[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cy[y].size()) {
				ri = cy[y][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][uy[i][j].second]);
		}
		rep(j, cy[i].size()) {
			int id = cy[i][j].second;
			if (v[id].f == 2)continue;
			if (v[id].f == 3) {
				st.update(cy[i][j].first, d[1][id]);
			}
			else {
				st.update(cy[i][j].first, d[1][id] + 1);
			}
		}
	}
}
void calc4() {
	SegT st(mn);
	per(i, mn) {
		rep(j, uy[i].size()) {
			int le = 0, ri = mn;
			int x = uy[i][j].first, y = i;
			int loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
			loc--;
			if (loc >= 0 && loc<cy[y].size()) {
				le = cy[y][loc].first + 1;
			}
			loc++;
			int nowi = uy[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cy[y].size()) {
				ri = cy[y][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][uy[i][j].second]);
		}
		rep(j, cy[i].size()) {
			int id = cy[i][j].second;
			if (v[id].f == 2)continue;
			if (v[id].f == 3) {
				st.update(cy[i][j].first, d[1][id]);
			}
			else {
				st.update(cy[i][j].first, d[1][id] + 1);
			}
		}
	}
}
void calc() {
	calc1(); calc2(); calc3(); calc4();
	if (ans >= mod)cout << -1 << endl;
	else cout << ans << endl;
	return;
}
int main() {
	cin >> sx >> sy >> gx >> gy;
	cin >> n;
	rep(i, n) {
		int x, y; cin >> x >> y;
		v.push_back({ x,y,0 });
		v.push_back({ x + 1,y,1 });
		v.push_back({ x - 1,y,1 });
		v.push_back({ x,y + 1,1 });
		v.push_back({ x,y - 1,1 });
	}
	v.push_back({ sx,sy,2 });
	v.push_back({ gx,gy,3 });
	compress(v);
	sort(v.begin(), v.end());
	len = unique(v.begin(), v.end()) - v.begin();

	int gid;
	rep(i, len) {
		inv[{v[i].x, v[i].y}] = i;

	}
	rep(i, len) {
		if (v[i].f == 2) {
			sid = i;
			inv[{v[i].x, v[i].y}] = i;
		}
		else if (v[i].f == 3) {
			gid = i;
			inv[{v[i].x, v[i].y}] = i;
		}
	}
	rep(i, len) {
		int x = v[i].x, y = v[i].y, f = v[i].f;
		if (f == 1)continue;
		cx[x].push_back({ y,i });
		cy[y].push_back({ x,i });
	}
	rep(i, len) {
		int x = v[i].x, y = v[i].y, f = v[i].f;
		if (f == 0)continue;
		ux[x].push_back({ y,i });
		uy[y].push_back({ x,i });

	}
	rep(i, mn) {
		sort(cx[i].begin(), cx[i].end());
		sort(cy[i].begin(), cy[i].end());
		sort(ux[i].begin(), ux[i].end());
		sort(uy[i].begin(), uy[i].end());
	}

	//dijkstra
	rep(i, 2)rep(j, mn)d[i][j] = mod;
	dijkstra(0, sid); invdijkstra(gid);
	ans = d[0][gid];
	calc();

	//stop
	return 0;
}
accuracy: 0.175
time_ms: 30
memory_kb: 69760
final_rank: 16

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<complex>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<utility>
using namespace std;
typedef long long ll;
typedef unsigned int ui;
const ll mod = 1000000007;
const ll INF = (ll)1000000007 * 1000000007;
typedef pair<int, int> P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
typedef long double ld;
typedef complex<ld> Point;
const ld eps = 1e-6;
const ld pi = acos(-1.0);
typedef pair<ll, ll> LP;

int n;
int sx, sy, gx, gy;

struct vertice {
	int x, y, f;
	bool operator<(const vertice &v)const {
		if (x != v.x)return x < v.x;
		if (y != v.y)return y < v.y;
		return f < v.f;
	}
	bool operator==(const vertice &v)const {
		if (x == v.x&&y == v.y&&f == v.f)return true;
		return false;
	}
};

void compress(vector<vertice> &v) {
	int n = v.size();
	vector<LP> x, y;
	rep(i, n) {
		x.push_back({ v[i].x,i });
		y.push_back({ v[i].y,i });
	}
	sort(x.begin(), x.end());
	sort(y.begin(), y.end());
	int cur = 0;
	rep(i, n) {
		v[x[i].second].x = cur;
		while (i + 1 < n&&x[i].first == x[i + 1].first) {
			i++; v[x[i].second].x = cur;
		}
		cur++;
	}
	cur = 0;
	rep(i, n) {
		v[y[i].second].y = cur;
		while (i + 1 < n&&y[i].first == y[i + 1].first) {
			i++; v[y[i].second].y = cur;
		}
		cur++;
	}
}

vector<vertice> v; map<P, int> inv;

const int mn = 500005;
vector<P> cx[mn], cy[mn];

int d[2][mn];
priority_queue<P, vector<P>, greater<P>> q;
void dijkstra(int id, int root) {
	d[id][root] = 0;
	q.push({ 0,root });
	while (!q.empty()) {
		P p = q.top(); q.pop();
		int i = p.second; int dist = p.first;
		int x = v[i].x, y = v[i].y;
		//x軸
		int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
		loc--;
		if (loc >= 0 && loc<cx[x].size()) {
			int ni = cx[x][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{x, cx[x][loc].first + 1}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		loc++;
		if (v[i].f >= 2)loc++;
		if (loc < cx[x].size()) {
			int ni = cx[x][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{x, cx[x][loc].first - 1}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		//y軸
		loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
		loc--;
		if (loc >= 0 && loc<cy[y].size()) {
			int ni = cy[y][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{cy[y][loc].first + 1, y}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		loc++;
		if (v[i].f >= 2)loc++;
		if (loc < cy[y].size()) {
			int ni = cy[y][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{cy[y][loc].first - 1, y}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			if (dist + 1 < d[id][ni]) {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
	}
}

int ans = mod;

struct SegT {
private:
	int sz; vector<int> node;
	const int init_c = mod;
public:
	SegT(int n) {
		sz = 1;
		while (sz < n)sz *= 2;
		node.resize(2 * sz - 1, init_c);
	}
	int f(int a, int b) {
		return min(a, b);
	}
	void update(int k, int a) {
		k += sz - 1;
		node[k] = a;
		while (k > 0) {
			k = (k - 1) / 2;
			node[k] = f(node[k * 2 + 1], node[k * 2 + 2]);
		}
	}
	int query(int a, int b, int k = 0, int l = 0, int r = -1) {
		if (r < 0)r = sz;
		if (r <= a || b <= l)return init_c;
		else if (a <= l && r <= b)return node[k];
		else {
			int vl = query(a, b, k * 2 + 1, l, (l + r) / 2);
			int vr = query(a, b, k * 2 + 2, (l + r) / 2, r);
			return f(vl, vr);
		}
	}
};
int len;

//全頂点が入ってるほう
vector<P> ux[mn], uy[mn];
//下から
void calc1() {
	SegT st(mn);
	rep(i, mn) {
		rep(j, ux[i].size()) {
			int le = 0, ri = mn;
			int x = i, y = ux[i][j].first;
			int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
			loc--;
			if (loc >= 0 && loc<cx[x].size()) {
				le = cx[x][loc].first + 1;
			}
			loc++;
			int nowi = ux[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cx[x].size()) {
				ri = cx[x][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][ux[i][j].second]);
		}
		rep(j, cx[i].size()) {
			int id = cx[i][j].second;
			if (v[id].f == 2)continue;
			if (v[id].f == 3) {
				st.update(cx[i][j].first, d[1][id]);
			}
			else {
				st.update(cx[i][j].first, d[1][id] + 1);
			}
		}
	}
}
//上から
void calc2() {
	SegT st(mn);
	per(i, mn) {
		rep(j, ux[i].size()) {
			int le = 0, ri = mn;
			int x = i, y = ux[i][j].first;
			int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
			loc--;
			if (loc >= 0 && loc<cx[x].size()) {
				le = cx[x][loc].first + 1;
			}
			loc++;
			int nowi = ux[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cx[x].size()) {
				ri = cx[x][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][ux[i][j].second]);
		}
		rep(j, cx[i].size()) {
			int id = cx[i][j].second;
			if (v[id].f == 2)continue;
			if (v[id].f == 3) {
				st.update(cx[i][j].first, d[1][id]);
			}
			else {
				st.update(cx[i][j].first, d[1][id] + 1);
			}
		}
	}
}
void calc3() {
	SegT st(mn);
	rep(i, mn) {
		rep(j, uy[i].size()) {
			int le = 0, ri = mn;
			int x = uy[i][j].first, y = i;
			int loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
			loc--;
			if (loc >= 0 && loc<cy[y].size()) {
				le = cy[y][loc].first + 1;
			}
			loc++;
			int nowi = uy[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cy[y].size()) {
				ri = cy[y][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][uy[i][j].second]);
		}
		rep(j, cy[i].size()) {
			int id = cy[i][j].second;
			if (v[id].f == 2)continue;
			if (v[id].f == 3) {
				st.update(cy[i][j].first, d[1][id]);
			}
			else {
				st.update(cy[i][j].first, d[1][id] + 1);
			}
		}
	}
}
void calc4() {
	SegT st(mn);
	per(i, mn) {
		rep(j, uy[i].size()) {
			int le = 0, ri = mn;
			int x = uy[i][j].first, y = i;
			int loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
			loc--;
			if (loc >= 0 && loc<cy[y].size()) {
				le = cy[y][loc].first + 1;
			}
			loc++;
			int nowi = uy[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cy[y].size()) {
				ri = cy[y][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][uy[i][j].second]);
		}
		rep(j, cy[i].size()) {
			int id = cy[i][j].second;
			if (v[id].f == 2)continue;
			if (v[id].f == 3) {
				st.update(cy[i][j].first, d[1][id]);
			}
			else {
				st.update(cy[i][j].first, d[1][id] + 1);
			}
		}
	}
}
void calc() {
	calc1(); calc2(); calc3(); calc4();
	if (ans >= mod)cout << -1 << endl;
	else cout << ans << endl;
	return;
}
int main() {
	cin >> sx >> sy >> gx >> gy;
	cin >> n;
	rep(i, n) {
		int x, y; cin >> x >> y;
		v.push_back({ x,y,0 });
		v.push_back({ x + 1,y,1 });
		v.push_back({ x - 1,y,1 });
		v.push_back({ x,y + 1,1 });
		v.push_back({ x,y - 1,1 });
	}
	v.push_back({ sx,sy,2 });
	v.push_back({ gx,gy,3 });
	compress(v);
	sort(v.begin(), v.end());
	len = unique(v.begin(), v.end()) - v.begin();

	int sid, gid;
	rep(i, len) {
		inv[{v[i].x, v[i].y}] = i;

	}
	rep(i, len) {
		if (v[i].f == 2) {
			sid = i;
			inv[{v[i].x, v[i].y}] = i;
		}
		else if (v[i].f == 3) {
			gid = i;
			inv[{v[i].x, v[i].y}] = i;
		}
	}
	rep(i, len) {
		int x = v[i].x, y = v[i].y, f = v[i].f;
		if (f == 1)continue;
		cx[x].push_back({ y,i });
		cy[y].push_back({ x,i });
	}
	rep(i, len) {
		int x = v[i].x, y = v[i].y, f = v[i].f;
		if (f == 0)continue;
		ux[x].push_back({ y,i });
		uy[y].push_back({ x,i });

	}
	rep(i, mn) {
		sort(cx[i].begin(), cx[i].end());
		sort(cy[i].begin(), cy[i].end());
		sort(ux[i].begin(), ux[i].end());
		sort(uy[i].begin(), uy[i].end());
	}

	//dijkstra
	rep(i, 2)rep(j, mn)d[i][j] = mod;
	dijkstra(0, sid); dijkstra(1, gid);
	ans = d[0][gid];
	calc();

	//stop
	return 0;
}
accuracy: 0.175
time_ms: 30
memory_kb: 58044
final_rank: 13

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<complex>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<utility>
using namespace std;
typedef long long ll;
typedef unsigned int ui;
const ll mod = 1000000007;
const ll INF = (ll)1000000007 * 1000000007;
typedef pair<int, int> P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
typedef long double ld;
typedef complex<ld> Point;
const ld eps = 1e-6;
const ld pi = acos(-1.0);
typedef pair<ll, ll> LP;

int n;
int sx, sy, gx, gy;

struct vertice {
	int x, y, f;
	bool operator<(const vertice &v)const {
		if (x != v.x)return x < v.x;
		if (y != v.y)return y < v.y;
		return f < v.f;
	}
	bool operator==(const vertice &v)const {
		if (x == v.x&&y == v.y&&f == v.f)return true;
		return false;
	}
};

void compress(vector<vertice> &v) {
	int n = v.size();
	vector<LP> x, y;
	rep(i, n) {
		x.push_back({ v[i].x,i });
		y.push_back({ v[i].y,i });
	}
	sort(x.begin(), x.end());
	sort(y.begin(), y.end());
	int cur = 0;
	rep(i, n) {
		v[x[i].second].x = cur;
		while (i + 1 < n&&x[i].first == x[i + 1].first) {
			i++; v[x[i].second].x = cur;
		}
		cur++;
	}
	cur = 0;
	rep(i, n) {
		v[y[i].second].y = cur;
		while (i + 1 < n&&y[i].first == y[i + 1].first) {
			i++; v[y[i].second].y = cur;
		}
		cur++;
	}
}

vector<vertice> v; map<P, int> inv;

const int mn = 500005;
vector<P> cx[mn], cy[mn];

int d[2][mn];
priority_queue<P, vector<P>, greater<P>> q;
void dijkstra(int id, int root) {
	d[id][root] = 0;
	q.push({ 0,root });
	while (!q.empty()) {
		P p = q.top(); q.pop();
		int i = p.second; int dist = p.first;
		int x = v[i].x, y = v[i].y;
		//x軸
		int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
		loc--;
		if (loc >= 0 && loc<cx[x].size()) {
			int ni = cx[x][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{x, cx[x][loc].first + 1}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		loc++;
		if (v[i].f >= 2)loc++;
		if (loc < cx[x].size()) {
			int ni = cx[x][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{x, cx[x][loc].first - 1}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		//y軸
		loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
		loc--;
		if (loc >= 0 && loc<cy[y].size()) {
			int ni = cy[y][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{cy[y][loc].first + 1, y}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		loc++;
		if (v[i].f >= 2)loc++;
		if (loc < cy[y].size()) {
			int ni = cy[y][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{cy[y][loc].first - 1, y}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			if (dist + 1 < d[id][ni]) {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
	}
}

int ans = mod;

struct SegT {
private:
	int sz; vector<int> node;
	const int init_c = mod;
public:
	SegT(int n) {
		sz = 1;
		while (sz < n)sz *= 2;
		node.resize(2 * sz - 1, init_c);
	}
	int f(int a, int b) {
		return min(a, b);
	}
	void update(int k, int a) {
		k += sz - 1;
		node[k] = a;
		while (k > 0) {
			k = (k - 1) / 2;
			node[k] = f(node[k * 2 + 1], node[k * 2 + 2]);
		}
	}
	int query(int a, int b, int k = 0, int l = 0, int r = -1) {
		if (r < 0)r = sz;
		if (r <= a || b <= l)return init_c;
		else if (a <= l && r <= b)return node[k];
		else {
			int vl = query(a, b, k * 2 + 1, l, (l + r) / 2);
			int vr = query(a, b, k * 2 + 2, (l + r) / 2, r);
			return f(vl, vr);
		}
	}
};
int len;

//全頂点が入ってるほう
vector<P> ux[mn], uy[mn];
//下から
void calc1() {
	SegT st(mn);
	rep(i, mn) {
		rep(j, ux[i].size()) {
			int le = 0, ri = mn;
			int x = i, y = ux[i][j].first;
			int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
			loc--;
			if (loc >= 0 && loc<cx[x].size()) {
				le = cx[x][loc].first + 1;
			}
			loc++;
			int nowi = ux[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cx[x].size()) {
				ri = cx[x][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][ux[i][j].second]);
		}
		rep(j, cx[i].size()) {
			int id = cx[i][j].second;
			if (v[id].f == 2)continue;
			if (v[id].f == 3) {
				st.update(cx[i][j].first, d[1][id]);
			}
			else {
				st.update(cx[i][j].first, d[1][id] + 1);
			}
		}
	}
}
//上から
void calc2() {
	SegT st(mn);
	per(i, mn) {
		rep(j, ux[i].size()) {
			int le = 0, ri = mn;
			int x = i, y = ux[i][j].first;
			int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
			loc--;
			if (loc >= 0 && loc<cx[x].size()) {
				le = cx[x][loc].first + 1;
			}
			loc++;
			int nowi = ux[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cx[x].size()) {
				ri = cx[x][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][ux[i][j].second]);
		}
		rep(j, cx[i].size()) {
			int id = cx[i][j].second;
			if (v[id].f == 2)continue;
			if (v[id].f == 3) {
				st.update(cx[i][j].first, d[1][id]);
			}
			else {
				st.update(cx[i][j].first, d[1][id] + 1);
			}
		}
	}
}
void calc3() {
	SegT st(mn);
	rep(i, mn) {
		rep(j, uy[i].size()) {
			int le = 0, ri = mn;
			int x = uy[i][j].first, y = i;
			int loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
			loc--;
			if (loc >= 0 && loc<cy[y].size()) {
				le = cy[y][loc].first + 1;
			}
			loc++;
			int nowi = uy[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cy[y].size()) {
				ri = cy[y][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][uy[i][j].second]);
		}
		rep(j, cy[i].size()) {
			int id = cy[i][j].second;
			if (v[id].f == 2)continue;
			if (v[id].f == 3) {
				st.update(cy[i][j].first, d[1][id]);
			}
			else {
				st.update(cy[i][j].first, d[1][id] + 1);
			}
		}
	}
}
void calc4() {
	SegT st(mn);
	per(i, mn) {
		rep(j, uy[i].size()) {
			int le = 0, ri = mn;
			int x = uy[i][j].first, y = i;
			int loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
			loc--;
			if (loc >= 0 && loc<cy[y].size()) {
				le = cy[y][loc].first + 1;
			}
			loc++;
			int nowi = uy[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cy[y].size()) {
				ri = cy[y][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][uy[i][j].second]);
		}
		rep(j, cy[i].size()) {
			int id = cy[i][j].second;
			if (v[id].f == 2)continue;
			if (v[id].f == 3) {
				st.update(cy[i][j].first, d[1][id]);
			}
			else {
				st.update(cy[i][j].first, d[1][id] + 1);
			}
		}
	}
}
void calc() {
	calc1(); calc2(); calc3(); calc4();
	if (ans == mod)cout << -1 << endl;
	else cout << ans << endl;
	return;
}
int main() {
	cin >> sx >> sy >> gx >> gy;
	cin >> n;
	rep(i, n) {
		int x, y; cin >> x >> y;
		v.push_back({ x,y,0 });
		v.push_back({ x + 1,y,1 });
		v.push_back({ x - 1,y,1 });
		v.push_back({ x,y + 1,1 });
		v.push_back({ x,y - 1,1 });
	}
	v.push_back({ sx,sy,2 });
	v.push_back({ gx,gy,3 });
	compress(v);
	sort(v.begin(), v.end());
	len = unique(v.begin(), v.end()) - v.begin();

	int sid, gid;
	rep(i, len) {
		inv[{v[i].x, v[i].y}] = i;

	}
	rep(i, len) {
		if (v[i].f == 2) {
			sid = i;
			inv[{v[i].x, v[i].y}] = i;
		}
		else if (v[i].f == 3) {
			gid = i;
			inv[{v[i].x, v[i].y}] = i;
		}
	}
	rep(i, len) {
		int x = v[i].x, y = v[i].y, f = v[i].f;
		if (f == 1)continue;
		cx[x].push_back({ y,i });
		cy[y].push_back({ x,i });
	}
	rep(i, len) {
		int x = v[i].x, y = v[i].y, f = v[i].f;
		if (f == 0)continue;
		ux[x].push_back({ y,i });
		uy[y].push_back({ x,i });

	}
	rep(i, mn) {
		sort(cx[i].begin(), cx[i].end());
		sort(cy[i].begin(), cy[i].end());
		sort(ux[i].begin(), ux[i].end());
		sort(uy[i].begin(), uy[i].end());
	}

	//dijkstra
	rep(i, 2)rep(j, mn)d[i][j] = mod;
	dijkstra(0, sid); dijkstra(1, gid);
	ans = d[0][gid];
	calc();

	//stop
	return 0;
}
accuracy: 0.175
time_ms: 30
memory_kb: 58028
final_rank: 12

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<complex>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<utility>
using namespace std;
typedef long long ll;
typedef unsigned int ui;
const ll mod = 1000000007;
const ll INF = (ll)1000000007 * 1000000007;
typedef pair<int, int> P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
typedef long double ld;
typedef complex<ld> Point;
const ld eps = 1e-6;
const ld pi = acos(-1.0);
typedef pair<ll, ll> LP;

int n;
int sx, sy, gx, gy;

struct vertice {
	int x, y, f;
	bool operator<(const vertice &v)const {
		if (x != v.x)return x < v.x;
		if (y != v.y)return y < v.y;
		return f < v.f;
	}
	bool operator==(const vertice &v)const {
		if (x == v.x&&y == v.y&&f == v.f)return true;
		return false;
	}
};

void compress(vector<vertice> &v) {
	int n = v.size();
	vector<LP> x, y;
	rep(i, n) {
		x.push_back({ v[i].x,i });
		y.push_back({ v[i].y,i });
	}
	sort(x.begin(), x.end());
	sort(y.begin(), y.end());
	int cur = 0;
	rep(i, n) {
		v[x[i].second].x = cur;
		while (i + 1 < n&&x[i].first == x[i + 1].first) {
			i++; v[x[i].second].x = cur;
		}
		cur++;
	}
	cur = 0;
	rep(i, n) {
		v[y[i].second].y = cur;
		while (i + 1 < n&&y[i].first == y[i + 1].first) {
			i++; v[y[i].second].y = cur;
		}
		cur++;
	}
}

vector<vertice> v; map<P, int> inv;

const int mn = 500005;
vector<P> cx[mn], cy[mn];

int d[2][mn];
priority_queue<P, vector<P>, greater<P>> q;
void dijkstra(int id, int root) {
	d[id][root] = 0;
	q.push({ 0,root });
	while (!q.empty()) {
		P p = q.top(); q.pop();
		int i = p.second; int dist = p.first;
		int x = v[i].x, y = v[i].y;
		//x軸
		int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
		loc--;
		if (loc >= 0 && loc<cx[x].size()) {
			int ni = cx[x][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{x, cx[x][loc].first + 1}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		loc++;
		if (v[i].f >= 2)loc++;
		if (loc < cx[x].size()) {
			int ni = cx[x][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{x, cx[x][loc].first - 1}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		//y軸
		loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
		loc--;
		if (loc >= 0 && loc<cy[y].size()) {
			int ni = cy[y][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{cy[y][loc].first + 1, y}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		loc++;
		if (v[i].f >= 2)loc++;
		if (loc < cy[y].size()) {
			int ni = cy[y][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{cy[y][loc].first - 1, y}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			if (dist + 1 < d[id][ni]) {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
	}
}

int ans = mod;

struct SegT {
private:
	int sz; vector<int> node;
	const int init_c = mod;
public:
	SegT(int n) {
		sz = 1;
		while (sz < n)sz *= 2;
		node.resize(2 * sz - 1, init_c);
	}
	int f(int a, int b) {
		return min(a, b);
	}
	void update(int k, int a) {
		k += sz - 1;
		node[k] = a;
		while (k > 0) {
			k = (k - 1) / 2;
			node[k] = f(node[k * 2 + 1], node[k * 2 + 2]);
		}
	}
	int query(int a, int b, int k = 0, int l = 0, int r = -1) {
		if (r < 0)r = sz;
		if (r <= a || b <= l)return init_c;
		else if (a <= l && r <= b)return node[k];
		else {
			int vl = query(a, b, k * 2 + 1, l, (l + r) / 2);
			int vr = query(a, b, k * 2 + 2, (l + r) / 2, r);
			return f(vl, vr);
		}
	}
};
int len;

//全頂点が入ってるほう
vector<P> ux[mn], uy[mn];
//下から
void calc1() {
	SegT st(mn);
	rep(i, mn) {
		rep(j, ux[i].size()) {
			int le = 0, ri = mn;
			int x = i, y = ux[i][j].first;
			int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
			loc--;
			if (loc >= 0 && loc<cx[x].size()) {
				le = cx[x][loc].first + 1;
			}
			loc++;
			int nowi = ux[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cx[x].size()) {
				ri = cx[x][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][ux[i][j].second]);
		}
		rep(j, cx[i].size()) {
			int id = cx[i][j].second;
			if (v[id].f == 2)continue;
			if (v[id].f == 3) {
				st.update(cx[i][j].first, d[1][id]);
			}
			else {
				st.update(cx[i][j].first, d[1][id] + 1);
			}
		}
	}
}
//上から
void calc2() {
	SegT st(mn);
	per(i, mn) {
		rep(j, ux[i].size()) {
			int le = 0, ri = mn;
			int x = i, y = ux[i][j].first;
			int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
			loc--;
			if (loc >= 0 && loc<cx[x].size()) {
				le = cx[x][loc].first + 1;
			}
			loc++;
			int nowi = ux[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cx[x].size()) {
				ri = cx[x][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][ux[i][j].second]);
		}
		rep(j, cx[i].size()) {
			int id = cx[i][j].second;
			if (v[id].f == 2)continue;
			if (v[id].f == 3) {
				st.update(cx[i][j].first, d[1][id]);
			}
			else {
				st.update(cx[i][j].first, d[1][id] + 1);
			}
		}
	}
}
void calc3() {
	SegT st(mn);
	rep(i, mn) {
		rep(j, uy[i].size()) {
			int le = 0, ri = mn;
			int x = uy[i][j].first, y = i;
			int loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
			loc--;
			if (loc >= 0 && loc<cy[y].size()) {
				le = cy[y][loc].first + 1;
			}
			loc++;
			int nowi = uy[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cy[y].size()) {
				ri = cy[y][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][uy[i][j].second]);
		}
		rep(j, cy[i].size()) {
			int id = cy[i][j].second;
			if (v[id].f == 2)continue;
			if (v[id].f == 3) {
				st.update(cy[i][j].first, d[1][id]);
			}
			else {
				st.update(cy[i][j].first, d[1][id] + 1);
			}
		}
	}
}
void calc4() {
	SegT st(mn);
	per(i, mn) {
		rep(j, uy[i].size()) {
			int le = 0, ri = mn;
			int x = uy[i][j].first, y = i;
			int loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
			loc--;
			if (loc >= 0 && loc<cy[y].size()) {
				le = cy[y][loc].first + 1;
			}
			loc++;
			int nowi = uy[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cy[y].size()) {
				ri = cy[y][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][uy[i][j].second]);
		}
		rep(j, cy[i].size()) {
			int id = cy[i][j].second;
			if (v[id].f == 2)continue;
			if (v[id].f == 3) {
				st.update(cy[i][j].first, d[1][id]);
			}
			else {
				st.update(cy[i][j].first, d[1][id] + 1);
			}
		}
	}
}
void calc() {
	calc1(); calc2(); calc3(); calc4();
	if (ans == mod)cout << -1 << endl;
	else cout << ans << endl;
	return;
}
int main() {
	cin >> sx >> sy >> gx >> gy;
	cin >> n;
	rep(i, n) {
		int x, y; cin >> x >> y;
		v.push_back({ x,y,0 });
		v.push_back({ x + 1,y,1 });
		v.push_back({ x - 1,y,1 });
		v.push_back({ x,y + 1,1 });
		v.push_back({ x,y - 1,1 });
	}
	v.push_back({ sx,sy,2 });
	v.push_back({ gx,gy,3 });
	compress(v);
	sort(v.begin(), v.end());
	len = unique(v.begin(), v.end()) - v.begin();

	int sid, gid;
	rep(i, len) {
		inv[{v[i].x, v[i].y}] = i;
		if (v[i].f == 2) {
			sid = i;
		}
		else if (v[i].f == 3) {
			gid = i;
		}
	}
	rep(i, len) {
		int x = v[i].x, y = v[i].y, f = v[i].f;
		if (f == 1)continue;
		cx[x].push_back({ y,i });
		cy[y].push_back({ x,i });
	}
	rep(i, len) {
		int x = v[i].x, y = v[i].y, f = v[i].f;
		if (f == 0)continue;
		ux[x].push_back({ y,i });
		uy[y].push_back({ x,i });

	}
	rep(i, mn) {
		sort(cx[i].begin(), cx[i].end());
		sort(cy[i].begin(), cy[i].end());
		sort(ux[i].begin(), ux[i].end());
		sort(uy[i].begin(), uy[i].end());
	}

	//dijkstra
	rep(i, 2)rep(j, mn)d[i][j] = mod;
	dijkstra(0, sid); dijkstra(1, gid);
	ans = d[0][gid];
	calc();

	//stop
	return 0;
}
accuracy: 0.175
time_ms: 30
memory_kb: 58044
final_rank: 13

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<complex>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<utility>
using namespace std;
typedef long long ll;
typedef unsigned int ui;
const ll mod = 1000000007;
const ll INF = (ll)1000000007 * 1000000007;
typedef pair<int, int> P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
typedef long double ld;
typedef complex<ld> Point;
const ld eps = 1e-6;
const ld pi = acos(-1.0);
typedef pair<ll, ll> LP;

int n;
int sx, sy, gx, gy;

struct vertice {
	int x, y, f;
	bool operator<(const vertice &v)const {
		if (x != v.x)return x < v.x;
		if (y != v.y)return y < v.y;
		return f < v.f;
	}
	bool operator==(const vertice &v)const {
		if (x == v.x&&y == v.y&&f == v.f)return true;
		return false;
	}
};

void compress(vector<vertice> &v) {
	int n = v.size();
	vector<LP> x, y;
	rep(i, n) {
		x.push_back({ v[i].x,i });
		y.push_back({ v[i].y,i });
	}
	sort(x.begin(), x.end());
	sort(y.begin(), y.end());
	int cur = 0;
	rep(i, n) {
		v[x[i].second].x = cur;
		while (i + 1 < n&&x[i].first == x[i + 1].first) {
			i++; v[x[i].second].x = cur;
		}
		cur++;
	}
	cur = 0;
	rep(i, n) {
		v[y[i].second].y = cur;
		while (i + 1 < n&&y[i].first == y[i + 1].first) {
			i++; v[y[i].second].y = cur;
		}
		cur++;
	}
}

vector<vertice> v; map<P, int> inv;

const int mn = 500005;
vector<P> cx[mn], cy[mn];

int d[2][mn];
priority_queue<P, vector<P>, greater<P>> q;
void dijkstra(int id, int root) {
	d[id][root] = 0;
	q.push({ 0,root });
	while (!q.empty()) {
		P p = q.top(); q.pop();
		int i = p.second; int dist = p.first;
		int x = v[i].x, y = v[i].y;
		//x軸
		int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
		loc--;
		if (loc >= 0 && loc<cx[x].size()) {
			int ni = cx[x][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{x, cx[x][loc].first + 1}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		loc++;
		if (v[i].f >= 2)loc++;
		if (loc < cx[x].size()) {
			int ni = cx[x][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{x, cx[x][loc].first - 1}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		//y軸
		loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
		loc--;
		if (loc >= 0 && loc<cy[y].size()) {
			int ni = cy[y][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{cy[y][loc].first + 1, y}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		loc++;
		if (v[i].f >= 2)loc++;
		if (loc < cy[y].size()) {
			int ni = cy[y][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{cy[y][loc].first - 1, y}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			if (dist + 1 < d[id][ni]) {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
	}
}

int ans = mod;

struct SegT {
private:
	int sz; vector<int> node;
	const int init_c = mod;
public:
	SegT(int n) {
		sz = 1;
		while (sz < n)sz *= 2;
		node.resize(2 * sz - 1, init_c);
	}
	int f(int a, int b) {
		return min(a, b);
	}
	void update(int k, int a) {
		k += sz - 1;
		node[k] = a;
		while (k > 0) {
			k = (k - 1) / 2;
			node[k] = f(node[k * 2 + 1], node[k * 2 + 2]);
		}
	}
	int query(int a, int b, int k = 0, int l = 0, int r = -1) {
		if (r < 0)r = sz;
		if (r <= a || b <= l)return init_c;
		else if (a <= l && r <= b)return node[k];
		else {
			int vl = query(a, b, k * 2 + 1, l, (l + r) / 2);
			int vr = query(a, b, k * 2 + 2, (l + r) / 2, r);
			return f(vl, vr);
		}
	}
};
int len;

//全頂点が入ってるほう
vector<P> ux[mn], uy[mn];
//下から
void calc1() {
	SegT st(mn);
	rep(i, mn) {
		rep(j, ux[i].size()) {
			int le = 0, ri = mn;
			int x = i, y = ux[i][j].first;
			int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
			loc--;
			if (loc >= 0 && loc<cx[x].size()) {
				le = cx[x][loc].first + 1;
			}
			loc++;
			int nowi = ux[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cx[x].size()) {
				ri = cx[x][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][ux[i][j].second]);
		}
		rep(j, cx[i].size()) {
			int id = cx[i][j].second;
			if (v[id].f == 2)continue;
			if (v[id].f == 3) {
				st.update(cx[i][j].first, d[1][id]);
			}
			else {
				st.update(cx[i][j].first, d[1][id] + 1);
			}
		}
	}
}
//上から
void calc2() {
	SegT st(mn);
	per(i, mn) {
		rep(j, ux[i].size()) {
			int le = 0, ri = mn;
			int x = i, y = ux[i][j].first;
			int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
			loc--;
			if (loc >= 0 && loc<cx[x].size()) {
				le = cx[x][loc].first + 1;
			}
			loc++;
			int nowi = ux[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cx[x].size()) {
				ri = cx[x][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][ux[i][j].second]);
		}
		rep(j, cx[i].size()) {
			int id = cx[i][j].second;
			if (v[id].f == 2)continue;
			if (v[id].f == 3) {
				st.update(cx[i][j].first, d[1][id]);
			}
			else {
				st.update(cx[i][j].first, d[1][id] + 1);
			}
		}
	}
}
void calc3() {
	SegT st(mn);
	rep(i, mn) {
		rep(j, uy[i].size()) {
			int le = 0, ri = mn;
			int x = uy[i][j].first, y = i;
			int loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
			loc--;
			if (loc >= 0 && loc<cy[y].size()) {
				le = cy[y][loc].first + 1;
			}
			loc++;
			int nowi = uy[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cy[y].size()) {
				ri = cy[y][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][uy[i][j].second]);
		}
		rep(j, cy[i].size()) {
			int id = cy[i][j].second;
			if (v[id].f == 2)continue;
			if (v[id].f == 3) {
				st.update(cy[i][j].first, d[1][id]);
			}
			else {
				st.update(cy[i][j].first, d[1][id] + 1);
			}
		}
	}
}
void calc4() {
	SegT st(mn);
	per(i, mn) {
		rep(j, uy[i].size()) {
			int le = 0, ri = mn;
			int x = uy[i][j].first, y = i;
			int loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
			loc--;
			if (loc >= 0 && loc<cy[y].size()) {
				le = cy[y][loc].first + 1;
			}
			loc++;
			int nowi = uy[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cy[y].size()) {
				ri = cy[y][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][uy[i][j].second]);
		}
		rep(j, cy[i].size()) {
			int id = cy[i][j].second;
			if (v[id].f == 2)continue;
			if (v[id].f == 3) {
				st.update(cy[i][j].first, d[1][id]);
			}
			else {
				st.update(cy[i][j].first, d[1][id] + 1);
			}
		}
	}
}
void calc() {
	calc1(); calc2(); calc3(); calc4();
	if (ans == mod)cout << -1 << endl;
	else cout << ans << endl;
	return;
}
int main() {
	cin >> sx >> sy >> gx >> gy;
	cin >> n;
	rep(i, n) {
		int x, y; cin >> x >> y;
		v.push_back({ x,y,0 });
		v.push_back({ x + 1,y,1 });
		v.push_back({ x - 1,y,1 });
		v.push_back({ x,y + 1,1 });
		v.push_back({ x,y - 1,1 });
	}
	v.push_back({ sx,sy,2 });
	v.push_back({ gx,gy,3 });
	compress(v);
	sort(v.begin(), v.end());
	len = unique(v.begin(), v.end()) - v.begin();

	int sid, gid;
	rep(i, len) {
		inv[{v[i].x, v[i].y}] = i;
		if (v[i].f == 2) {
			sid = i;
		}
		else if (v[i].f == 3) {
			gid = i;
		}
	}
	rep(i, len) {
		int x = v[i].x, y = v[i].y, f = v[i].f;
		if (f == 1)continue;
		cx[x].push_back({ y,i });
		cy[y].push_back({ x,i });
	}
	rep(i, len) {
		int x = v[i].x, y = v[i].y, f = v[i].f;
		if (f == 0)continue;
		ux[x].push_back({ y,i });
		uy[y].push_back({ x,i });

	}
	rep(i, mn) {
		sort(cx[i].begin(), cx[i].end());
		sort(cy[i].begin(), cy[i].end());
		sort(ux[i].begin(), ux[i].end());
		sort(uy[i].begin(), uy[i].end());
	}

	//dijkstra
	rep(i, 2)rep(j, mn)d[i][j] = mod;
	dijkstra(0, sid); dijkstra(1, gid);
	ans = d[sid][gid];
	calc();

	//stop
	return 0;
}
accuracy: 0.05
time_ms: 30
memory_kb: 58032
final_rank: 19

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<complex>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<utility>
using namespace std;
typedef long long ll;
typedef unsigned int ui;
const ll mod = 1000000007;
const ll INF = (ll)1000000007 * 1000000007;
typedef pair<int, int> P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
typedef long double ld;
typedef complex<ld> Point;
const ld eps = 1e-6;
const ld pi = acos(-1.0);
typedef pair<ll, ll> LP;

int n;
int sx, sy, gx, gy;

struct vertice {
	int x, y, f;
	bool operator<(const vertice &v)const {
		if (x != v.x)return x < v.x;
		if (y != v.y)return y < v.y;
		return f < v.f;
	}
	bool operator==(const vertice &v)const {
		if (x == v.x&&y == v.y&&f == v.f)return true;
		return false;
	}
};

void compress(vector<vertice> &v) {
	int n = v.size();
	vector<LP> x, y;
	rep(i, n) {
		x.push_back({ v[i].x,i });
		y.push_back({ v[i].y,i });
	}
	sort(x.begin(), x.end());
	sort(y.begin(), y.end());
	int cur = 0;
	rep(i, n) {
		v[x[i].second].x = cur;
		while (i + 1 < n&&x[i].first == x[i + 1].first) {
			i++; v[x[i].second].x = cur;
		}
		cur++;
	}
	cur = 0;
	rep(i, n) {
		v[y[i].second].y = cur;
		while (i + 1 < n&&y[i].first == y[i + 1].first) {
			i++; v[y[i].second].y = cur;
		}
		cur++;
	}
}

vector<vertice> v; map<P, int> inv;

const int mn = 500005;
vector<P> cx[mn], cy[mn];

int d[2][mn];
priority_queue<P, vector<P>, greater<P>> q;
void dijkstra(int id, int root) {
	d[id][root] = 0;
	q.push({ 0,root });
	while (!q.empty()) {
		P p = q.top(); q.pop();
		int i = p.second; int dist = p.first;
		int x = v[i].x, y = v[i].y;
		//x軸
		int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
		loc--;
		if (loc >= 0&&loc<cx[x].size()) {
			int ni = cx[x][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{x, cx[x][loc].first + 1}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		loc++;
		if (v[i].f >= 2)loc++;
		if (loc < cx[x].size()) {
			int ni = cx[x][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{x, cx[x][loc].first - 1}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		//y軸
		loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
		loc--;
		if (loc >= 0&&loc<cy[y].size()) {
			int ni = cy[y][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{cy[y][loc].first + 1, y}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		loc++;
		if (v[i].f >= 2)loc++;
		if (loc < cy[y].size()) {
			int ni = cy[y][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{cy[y][loc].first - 1, y}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			if (dist + 1 < d[id][ni]) {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
	}
}

int ans = mod;

struct SegT {
private:
	int sz; vector<int> node;
	const int init_c = mod;
public:
	SegT(int n) {
		sz = 1;
		while (sz < n)sz *= 2;
		node.resize(2 * sz - 1, init_c);
	}
	int f(int a, int b) {
		return min(a, b);
	}
	void update(int k, int a) {
		k += sz - 1;
		node[k] = a;
		while (k > 0) {
			k = (k - 1) / 2;
			node[k] = f(node[k * 2 + 1], node[k * 2 + 2]);
		}
	}
	int query(int a, int b, int k = 0, int l = 0, int r = -1) {
		if (r < 0)r = sz;
		if (r <= a || b <= l)return init_c;
		else if (a <= l && r <= b)return node[k];
		else {
			int vl = query(a, b, k * 2 + 1, l, (l + r) / 2);
			int vr = query(a, b, k * 2 + 2, (l + r) / 2, r);
			return f(vl, vr);
		}
	}
};
int len;

//全頂点が入ってるほう
vector<P> ux[mn], uy[mn];
//下から
void calc1() {
	SegT st(mn);
	rep(i, mn) {
		rep(j, ux[i].size()) {
			int le = 0, ri = mn;
			int x = i, y = ux[i][j].first;
			int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
			loc--;
			if (loc >= 0&&loc<cx[x].size()) {
				le = cx[x][loc].first + 1;
			}
			loc++;
			int nowi = ux[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cx[x].size()) {
				ri = cx[x][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][ux[i][j].second]);
		}
		rep(j, cx[i].size()) {
			int id = cx[i][j].second;
			if (v[id].f == 2)continue;
			if (v[id].f == 3) {
				st.update(cx[i][j].first, d[1][id]);
			}
			else {
				st.update(cx[i][j].first, d[1][id] + 1);
			}
		}
	}
}
//上から
void calc2() {
	SegT st(mn);
	per(i, mn) {
		rep(j, ux[i].size()) {
			int le = 0, ri = mn;
			int x = i, y = ux[i][j].first;
			int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
			loc--;
			if (loc >= 0 && loc<cx[x].size()) {
				le = cx[x][loc].first + 1;
			}
			loc++;
			int nowi = ux[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cx[x].size()) {
				ri = cx[x][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][ux[i][j].second]);
		}
		rep(j, cx[i].size()) {
			int id = cx[i][j].second;
			if (v[id].f == 2)continue;
			if (v[id].f == 3) {
				st.update(cx[i][j].first, d[1][id]);
			}
			else {
				st.update(cx[i][j].first, d[1][id]+1);
			}
		}
	}
}
void calc3() {
	SegT st(mn);
	rep(i, mn) {
		rep(j, uy[i].size()) {
			int le = 0, ri = mn;
			int x = uy[i][j].first, y = i;
			int loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
			loc--;
			if (loc >= 0 && loc<cy[y].size()) {
				le = cy[y][loc].first + 1;
			}
			loc++;
			int nowi = uy[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cy[y].size()) {
				ri = cy[y][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][uy[i][j].second]);
		}
		rep(j, cy[i].size()) {
			int id = cy[i][j].second;
			if (v[id].f == 2)continue; 
			if (v[id].f == 3) {
				st.update(cy[i][j].first, d[1][id]);
			}
			else {
				st.update(cy[i][j].first, d[1][id] + 1);
			}
		}
	}
}
void calc4() {
	SegT st(mn);
	per(i, mn) {
		rep(j, uy[i].size()) {
			int le = 0, ri = mn;
			int x = uy[i][j].first, y = i;
			int loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
			loc--;
			if (loc >= 0 && loc<cy[y].size()) {
				le = cy[y][loc].first + 1;
			}
			loc++;
			int nowi = uy[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cy[y].size()) {
				ri = cy[y][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][uy[i][j].second]);
		}
		rep(j, cy[i].size()) {
			int id = cy[i][j].second;
			if (v[id].f == 2)continue;
			if (v[id].f == 3) {
				st.update(cy[i][j].first, d[1][id]);
			}
			else {
				st.update(cy[i][j].first, d[1][id] + 1);
			}
		}
	}
}
void calc() {
	calc1(); calc2(); calc3(); calc4();
	if (ans == mod)cout << -1 << endl;
	else cout << ans << endl;
	return;
}
int main() {
	cin >> sx >> sy >> gx >> gy;
	cin >> n;
	rep(i, n) {
		int x, y; cin >> x >> y;
		v.push_back({ x,y,0 });
		v.push_back({ x + 1,y,1 });
		v.push_back({ x - 1,y,1 });
		v.push_back({ x,y + 1,1 });
		v.push_back({ x,y - 1,1 });
	}
	v.push_back({ sx,sy,2 });
	v.push_back({ gx,gy,3 });
	compress(v);
	sort(v.begin(), v.end());
	len = unique(v.begin(), v.end()) - v.begin();

	int sid, gid;
	rep(i, len) {
		inv[{v[i].x, v[i].y}] = i;
		if (v[i].f == 2) {
			sid = i;
		}
		else if (v[i].f == 3) {
			gid = i;
		}
	}
	rep(i, len) {
		int x = v[i].x, y = v[i].y, f = v[i].f;
		if (f == 1)continue;
		cx[x].push_back({ y,i });
		cy[y].push_back({ x,i });
	}
	rep(i, len) {
		int x = v[i].x, y = v[i].y, f = v[i].f;
		if (f == 0)continue;
		ux[x].push_back({ y,i });
		uy[y].push_back({ x,i });

	}
	rep(i, mn) {
		sort(cx[i].begin(), cx[i].end());
		sort(cy[i].begin(), cy[i].end());
		sort(ux[i].begin(), ux[i].end());
		sort(uy[i].begin(), uy[i].end());
	}

	//dijkstra
	rep(i, 2)rep(j, mn)d[i][j] = mod;
	dijkstra(0, sid); dijkstra(1, gid);

	calc();

	//stop
	return 0;
}
accuracy: 0.175
time_ms: 30
memory_kb: 58044
final_rank: 13

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<complex>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<utility>
using namespace std;
typedef long long ll;
typedef unsigned int ui;
const ll mod = 1000000007;
const ll INF = (ll)1000000007 * 1000000007;
typedef pair<int, int> P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
typedef long double ld;
typedef complex<ld> Point;
const ld eps = 1e-6;
const ld pi = acos(-1.0);
typedef pair<ll, ll> LP;

int n;
int sx, sy, gx, gy;

struct vertice {
	int x, y, f;
	bool operator<(const vertice &v)const {
		if (x != v.x)return x < v.x;
		if (y != v.y)return y < v.y;
		return f < v.f;
	}
	bool operator==(const vertice &v)const {
		if (x == v.x&&y == v.y&&f == v.f)return true;
		return false;
	}
};

void compress(vector<vertice> &v) {
	int n = v.size();
	vector<LP> x, y;
	rep(i, n) {
		x.push_back({ v[i].x,i });
		y.push_back({ v[i].y,i });
	}
	sort(x.begin(), x.end());
	sort(y.begin(), y.end());
	int cur = 0;
	rep(i, n) {
		v[x[i].second].x = cur;
		while (i + 1 < n&&x[i].first == x[i + 1].first) {
			i++; v[x[i].second].x = cur;
		}
		cur++;
	}
	cur = 0;
	rep(i, n) {
		v[y[i].second].y = cur;
		while (i + 1 < n&&y[i].first == y[i + 1].first) {
			i++; v[y[i].second].y = cur;
		}
		cur++;
	}
}

vector<vertice> v; map<P, int> inv;

const int mn = 300003;
vector<P> cx[mn], cy[mn];

int d[2][mn];
priority_queue<P, vector<P>, greater<P>> q;
void dijkstra(int id, int root) {
	d[id][root] = 0;
	q.push({ 0,root });
	while (!q.empty()) {
		P p = q.top(); q.pop();
		int i = p.second; int dist = p.first;
		int x = v[i].x, y = v[i].y;
		//x軸
		int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
		loc--;
		if (loc >= 0&&loc<cx[x].size()) {
			int ni = cx[x][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{x, cx[x][loc].first + 1}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		loc++;
		if (v[i].f >= 2)loc++;
		if (loc < cx[x].size()) {
			int ni = cx[x][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{x, cx[x][loc].first - 1}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		//y軸
		loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
		loc--;
		if (loc >= 0&&loc<cy[y].size()) {
			int ni = cy[y][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{cy[y][loc].first + 1, y}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		loc++;
		if (v[i].f >= 2)loc++;
		if (loc < cy[y].size()) {
			int ni = cy[y][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{cy[y][loc].first - 1, y}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			if (dist + 1 < d[id][ni]) {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
	}
}

int ans = mod;

struct SegT {
private:
	int sz; vector<int> node;
	const int init_c = mod;
public:
	SegT(int n) {
		sz = 1;
		while (sz < n)sz *= 2;
		node.resize(2 * sz - 1, init_c);
	}
	int f(int a, int b) {
		return min(a, b);
	}
	void update(int k, int a) {
		k += sz - 1;
		node[k] = a;
		while (k > 0) {
			k = (k - 1) / 2;
			node[k] = f(node[k * 2 + 1], node[k * 2 + 2]);
		}
	}
	int query(int a, int b, int k = 0, int l = 0, int r = -1) {
		if (r < 0)r = sz;
		if (r <= a || b <= l)return init_c;
		else if (a <= l && r <= b)return node[k];
		else {
			int vl = query(a, b, k * 2 + 1, l, (l + r) / 2);
			int vr = query(a, b, k * 2 + 2, (l + r) / 2, r);
			return f(vl, vr);
		}
	}
};
int len;

//全頂点が入ってるほう
vector<P> ux[mn], uy[mn];
//下から
void calc1() {
	SegT st(mn);
	rep(i, mn) {
		rep(j, ux[i].size()) {
			int le = 0, ri = mn;
			int x = i, y = ux[i][j].first;
			int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
			loc--;
			if (loc >= 0&&loc<cx[x].size()) {
				le = cx[x][loc].first + 1;
			}
			loc++;
			int nowi = ux[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cx[x].size()) {
				ri = cx[x][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][ux[i][j].second]);
		}
		rep(j, cx[i].size()) {
			int id = cx[i][j].second;
			if (v[id].f == 2)continue;
			if (v[id].f == 3) {
				st.update(cx[i][j].first, d[1][id]);
			}
			else {
				st.update(cx[i][j].first, d[1][id] + 1);
			}
		}
	}
}
//上から
void calc2() {
	SegT st(mn);
	per(i, mn) {
		rep(j, ux[i].size()) {
			int le = 0, ri = mn;
			int x = i, y = ux[i][j].first;
			int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
			loc--;
			if (loc >= 0 && loc<cx[x].size()) {
				le = cx[x][loc].first + 1;
			}
			loc++;
			int nowi = ux[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cx[x].size()) {
				ri = cx[x][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][ux[i][j].second]);
		}
		rep(j, cx[i].size()) {
			int id = cx[i][j].second;
			if (v[id].f == 2)continue;
			if (v[id].f == 3) {
				st.update(cx[i][j].first, d[1][id]);
			}
			else {
				st.update(cx[i][j].first, d[1][id]+1);
			}
		}
	}
}
void calc3() {
	SegT st(mn);
	rep(i, mn) {
		rep(j, uy[i].size()) {
			int le = 0, ri = mn;
			int x = uy[i][j].first, y = i;
			int loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
			loc--;
			if (loc >= 0 && loc<cy[y].size()) {
				le = cy[y][loc].first + 1;
			}
			loc++;
			int nowi = uy[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cy[y].size()) {
				ri = cy[y][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][uy[i][j].second]);
		}
		rep(j, cy[i].size()) {
			int id = cy[i][j].second;
			if (v[id].f == 2)continue; 
			if (v[id].f == 3) {
				st.update(cy[i][j].first, d[1][id]);
			}
			else {
				st.update(cy[i][j].first, d[1][id] + 1);
			}
		}
	}
}
void calc4() {
	SegT st(mn);
	per(i, mn) {
		rep(j, uy[i].size()) {
			int le = 0, ri = mn;
			int x = uy[i][j].first, y = i;
			int loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
			loc--;
			if (loc >= 0 && loc<cy[y].size()) {
				le = cy[y][loc].first + 1;
			}
			loc++;
			int nowi = uy[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cy[y].size()) {
				ri = cy[y][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][uy[i][j].second]);
		}
		rep(j, cy[i].size()) {
			int id = cy[i][j].second;
			if (v[id].f == 2)continue;
			if (v[id].f == 3) {
				st.update(cy[i][j].first, d[1][id]);
			}
			else {
				st.update(cy[i][j].first, d[1][id] + 1);
			}
		}
	}
}
void calc() {
	calc1(); calc2(); calc3(); calc4();
	if (ans == mod)cout << -1 << endl;
	else cout << ans << endl;
	return;
}
int main() {
	cin >> sx >> sy >> gx >> gy;
	cin >> n;
	rep(i, n) {
		int x, y; cin >> x >> y;
		v.push_back({ x,y,0 });
		v.push_back({ x + 1,y,1 });
		v.push_back({ x - 1,y,1 });
		v.push_back({ x,y + 1,1 });
		v.push_back({ x,y - 1,1 });
	}
	v.push_back({ sx,sy,2 });
	v.push_back({ gx,gy,3 });
	compress(v);
	sort(v.begin(), v.end());
	len = unique(v.begin(), v.end()) - v.begin();

	int sid, gid;
	rep(i, len) {
		inv[{v[i].x, v[i].y}] = i;
		if (v[i].f == 2) {
			sid = i;
		}
		else if (v[i].f == 3) {
			gid = i;
		}
	}
	rep(i, len) {
		int x = v[i].x, y = v[i].y, f = v[i].f;
		if (f == 1)continue;
		cx[x].push_back({ y,i });
		cy[y].push_back({ x,i });
	}
	rep(i, len) {
		int x = v[i].x, y = v[i].y, f = v[i].f;
		if (f == 0)continue;
		ux[x].push_back({ y,i });
		uy[y].push_back({ x,i });

	}
	rep(i, mn) {
		sort(cx[i].begin(), cx[i].end());
		sort(cy[i].begin(), cy[i].end());
		sort(ux[i].begin(), ux[i].end());
		sort(uy[i].begin(), uy[i].end());
	}

	//dijkstra
	rep(i, 2)rep(j, mn)d[i][j] = mod;
	dijkstra(0, sid); dijkstra(1, gid);

	calc();

	//stop
	return 0;
}
accuracy: 0.175
time_ms: 20
memory_kb: 37744
final_rank: 11

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<complex>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<utility>
using namespace std;
typedef long long ll;
typedef unsigned int ui;
const ll mod = 1000000007;
const ll INF = (ll)1000000007 * 1000000007;
typedef pair<int, int> P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
typedef long double ld;
typedef complex<ld> Point;
const ld eps = 1e-6;
const ld pi = acos(-1.0);
typedef pair<ll, ll> LP;

int n;
int sx, sy, gx, gy;

struct vertice {
	int x, y, f;
	bool operator<(const vertice &v)const {
		if (x != v.x)return x < v.x;
		if (y != v.y)return y < v.y;
		return f < v.f;
	}
	bool operator==(const vertice &v)const {
		if (x == v.x&&y == v.y&&f == v.f)return true;
		return false;
	}
};

void compress(vector<vertice> &v) {
	int n = v.size();
	vector<LP> x, y;
	rep(i, n) {
		x.push_back({ v[i].x,i });
		y.push_back({ v[i].y,i });
	}
	sort(x.begin(), x.end());
	sort(y.begin(), y.end());
	int cur = 0;
	rep(i, n) {
		v[x[i].second].x = cur;
		while (i + 1 < n&&x[i].first == x[i + 1].first) {
			i++; v[x[i].second].x = cur;
		}
		cur++;
	}
	cur = 0;
	rep(i, n) {
		v[y[i].second].y = cur;
		while (i + 1 < n&&y[i].first == y[i + 1].first) {
			i++; v[y[i].second].y = cur;
		}
		cur++;
	}
}

vector<vertice> v; map<P, int> inv;

const int mn = 300003;
vector<P> cx[mn], cy[mn];

int d[2][mn];
priority_queue<P, vector<P>, greater<P>> q;
void dijkstra(int id, int root) {
	d[id][root] = 0;
	q.push({ 0,root });
	while (!q.empty()) {
		P p = q.top(); q.pop();
		int i = p.second; int dist = p.first;
		int x = v[i].x, y = v[i].y;
		//x軸
		int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
		loc--;
		if (loc >= 0&&loc<cx[x].size()) {
			int ni = cx[x][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{x, cx[x][loc].first + 1}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		loc++;
		if (v[i].f >= 2)loc++;
		if (loc < cx[x].size()) {
			int ni = cx[x][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{x, cx[x][loc].first - 1}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		//y軸
		loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
		loc--;
		if (loc >= 0&&loc<cy[y].size()) {
			int ni = cy[y][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{cy[y][loc].first + 1, y}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		loc++;
		if (v[i].f >= 2)loc++;
		if (loc < cy[y].size()) {
			int ni = cy[y][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{cy[y][loc].first - 1, y}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			if (dist + 1 < d[id][ni]) {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
	}
}

int ans = mod;

struct SegT {
private:
	int sz; vector<int> node;
	const int init_c = mod;
public:
	SegT(int n) {
		sz = 1;
		while (sz < n)sz *= 2;
		node.resize(2 * sz - 1, init_c);
	}
	int f(int a, int b) {
		return min(a, b);
	}
	void update(int k, int a) {
		k += sz - 1;
		node[k] = a;
		while (k > 0) {
			k = (k - 1) / 2;
			node[k] = f(node[k * 2 + 1], node[k * 2 + 2]);
		}
	}
	int query(int a, int b, int k = 0, int l = 0, int r = -1) {
		if (r < 0)r = sz;
		if (r <= a || b <= l)return init_c;
		else if (a <= l && r <= b)return node[k];
		else {
			int vl = query(a, b, k * 2 + 1, l, (l + r) / 2);
			int vr = query(a, b, k * 2 + 2, (l + r) / 2, r);
			return f(vl, vr);
		}
	}
};
int len;

//全頂点が入ってるほう
vector<P> ux[mn], uy[mn];
//下から
void calc1() {
	SegT st(mn);
	rep(i, mn) {
		rep(j, ux[i].size()) {
			int le = 0, ri = mn;
			int x = i, y = ux[i][j].first;
			int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
			loc--;
			if (loc >= 0&&loc<cx[x].size()) {
				le = cx[x][loc].first + 1;
			}
			loc++;
			int nowi = ux[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cx[x].size()) {
				ri = cx[x][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][ux[i][j].second]);
		}
		rep(j, cx[i].size()) {
			int id = cx[i][j].second;
			if (v[id].f == 2)continue;
			st.update(cx[i][j].first, d[1][id]);
		}
	}
}
//上から
void calc2() {
	SegT st(mn);
	per(i, mn) {
		rep(j, ux[i].size()) {
			int le = 0, ri = mn;
			int x = i, y = ux[i][j].first;
			int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
			loc--;
			if (loc >= 0 && loc<cx[x].size()) {
				le = cx[x][loc].first + 1;
			}
			loc++;
			int nowi = ux[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cx[x].size()) {
				ri = cx[x][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][ux[i][j].second]);
		}
		rep(j, cx[i].size()) {
			int id = cx[i][j].second;
			if (v[id].f == 2)continue;
			st.update(cx[i][j].first, d[1][id]);
		}
	}
}
void calc3() {
	SegT st(mn);
	rep(i, mn) {
		rep(j, uy[i].size()) {
			int le = 0, ri = mn;
			int x = uy[i][j].first, y = i;
			int loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
			loc--;
			if (loc >= 0 && loc<cy[y].size()) {
				le = cy[y][loc].first + 1;
			}
			loc++;
			int nowi = uy[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cy[y].size()) {
				ri = cy[y][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][uy[i][j].second]);
		}
		rep(j, cy[i].size()) {
			int id = cy[i][j].second;
			if (v[id].f == 2)continue;
			st.update(cy[i][j].first, d[1][id]);
		}
	}
}
void calc4() {
	SegT st(mn);
	per(i, mn) {
		rep(j, uy[i].size()) {
			int le = 0, ri = mn;
			int x = uy[i][j].first, y = i;
			int loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
			loc--;
			if (loc >= 0 && loc<cy[y].size()) {
				le = cy[y][loc].first + 1;
			}
			loc++;
			int nowi = uy[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cy[y].size()) {
				ri = cy[y][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][uy[i][j].second]);
		}
		rep(j, cy[i].size()) {
			int id = cy[i][j].second;
			if (v[id].f == 2)continue;
			st.update(cy[i][j].first, d[1][id]);
		}
	}
}
void calc() {
	calc1(); calc2(); calc3(); calc4();
	if (ans == mod)cout << -1 << endl;
	else cout << ans << endl;
	return;
}
int main() {
	cin >> sx >> sy >> gx >> gy;
	cin >> n;
	rep(i, n) {
		int x, y; cin >> x >> y;
		v.push_back({ x,y,0 });
		v.push_back({ x + 1,y,1 });
		v.push_back({ x - 1,y,1 });
		v.push_back({ x,y + 1,1 });
		v.push_back({ x,y - 1,1 });
	}
	v.push_back({ sx,sy,2 });
	v.push_back({ gx,gy,3 });
	compress(v);
	sort(v.begin(), v.end());
	len = unique(v.begin(), v.end()) - v.begin();

	int sid, gid;
	rep(i, len) {
		inv[{v[i].x, v[i].y}] = i;
		if (v[i].f == 2) {
			sid = i;
		}
		else if (v[i].f == 3) {
			gid = i;
		}
	}
	rep(i, len) {
		int x = v[i].x, y = v[i].y, f = v[i].f;
		if (f == 1)continue;
		cx[x].push_back({ y,i });
		cy[y].push_back({ x,i });
	}
	rep(i, len) {
		int x = v[i].x, y = v[i].y, f = v[i].f;
		if (f == 0)continue;
		ux[x].push_back({ y,i });
		uy[y].push_back({ x,i });

	}
	rep(i, mn) {
		sort(cx[i].begin(), cx[i].end());
		sort(cy[i].begin(), cy[i].end());
		sort(ux[i].begin(), ux[i].end());
		sort(uy[i].begin(), uy[i].end());
	}

	//dijkstra
	rep(i, 2)rep(j, mn)d[i][j] = mod;
	dijkstra(0, sid); dijkstra(1, gid);

	calc();

	//stop
	return 0;
}
accuracy: 0.175
time_ms: 10
memory_kb: 37728
final_rank: 8

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<complex>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<utility>
using namespace std;
typedef long long ll;
typedef unsigned int ui;
const ll mod = 1000000007;
const ll INF = (ll)1000000007 * 1000000007;
typedef pair<int, int> P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
typedef long double ld;
typedef complex<ld> Point;
const ld eps = 1e-6;
const ld pi = acos(-1.0);
typedef pair<ll, ll> LP;

int n;
int sx, sy, gx, gy;

struct vertice {
	int x, y, f;
	bool operator<(const vertice &v)const {
		if (x != v.x)return x < v.x;
		if (y != v.y)return y < v.y;
		return f < v.f;
	}
	bool operator==(const vertice &v)const {
		if (x == v.x&&y == v.y&&f == v.f)return true;
		return false;
	}
};

void compress(vector<vertice> &v) {
	int n = v.size();
	vector<LP> x, y;
	rep(i, n) {
		x.push_back({ v[i].x,i });
		y.push_back({ v[i].y,i });
	}
	sort(x.begin(), x.end());
	sort(y.begin(), y.end());
	int cur = 0;
	rep(i, n) {
		v[x[i].second].x = cur;
		while (i + 1 < n&&x[i].first == x[i + 1].first) {
			i++; v[x[i].second].x = cur;
		}
		cur++;
	}
	cur = 0;
	rep(i, n) {
		v[y[i].second].y = cur;
		while (i + 1 < n&&y[i].first == y[i + 1].first) {
			i++; v[y[i].second].y = cur;
		}
		cur++;
	}
}

vector<vertice> v; map<P, int> inv;

const int mn = 300003;
vector<P> cx[mn], cy[mn];

int d[2][mn];
priority_queue<P, vector<P>, greater<P>> q;
void dijkstra(int id, int root) {
	d[id][root] = 0;
	q.push({ 0,root });
	while (!q.empty()) {
		P p = q.top(); q.pop();
		int i = p.second; int dist = p.first;
		int x = v[i].x, y = v[i].y;
		//x軸
		int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
		loc--;
		if (loc >= 0&&loc<cx[x].size()) {
			int ni = cx[x][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{x, cx[x][loc].first + 1}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		loc++;
		if (v[i].f >= 2)loc++;
		if (loc < cx[x].size()) {
			int ni = cx[x][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{x, cx[x][loc].first - 1}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		//y軸
		loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
		loc--;
		if (loc >= 0&&loc<cy[y].size()) {
			int ni = cy[y][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{cy[y][loc].first + 1, y}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		loc++;
		if (v[i].f >= 2)loc++;
		if (loc < cy[y].size()) {
			int ni = cy[y][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{cy[y][loc].first - 1, y}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			if (dist + 1 < d[id][ni]) {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
	}
}

int ans = mod;

struct SegT {
private:
	int sz; vector<int> node;
	const int init_c = mod;
public:
	SegT(int n) {
		sz = 1;
		while (sz < n)sz *= 2;
		node.resize(2 * sz - 1, init_c);
	}
	int f(int a, int b) {
		return min(a, b);
	}
	void update(int k, int a) {
		k += sz - 1;
		node[k] = a;
		while (k > 0) {
			k = (k - 1) / 2;
			node[k] = f(node[k * 2 + 1], node[k * 2 + 2]);
		}
	}
	int query(int a, int b, int k = 0, int l = 0, int r = -1) {
		if (r < 0)r = sz;
		if (r <= a || b <= l)return init_c;
		else if (a <= l && r <= b)return node[k];
		else {
			int vl = query(a, b, k * 2 + 1, l, (l + r) / 2);
			int vr = query(a, b, k * 2 + 2, (l + r) / 2, r);
			return f(vl, vr);
		}
	}
};
int len;

//全頂点が入ってるほう
vector<P> ux[mn], uy[mn];
//下から
void calc1() {
	SegT st(mn);
	rep(i, mn) {
		rep(j, ux[i].size()) {
			int le = 0, ri = mn;
			int x = i, y = ux[i][j].first;
			int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
			loc--;
			if (loc >= 0&&loc<cx[x].size()) {
				le = cx[x][loc].first + 1;
			}
			loc++;
			int nowi = ux[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cx[x].size()) {
				ri = cx[x][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][ux[i][j].second]);
		}
		rep(j, cx[i].size()) {
			int id = cx[i][j].second;
			st.update(cx[i][j].first, d[1][id]);
		}
	}
}
//上から
void calc2() {
	SegT st(mn);
	per(i, mn) {
		rep(j, ux[i].size()) {
			int le = 0, ri = mn;
			int x = i, y = ux[i][j].first;
			int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
			loc--;
			if (loc >= 0 && loc<cx[x].size()) {
				le = cx[x][loc].first + 1;
			}
			loc++;
			int nowi = ux[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cx[x].size()) {
				ri = cx[x][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][ux[i][j].second]);
		}
		rep(j, cx[i].size()) {
			int id = cx[i][j].second;
			st.update(cx[i][j].first, d[1][id]);
		}
	}
}
void calc3() {
	SegT st(mn);
	rep(i, mn) {
		rep(j, uy[i].size()) {
			int le = 0, ri = mn;
			int x = uy[i][j].first, y = i;
			int loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
			loc--;
			if (loc >= 0 && loc<cy[y].size()) {
				le = cy[y][loc].first + 1;
			}
			loc++;
			int nowi = uy[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cy[y].size()) {
				ri = cy[y][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][uy[i][j].second]);
		}
		rep(j, cy[i].size()) {
			int id = cy[i][j].second;
			st.update(cy[i][j].first, d[1][id]);
		}
	}
}
void calc4() {
	SegT st(mn);
	per(i, mn) {
		rep(j, uy[i].size()) {
			int le = 0, ri = mn;
			int x = uy[i][j].first, y = i;
			int loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
			loc--;
			if (loc >= 0 && loc<cy[y].size()) {
				le = cy[y][loc].first + 1;
			}
			loc++;
			int nowi = uy[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cy[y].size()) {
				ri = cy[y][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][uy[i][j].second]);
		}
		rep(j, cy[i].size()) {
			int id = cy[i][j].second;
			st.update(cy[i][j].first, d[1][id]);
		}
	}
}
void calc() {
	calc1(); calc2(); calc3(); calc4();
	if (ans == mod)cout << -1 << endl;
	else cout << ans << endl;
	return;
}
int main() {
	cin >> sx >> sy >> gx >> gy;
	cin >> n;
	rep(i, n) {
		int x, y; cin >> x >> y;
		v.push_back({ x,y,0 });
		v.push_back({ x + 1,y,1 });
		v.push_back({ x - 1,y,1 });
		v.push_back({ x,y + 1,1 });
		v.push_back({ x,y - 1,1 });
	}
	v.push_back({ sx,sy,2 });
	v.push_back({ gx,gy,3 });
	compress(v);
	sort(v.begin(), v.end());
	len = unique(v.begin(), v.end()) - v.begin();

	int sid, gid;
	rep(i, len) {
		inv[{v[i].x, v[i].y}] = i;
		if (v[i].f == 2) {
			sid = i;
		}
		else if (v[i].f == 3) {
			gid = i;
		}
	}
	rep(i, len) {
		int x = v[i].x, y = v[i].y, f = v[i].f;
		if (f == 1)continue;
		cx[x].push_back({ y,i });
		cy[y].push_back({ x,i });
	}
	rep(i, len) {
		int x = v[i].x, y = v[i].y, f = v[i].f;
		if (f == 0)continue;
		ux[x].push_back({ y,i });
		uy[y].push_back({ x,i });

	}
	rep(i, mn) {
		sort(cx[i].begin(), cx[i].end());
		sort(cy[i].begin(), cy[i].end());
		sort(ux[i].begin(), ux[i].end());
		sort(uy[i].begin(), uy[i].end());
	}

	//dijkstra
	rep(i, 2)rep(j, mn)d[i][j] = mod;
	dijkstra(0, sid); dijkstra(1, gid);

	calc();

	//stop
	return 0;
}
accuracy: 0.175
time_ms: 20
memory_kb: 37736
final_rank: 10

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<complex>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<utility>
using namespace std;
typedef long long ll;
typedef unsigned int ui;
const ll mod = 1000000007;
const ll INF = (ll)1000000007 * 1000000007;
typedef pair<int, int> P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
typedef long double ld;
typedef complex<ld> Point;
const ld eps = 1e-6;
const ld pi = acos(-1.0);
typedef pair<ll, ll> LP;

int n;
int sx, sy, gx, gy;

struct vertice {
	int x, y, f;
	bool operator<(const vertice &v)const {
		if (x != v.x)return x < v.x;
		if (y != v.y)return y < v.y;
		return f < v.f;
	}
	bool operator==(const vertice &v)const {
		if (x == v.x&&y == v.y&&f == v.f)return true;
		return false;
	}
};

void compress(vector<vertice> &v) {
	int n = v.size();
	vector<LP> x, y;
	rep(i, n) {
		x.push_back({ v[i].x,i });
		y.push_back({ v[i].y,i });
	}
	sort(x.begin(), x.end());
	sort(y.begin(), y.end());
	int cur = 0;
	rep(i, n) {
		v[x[i].second].x = cur;
		while (i + 1 < n&&x[i].first == x[i + 1].first) {
			i++; v[x[i].second].x = cur;
		}
		cur++;
	}
	cur = 0;
	rep(i, n) {
		v[y[i].second].y = cur;
		while (i + 1 < n&&y[i].first == y[i + 1].first) {
			i++; v[y[i].second].y = cur;
		}
		cur++;
	}
}

vector<vertice> v; map<P, int> inv;

const int mn = 300003;
vector<P> cx[mn], cy[mn];

int d[2][mn];
priority_queue<P, vector<P>, greater<P>> q;
void dijkstra(int id, int root) {
	d[id][root] = 0;
	q.push({ 0,root });
	while (!q.empty()) {
		P p = q.top(); q.pop();
		int i = p.second; int dist = p.first;
		int x = v[i].x, y = v[i].y;
		//x軸
		int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
		loc--;
		if (loc >= 0&&loc<cx[x].size()) {
			int ni = cx[x][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{x, cx[x][loc].first + 1}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		loc++;
		if (v[i].f >= 2)loc++;
		if (loc < cx[x].size()) {
			int ni = cx[x][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{x, cx[x][loc].first - 1}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		//y軸
		loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
		loc--;
		if (loc >= 0&&loc<cy[y].size()) {
			int ni = cy[y][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{cy[y][loc].first + 1, y}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		loc++;
		if (v[i].f >= 2)loc++;
		if (loc < cy[y].size()) {
			int ni = cy[y][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{cy[y][loc].first - 1, y}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			if (dist + 1 < d[id][ni]) {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
	}
}

int ans = mod;

struct SegT {
private:
	int sz; vector<int> node;
	const int init_c = mod;
public:
	SegT(int n) {
		sz = 1;
		while (sz < n)sz *= 2;
		node.resize(2 * sz - 1, init_c);
	}
	int f(int a, int b) {
		return min(a, b);
	}
	void update(int k, int a) {
		k += sz - 1;
		node[k] = a;
		while (k > 0) {
			k = (k - 1) / 2;
			node[k] = f(node[k * 2 + 1], node[k * 2 + 2]);
		}
	}
	int query(int a, int b, int k = 0, int l = 0, int r = -1) {
		if (r < 0)r = sz;
		if (r <= a || b <= l)return init_c;
		else if (a <= l && r <= b)return node[k];
		else {
			int vl = query(a, b, k * 2 + 1, l, (l + r) / 2);
			int vr = query(a, b, k * 2 + 2, (l + r) / 2, r);
			return f(vl, vr);
		}
	}
};
int len;

//全頂点が入ってるほう
vector<P> ux[mn], uy[mn];
//下から
void calc1() {
	SegT st(mn);
	rep(i, mn) {
		rep(j, ux[i].size()) {
			int le = 0, ri = mn;
			int x = i, y = ux[i][j].first;
			int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
			loc--;
			if (loc >= 0&&loc<cx[x].size()) {
				le = cx[x][loc].first + 1;
			}
			loc++;
			int nowi = ux[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cx[x].size()) {
				ri = cx[x][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][ux[i][j].second]);
		}
		rep(j, cx[i].size()) {
			int id = cx[i][j].second;
			st.update(cx[i][j].first, d[1][id]);
		}
	}
}
//上から
void calc2() {
	SegT st(mn);
	per(i, mn) {
		rep(j, ux[i].size()) {
			int le = 0, ri = mn;
			int x = i, y = ux[i][j].first;
			int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
			loc--;
			if (loc >= 0 && loc<cx[x].size()) {
				le = cx[x][loc].first + 1;
			}
			loc++;
			int nowi = ux[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cx[x].size()) {
				ri = cx[x][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][ux[i][j].second]);
		}
		rep(j, cx[i].size()) {
			int id = cx[i][j].second;
			st.update(cx[i][j].first, d[1][id]);
		}
	}
}
void calc3() {
	SegT st(mn);
	rep(i, mn) {
		rep(j, uy[i].size()) {
			int le = 0, ri = mn;
			int x = uy[i][j].first, y = i;
			int loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
			loc--;
			if (loc >= 0 && loc<cy[y].size()) {
				le = cy[y][loc].first + 1;
			}
			loc++;
			int nowi = uy[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cy[y].size()) {
				ri = cy[y][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][uy[i][j].second]);
		}
		rep(j, cy[i].size()) {
			int id = cy[i][j].second;
			st.update(cy[i][j].first, d[1][id]);
		}
	}
}
void calc4() {
	SegT st(mn);
	rep(i, mn) {
		rep(j, uy[i].size()) {
			int le = 0, ri = mn;
			int x = uy[i][j].first, y = i;
			int loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
			loc--;
			if (loc >= 0 && loc<cy[y].size()) {
				le = cy[y][loc].first + 1;
			}
			loc++;
			int nowi = uy[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cy[y].size()) {
				ri = cy[y][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][uy[i][j].second]);
		}
		rep(j, cy[i].size()) {
			int id = cy[i][j].second;
			st.update(cy[i][j].first, d[1][id]);
		}
	}
}
void calc() {
	calc1(); calc2(); calc3(); calc4();
	if (ans == mod)cout << -1 << endl;
	else cout << ans << endl;
	return;
}
int main() {
	cin >> sx >> sy >> gx >> gy;
	cin >> n;
	rep(i, n) {
		int x, y; cin >> x >> y;
		v.push_back({ x,y,0 });
		v.push_back({ x + 1,y,1 });
		v.push_back({ x - 1,y,1 });
		v.push_back({ x,y + 1,1 });
		v.push_back({ x,y - 1,1 });
	}
	v.push_back({ sx,sy,2 });
	v.push_back({ gx,gy,3 });
	compress(v);
	sort(v.begin(), v.end());
	len = unique(v.begin(), v.end()) - v.begin();

	int sid, gid;
	rep(i, len) {
		inv[{v[i].x, v[i].y}] = i;
		if (v[i].f == 2) {
			sid = i;
		}
		else if (v[i].f == 3) {
			gid = i;
		}
	}
	rep(i, len) {
		int x = v[i].x, y = v[i].y, f = v[i].f;
		if (f == 1)continue;
		cx[x].push_back({ y,i });
		cy[y].push_back({ x,i });
	}
	rep(i, len) {
		int x = v[i].x, y = v[i].y, f = v[i].f;
		if (f == 0)continue;
		ux[x].push_back({ y,i });
		uy[y].push_back({ x,i });

	}
	rep(i, mn) {
		sort(cx[i].begin(), cx[i].end());
		sort(cy[i].begin(), cy[i].end());
		sort(ux[i].begin(), ux[i].end());
		sort(uy[i].begin(), uy[i].end());
	}

	//dijkstra
	rep(i, 2)rep(j, mn)d[i][j] = mod;
	dijkstra(0, sid); dijkstra(1, gid);

	calc();

	//stop
	return 0;
}
accuracy: 0.175
time_ms: 20
memory_kb: 37728
final_rank: 9

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<complex>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<utility>
using namespace std;
typedef long long ll;
typedef unsigned int ui;
const ll mod = 1000000007;
const ll INF = (ll)1000000007 * 1000000007;
typedef pair<int, int> P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
typedef long double ld;
typedef complex<ld> Point;
const ld eps = 1e-6;
const ld pi = acos(-1.0);
typedef pair<ll, ll> LP;

int n;
int sx, sy, gx, gy;

struct vertice {
	int x, y, f;
	bool operator<(const vertice &v)const {
		if (x != v.x)return x < v.x;
		if (y != v.y)return y < v.y;
		return f < v.f;
	}
	bool operator==(const vertice &v)const {
		if (x == v.x&&y == v.y&&f == v.f)return true;
		return false;
	}
};

void compress(vector<vertice> &v) {
	int n = v.size();
	vector<LP> x, y;
	rep(i, n) {
		x.push_back({ v[i].x,i });
		y.push_back({ v[i].y,i });
	}
	sort(x.begin(), x.end());
	sort(y.begin(), y.end());
	int cur = 0;
	rep(i, n) {
		v[x[i].second].x = cur;
		while (i + 1 < n&&x[i].first == x[i + 1].first) {
			i++; v[x[i].second].x = cur;
		}
		cur++;
	}
	cur = 0;
	rep(i, n) {
		v[y[i].second].y = cur;
		while (i + 1 < n&&y[i].first == y[i + 1].first) {
			i++; v[y[i].second].y = cur;
		}
		cur++;
	}
}

vector<vertice> v; map<P, int> inv;

const int mn = 300003;
vector<P> cx[mn], cy[mn];

int d[2][mn];
priority_queue<P, vector<P>, greater<P>> q;
void dijkstra(int id, int root) {
	d[id][root] = 0;
	q.push({ 0,root });
	while (!q.empty()) {
		P p = q.top(); q.pop();
		int i = p.second; int dist = p.first;
		int x = v[i].x, y = v[i].y;
		//x軸
		int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
		loc--;
		if (loc >= 0) {
			int ni = cx[x][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{x, cx[x][loc].first + 1}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		loc++;
		if (v[i].f >= 2)loc++;
		if (loc < cx[x].size()) {
			int ni = cx[x][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{x, cx[x][loc].first - 1}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		//y軸
		loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
		loc--;
		if (loc >= 0) {
			int ni = cy[y][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{cy[y][loc].first + 1, y}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			else {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
		loc++;
		if (v[i].f >= 2)loc++;
		if (loc < cy[y].size()) {
			int ni = cy[y][loc].second;
			if (v[ni].f == 0) {
				ni = inv[{cy[y][loc].first - 1, y}];
				if (dist + 1 < d[id][ni]) {
					d[id][ni] = dist + 1;
					q.push({ d[id][ni],ni });
				}
			}
			if (dist + 1 < d[id][ni]) {
				d[id][ni] = min(d[id][ni], dist);
			}
		}
	}
}

int ans = mod;

struct SegT {
private:
	int sz; vector<int> node;
	const int init_c = mod;
public:
	SegT(int n) {
		sz = 1;
		while (sz < n)sz *= 2;
		node.resize(2 * sz - 1, init_c);
	}
	int f(int a, int b) {
		return min(a, b);
	}
	void update(int k, int a) {
		k += sz - 1;
		node[k] = a;
		while (k > 0) {
			k = (k - 1) / 2;
			node[k] = f(node[k * 2 + 1], node[k * 2 + 2]);
		}
	}
	int query(int a, int b, int k = 0, int l = 0, int r = -1) {
		if (r < 0)r = sz;
		if (r <= a || b <= l)return init_c;
		else if (a <= l && r <= b)return node[k];
		else {
			int vl = query(a, b, k * 2 + 1, l, (l + r) / 2);
			int vr = query(a, b, k * 2 + 2, (l + r) / 2, r);
			return f(vl, vr);
		}
	}
};
int len;

//全頂点が入ってるほう
vector<P> ux[mn], uy[mn];
//下から
void calc1() {
	SegT st(mn);
	rep(i, mn) {
		rep(j, ux[i].size()) {
			int le = 0, ri = mn;
			int x = i, y = ux[i][j].first;
			int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
			loc--;
			if (loc >= 0) {
				le = cx[x][loc].first + 1;
			}
			loc++;
			int nowi = ux[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cx[x].size()) {
				ri = cx[x][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][ux[i][j].second]);
		}
		rep(j, cx[i].size()) {
			int id = cx[i][j].second;
			st.update(cx[i][j].first, d[1][id]);
		}
	}
}
//上から
void calc2() {
	SegT st(mn);
	per(i, mn) {
		rep(j, ux[i].size()) {
			int le = 0, ri = mn;
			int x = i, y = ux[i][j].first;
			int loc = lower_bound(cx[x].begin(), cx[x].end(), P{ y,-1 }) - cx[x].begin();
			loc--;
			if (loc >= 0) {
				le = cx[x][loc].first + 1;
			}
			loc++;
			int nowi = ux[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cx[x].size()) {
				ri = cx[x][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][ux[i][j].second]);
		}
		rep(j, cx[i].size()) {
			int id = cx[i][j].second;
			st.update(cx[i][j].first, d[1][id]);
		}
	}
}
void calc3() {
	SegT st(mn);
	rep(i, mn) {
		rep(j, uy[i].size()) {
			int le = 0, ri = mn;
			int x = uy[i][j].first, y = i;
			int loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
			loc--;
			if (loc >= 0) {
				le = cy[y][loc].first + 1;
			}
			loc++;
			int nowi = ux[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cy[y].size()) {
				ri = cy[y][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][uy[i][j].second]);
		}
		rep(j, cy[i].size()) {
			int id = cy[i][j].second;
			st.update(cy[i][j].first, d[1][id]);
		}
	}
}
void calc4() {
	SegT st(mn);
	rep(i, mn) {
		rep(j, uy[i].size()) {
			int le = 0, ri = mn;
			int x = uy[i][j].first, y = i;
			int loc = lower_bound(cy[y].begin(), cy[y].end(), P{ x,-1 }) - cy[y].begin();
			loc--;
			if (loc >= 0) {
				le = cy[y][loc].first + 1;
			}
			loc++;
			int nowi = ux[i][j].second;
			if (v[nowi].f >= 2)loc++;
			if (loc < cy[y].size()) {
				ri = cy[y][loc].first;
			}
			int z = st.query(le, ri);
			ans = min(ans, z + d[0][uy[i][j].second]);
		}
		rep(j, cy[i].size()) {
			int id = cy[i][j].second;
			st.update(cy[i][j].first, d[1][id]);
		}
	}
}
void calc() {
	calc1(); calc2(); calc3(); calc4();
	if (ans == mod)cout << -1 << endl;
	else cout << ans << endl;
	return;
}
int main() {
	cin >> sx >> sy >> gx >> gy;
	cin >> n;
	rep(i, n) {
		int x, y; cin >> x >> y;
		v.push_back({ x,y,0 });
		v.push_back({ x + 1,y,1 });
		v.push_back({ x - 1,y,1 });
		v.push_back({ x,y + 1,1 });
		v.push_back({ x,y - 1,1 });
	}
	v.push_back({ sx,sy,2 });
	v.push_back({ gx,gy,3 });
	compress(v);
	sort(v.begin(), v.end());
	len = unique(v.begin(), v.end()) - v.begin();

	int sid, gid;
	rep(i, len) {
		inv[{v[i].x, v[i].y}] = i;
		if (v[i].f == 2) {
			sid = i;
		}
		else if (v[i].f == 3) {
			gid = i;
		}
	}
	rep(i, len) {
		int x = v[i].x, y = v[i].y, f = v[i].f;
		if (f == 1)continue;
		cx[x].push_back({ y,i });
		cy[y].push_back({ x,i });
	}
	rep(i, len) {
		int x = v[i].x, y = v[i].y, f = v[i].f;
		if (f == 0)continue;
		ux[x].push_back({ y,i });
		uy[y].push_back({ x,i });

	}
	rep(i, mn) {
		sort(cx[i].begin(), cx[i].end());
		sort(cy[i].begin(), cy[i].end());
		sort(ux[i].begin(), ux[i].end());
		sort(uy[i].begin(), uy[i].end());
	}

	//dijkstra
	rep(i, 2)rep(j, mn)d[i][j] = mod;
	dijkstra(0, sid); dijkstra(1, gid);

	calc();

	//stop
	return 0;
}
accuracy: 0.075
time_ms: 20
memory_kb: 37716
final_rank: 18

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

using namespace std;
typedef long long LL;

#ifdef BTK
#define DEBUG if(1)
#else
#define CIN_ONLY if(1)
struct cww {cww() {CIN_ONLY{ios::sync_with_stdio(false); cin.tie(0);}}
}star;
#define DEBUG if(0)
#endif

#define ALL(v) (v).begin(),(v).end()
#define REC(ret, ...) std::function<ret (__VA_ARGS__)>
template <typename T>inline bool chmin(T &l, T r){bool a = l>r; if (a)l = r; return a;}
template <typename T>inline bool chmax(T &l, T r){bool a = l<r; if (a)l = r; return a;}
template <typename T>istream& operator>>(istream &is, vector<T> &v){for (auto &it : v)is >> it;return is;}

class range {private: struct I { int x; int operator*() { return x; }bool operator!=(I& lhs) { return x<lhs.x; }void operator++() { ++x; } }; I i, n;public:range(int n) :i({ 0 }), n({ n }) {}range(int i, int n) :i({ i }), n({ n }) {}I& begin() { return i; }I& end() { return n; }};

constexpr int MAX_N = 812345;
struct P{
	int r, c;
};
istream& operator>>(istream &is, P &v) { is >> v.r >> v.c; return is; }

P S, T;
int N;
P in[MAX_N];
namespace Z{
	int latte[MAX_N];
	int id;
	void init() {
		id = 0;
	}
	inline void set(int v) {
		latte[id++] = v;
	}
	inline void build() {
		sort(latte, latte + id);
		id = unique(latte, latte + id) - latte;
	}
	inline int ItoZ(int v) {
		return lower_bound(latte, latte + id, v) - latte;
	}
	inline int ZtoI(int v) {
		return latte[v];
	}
}

bool input() {
	if(cin >> S >> T);
	else return false;
	cin >> N;
	Z::init();
	for (int j : {-1, 0, 1}) {
		Z::set(S.r + j);
		Z::set(S.c + j);
		Z::set(T.r + j);
		Z::set(T.c + j);
	}
	for (int i : range(N)) {
		cin >> in[i];
		for (int j : {-1, 0, 1}) {
			Z::set(in[i].r + j);
			Z::set(in[i].c + j);
		}
	}
	Z::build();
	S.r = Z::ItoZ(S.r);	S.c = Z::ItoZ(S.c);
	T.r = Z::ItoZ(T.r);	T.c = Z::ItoZ(T.c);
	for (int i : range(N)) {
		in[i].r = Z::ItoZ(in[i].r);
		in[i].c = Z::ItoZ(in[i].c);
	}
#ifdef BTK
	cout << S.r << " " << S.c << endl;
	cout << T.r << " " << T.c << endl;
	cout << N << endl;
	for (int i : range(N)) {
		cout << in[i].r << " " << in[i].c << endl;
	}
#endif
	return true;
}
typedef vector<int> V;
typedef vector<V> VV;
typedef vector<VV> VVV;
constexpr int dr[4] = { 1,0,0,-1 };
constexpr int dc[4] = { 0,1,-1,0 };
const string ds = { "DRLU" };
struct Tate {
	static constexpr int index = 0;
	static inline bool comp(const int lr, const int lc, const int rr, const int rc) {
		return lr == rr ? lc < rc : lr < rr;
	}
};
struct Yoko {
	static constexpr int index = 1;
	static inline bool comp(const int lr, const int lc, const int rr, const int rc) {
		return lc == rc ? lr < rr : lc < rc;
	}
};

namespace pts {
	int pt[2][MAX_N];
	int cr[MAX_N];
	template<typename dir>
	inline bool ice_comp(const int li, const int ri) {
		return dir::comp(in[li].r, in[li].c, in[ri].r, in[ri].c);
	}
	void build() {
		iota(pt[Yoko::index], pt[Yoko::index] + N, 0);
		iota(pt[Tate::index], pt[Tate::index] + N, 0);
		sort(pt[Yoko::index], pt[Yoko::index] + N, ice_comp<Yoko>);
		sort(pt[Tate::index], pt[Tate::index] + N, ice_comp<Tate>);
	}
	template<typename dir>
	inline int lower_bound(int r, int c) {
		int lb = -1, ub = N;
		while (ub - lb > 1) {
			const int mid = (lb + ub) / 2;
			(!dir::comp(r, c, in[pt[dir::index][mid]].r, in[pt[dir::index][mid]].c) ? lb : ub) = mid;
		}
		return ub;
	}
	inline bool isIce(int r, int c) {

		int id = lower_bound<Yoko>(r, c);
		return id != N && in[pt[Yoko::index][id]].r == r && in[pt[Yoko::index][id]].c == c;
	}
}

struct Down {
	static constexpr int index = 0;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Yoko>(r, c);
		if (id != N && in[pts::pt[Yoko::index][id]].c == c)
			return pts::pt[Yoko::index][id];
		else return -1;
	}
};

struct Right {
	static constexpr int index = 1;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Tate>(r, c);
		if (id != N && in[pts::pt[Tate::index][id]].r == r)
			return pts::pt[Tate::index][id];
		else return -1;
	}
};
struct Left {
	static constexpr int index = 2;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Tate>(r, c) - 1;
		if (id != -1 && in[pts::pt[Tate::index][id]].r == r)
			return pts::pt[Tate::index][id];
		else return -1;
	}
};
struct Up {
	static constexpr int index = 3;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Yoko>(r, c) - 1;
		if (id != -1 && in[pts::pt[Yoko::index][id]].c == c)
			return pts::pt[Yoko::index][id];
		else return -1;
	}
};
		
inline bool isReachable(int r,int c,int nr,int nc) {
	if (r == nr) {
		if (c < nc) {
			const int id = Right::getIce(r, c);
			return id == -1 || nc < in[id].c;
		}
		else if (nc < c) {
			const int id = Left::getIce(r, c);
			return id == -1 || in[id].c < nc;
		}
		else return true;
	}
	else if (c == nc) {
		if (r < nr) {
			const int id = Down::getIce(r, c);
			return id == -1 || nr < in[id].r;
		}
		else if (nr < r) {
			const int id = Up::getIce(r, c);
			return id == -1 || in[id].r < nr;
		}
		else return true;
	}
	else return false;
}


vector<P> g[MAX_N][4];
vector<P> rg[MAX_N][4];

int dist[MAX_N][4];
int rdist[MAX_N][4];
template<typename dir> 
inline void addArc(const int i, const int j, const int r,const int c) {
	const int id = dir::getIce(r, c);
	if (id != -1) {
		g[i][j].push_back(P{ id,3 - dir::index });
		rg[id][3 - dir::index].push_back(P{ i,j });
	}
}
void buildGraph(){
	for (int i : range(N)) {
		for (int d : range(4)) {
			int r = in[i].r + dr[d];
			int c = in[i].c + dc[d];
			if (pts::isIce(r, c))continue;
			addArc<Down>(i, d, r, c);
			addArc<Up>(i, d, r, c);
			addArc<Left>(i, d, r, c);
			addArc<Right>(i, d, r, c);
		}
	}
}
template<typename dir>
void uku(){
	int id = dir::getIce(S.r, S.c);
	if (id != -1) {
		const int r = in[id].r + dr[3 - dir::index];
		const int c = in[id].c + dc[3 - dir::index];
		dist[id][3 - dir::index] = (S.r != r || S.c != c);
	}
}

constexpr int INF = 1e7;
queue<P> que;
void bfs() {
	uku<Down>();
	uku<Left>();
	uku<Right>();
	uku<Up>();
	for (int i : range(N)) {
		for (int d : range(4)) {
			if (dist[i][d] == 0)que.push(P{ i,d });
		}
	}
	for (int i : range(N)) {
		for (int d : range(4)) {
			if (dist[i][d] == 1)que.push(P{ i,d });
		}
	}
	while (!que.empty()) {
		int i = que.front().r;
		int j = que.front().c;
		que.pop();
		for (auto &it : g[i][j]) {
			int ni = it.r;
			int nj = it.c;
			if (chmin(dist[ni][nj], dist[i][j] + 1)) {
				que.push(it);
			}
		}
	}
	for (int i : range(N)) {
		for (int d : range(4)) {
			const int r = in[i].r + dr[d];
			const int c = in[i].c + dc[d];
			if (isReachable(r, c, T.r, T.c)) {
				rdist[i][d] = 0;
				que.push(P{ i,d });
			}
		}
	}
	while (!que.empty()) {
		int i = que.front().r;
		int j = que.front().c;
		que.pop();
		for (auto &it : rg[i][j]) {
			int ni = it.r;
			int nj = it.c;
			if (chmin(rdist[ni][nj], rdist[i][j] + 1)) {
				que.push(it);
			}
		}
	}
}

template<typename SEG> using SetInitialLeaf = function<void(SEG&, int)>;
template<typename SEG> using SetInitialSegment = function<void(SEG&, const int, const int)>;
template<typename RET, typename SEG> using GetSingleSegment = function<RET(SEG&, const int, const int)>;
template<typename RET> using GetMergedSegment = function<RET(RET, RET)>;
template<typename SEG, typename Q> using UpdateSingleSegment = function<void(SEG&, Q)>;

struct node { int ret; };

SetInitialLeaf<node>
set_leaf = [](node &v, const int id) {
	v.ret = INF;
};

SetInitialSegment<node>
set_segment = [](node &v, const int l, const int r) {};

GetSingleSegment<int, node>
segment_min = [](node &v, const int l, const int r) {
	return v.ret;
};

GetMergedSegment<int>
merge_segment = [](int l, int r) {
	return l < r ? l : r;
};

UpdateSingleSegment<node, int>
force_update = [](node &v, int l) {
	v.ret = l;
};

UpdateSingleSegment<node, int>
weak_update = [](node &v, int l) {
	if (v.ret > l)v.ret = l;
};

template<typename T>
struct BufferManager {
	T *mem;
	int ptr;
	BufferManager(T* mem) {
		ptr = 0;
		this->mem = mem;
	}
	T* get(int m) {
		ptr += m;
		return mem + ptr - m;
	}
	void reset() {
		ptr = 0;
	}
};

namespace NodeBuffer {
	constexpr int BufferSize = 812345;
	using NodeType = node;
	NodeType mem[BufferSize];
	BufferManager<NodeType> buffer(mem);
}

template<typename Node, typename RET>
struct SegmentTree {
	int size;
	Node *seg;
	GetSingleSegment<RET, Node> get_single_segment;
	GetMergedSegment<RET> get_merged_segment;
	void init(int l, int r, SetInitialSegment<Node>& init_segment, SetInitialLeaf<Node>& init_leaf, int k = 0) {
		auto &v = seg[k];
		init_segment(v, l, r);
		if (r - l == 1) {
			//葉の時の処理
			init_leaf(v, l);
		}
		else if (r - l>1) {
			int m = (l + r) / 2;
			init(l, m, init_segment, init_leaf, k * 2 + 1);
			init(m, r, init_segment, init_leaf, k * 2 + 2);
			v.ret = get_merged_segment(
				get_single_segment(seg[k * 2 + 1], l, m),
				get_single_segment(seg[k * 2 + 2], m, r)
			);
		}
	}
	SegmentTree(
		int n,
		GetSingleSegment<RET, Node> gss,
		GetMergedSegment<RET> gms,
		SetInitialSegment<Node> sis,
		SetInitialLeaf<Node> sil,
		BufferManager<Node> buf = NodeBuffer::buffer
	)
		:get_single_segment(gss),
		get_merged_segment(gms) {
		size = 1; while (size<n)size *= 2;
		seg = buf.get(size + 10);
		init(0, size, sis, sil);
	}
#define LQ a,b,k*2+1,l,m
#define RQ a,b,k*2+2,m,r
	RET get(int a, int b, int k, int l, int r) {
		if (a <= l && r <= b)return get_single_segment(seg[k], l, r);
		int m = (l + r) / 2;
		bool ll = !(m <= a || b <= l);
		bool rr = !(r <= a || b <= m);
		RET ret;
		if (ll&&rr)ret = get_merged_segment(get(LQ), get(RQ));
		else if (ll)ret = get(LQ); else ret = get(RQ);
		return ret;
	}
	RET get(int a, int b) {
		return get(a, b, 0, 0, size);
	}
	template<typename Q>
	void update(int a, int b, int k, int l, int r, UpdateSingleSegment<Node, Q> &update_segment, Q value) {
		if (r <= a || b <= l)return;
		if (a <= l && r <= b) {
			update_segment(seg[k], value);
		}
		else {
			int m = (l + r) / 2;
			update(LQ, update_segment, value);
			update(RQ, update_segment, value);
			seg[k].ret = get_merged_segment(
				get_single_segment(seg[k * 2 + 1], l, m),
				get_single_segment(seg[k * 2 + 2], m, r)
			);
		}
	}
	template<typename Q>
	void update_segment(int a, int b, UpdateSingleSegment<Node, Q> &update_segment, Q value) {
		update(a, b, 0, 0, size, update_segment, value);
	}

	template<typename Q>
	void update_element(int a, UpdateSingleSegment<Node, Q> &update_segment, Q value) {
		update(a, a + 1, 0, 0, size, update_segment, value);
	}
};

int ret = INF;
void solve_down() {
	constexpr int dir = Down::index;
	constexpr int s = Left::index;
	SegmentTree<node, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = 0; lb < N;) {
		int ub = lb;
		int* pt = pts::pt[Tate::index];
		while (ub < N&&
			in[pt[lb]].r == in[pt[ub]].r) {
			ub++;
		}
		chmin(ret, rdist[pt[lb]][s] + query(0, in[pt[lb]].c) + 1);
		for (int i : range(lb, ub-1)) {
			const int seg_cost = query(in[pt[i]].c + 1, in[pt[i + 1]].c);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[ub - 1]][3 - s] + query(in[pt[ub - 1]].c + 1, Z::id) + 1);
		for (int i : range(lb, ub)) {
			rmq.update_element(in[pt[i]].c, force_update, dist[pt[i]][dir]);
			rmq.update_element(in[pt[i]].c + dc[s], weak_update, dist[pt[i]][s]);
			rmq.update_element(in[pt[i]].c + dc[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}

void solve_right() {
	constexpr int dir = Right::index;
	constexpr int s = Up::index;
	SegmentTree<node, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = 0; lb < N;) {
		int ub = lb;
		int* pt = pts::pt[Yoko::index];
		while (ub < N&&
			in[pt[lb]].c == in[pt[ub]].c) {
			ub++;
		}
		chmin(ret, rdist[pt[lb]][s] + query(0, in[pt[lb]].r) + 1);
		for (int i : range(lb, ub - 1)) {
			const int seg_cost = query(in[pt[i]].r + 1, in[pt[i + 1]].r);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[ub - 1]][3 - s] + query(in[pt[ub - 1]].r + 1, Z::id) + 1);
		for (int i : range(lb, ub)) {
			rmq.update_element(in[pt[i]].r, force_update, dist[pt[i]][dir]);
			rmq.update_element(in[pt[i]].r + dr[s], weak_update, dist[pt[i]][s]);
			rmq.update_element(in[pt[i]].r + dr[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}

void solve_up() {
	constexpr int dir = Up::index;
	constexpr int s = Left::index;
	SegmentTree<node, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = N-1; lb >= 0;) {
		int ub = lb;
		int* pt = pts::pt[Tate::index];
		while (ub >=0 &&
			in[pt[lb]].r == in[pt[ub]].r) {
			ub--;
		}
		chmin(ret, rdist[pt[ub+1]][s] + query(0, in[pt[ub+1]].c) + 1);
		for (int i : range(ub+1, lb)) {
			const int seg_cost = query(in[pt[i]].c + 1, in[pt[i + 1]].c);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[lb]][3 - s] + query(in[pt[lb]].c + 1, Z::id) + 1);
		for (int i : range(ub+1, lb+1)) {
			rmq.update_element(in[pt[i]].c, force_update, dist[pt[i]][dir]);
			rmq.update_element(in[pt[i]].c + dc[s], weak_update, dist[pt[i]][s]);
			rmq.update_element(in[pt[i]].c + dc[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}

void solve_left() {
	constexpr int dir = Left::index;
	constexpr int s = Up::index;
	SegmentTree<node, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = N-1; lb >= 0;) {
		int ub = lb;
		int* pt = pts::pt[Yoko::index];
		while (ub >=0&&
			in[pt[lb]].c == in[pt[ub]].c) {
			ub--;
		}
		chmin(ret, rdist[pt[ub+1]][s] + query(0, in[pt[ub+1]].r) + 1);
		for (int i : range(ub+1, lb)) {
			const int seg_cost = query(in[pt[i]].r + 1, in[pt[i + 1]].r);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[lb]][3 - s] + query(in[pt[lb]].r + 1, Z::id) + 1);
		for (int i : range(ub+1, lb+1)) {
			rmq.update_element(in[pt[i]].r, force_update, dist[pt[i]][dir]);
			rmq.update_element(in[pt[i]].r + dr[s], weak_update, dist[pt[i]][s]);
			rmq.update_element(in[pt[i]].r + dr[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}
inline bool isReachableWithHop(int r,int c) {
	return (isReachable(r, c, r, T.c) &&
		isReachable(r, T.c, T.r, T.c)) ||
		(isReachable(r, c, T.r, c) &&
			isReachable(T.r, c, T.r, T.c));
}

int main() {
	while (input()) {
		pts::build();
		if (isReachableWithHop(S.r, S.c)) {
			cout << 0 << endl; continue;
		}
		for (int i : range(N)) {
			for (int j : range(4)) {
				g[i][j].clear();
				rg[i][j].clear();
				dist[i][j] = INF;
				rdist[i][j] = INF;
			}
		}
		buildGraph();
		bfs();
		
		for (int i : range(N)) {
			for (int j : range(4)) {
				const int r = in[i].r + dr[j];
				const int c = in[i].c + dc[j];
				if (isReachableWithHop(r, c)) {
					chmin(ret, dist[i][j]);
					isReachableWithHop(r, c);
				}
			}
		}

		for (int i : range(N)) {
			if (isReachable(S.r,S.c,S.r,in[i].c)) {
				const int r = S.r;
				const int c = in[i].c;
				if (Down::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Down::index] + 1);
				if (Left::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Left::index] + 1);

				if (Right::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Right::index] + 1);
				if (Up::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Up::index] + 1);
			}
			if (isReachable(S.r, S.c, in[i].r, S.c)) {
				const int r = in[i].r;
				const int c = S.c;
				if (Down::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Down::index] + 1);
				if (Left::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Left::index] + 1);
				if (Right::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Right::index] + 1);
				if (Up::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Up::index] + 1);
			}
		}
		solve_down();
		solve_up(); 
		solve_left();
		solve_right();
		if (ret == INF)cout << -1 << endl;
		else cout << ret << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 870
memory_kb: 201264
final_rank: 3

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

using namespace std;
typedef long long LL;

#ifdef BTK
#define DEBUG if(1)
#else
#define CIN_ONLY if(1)
struct cww {cww() {CIN_ONLY{ios::sync_with_stdio(false); cin.tie(0);}}
}star;
#define DEBUG if(0)
#endif

#define ALL(v) (v).begin(),(v).end()
#define REC(ret, ...) std::function<ret (__VA_ARGS__)>
template <typename T>inline bool chmin(T &l, T r){bool a = l>r; if (a)l = r; return a;}
template <typename T>inline bool chmax(T &l, T r){bool a = l<r; if (a)l = r; return a;}
template <typename T>istream& operator>>(istream &is, vector<T> &v){for (auto &it : v)is >> it;return is;}

class range {private: struct I { int x; int operator*() { return x; }bool operator!=(I& lhs) { return x<lhs.x; }void operator++() { ++x; } }; I i, n;public:range(int n) :i({ 0 }), n({ n }) {}range(int i, int n) :i({ i }), n({ n }) {}I& begin() { return i; }I& end() { return n; }};

constexpr int MAX_N = 812345;
struct P{
	int r, c;
};
istream& operator>>(istream &is, P &v) { is >> v.r >> v.c; return is; }

P S, T;
int N;
P in[MAX_N];
namespace Z{
	int latte[MAX_N];
	int id;
	void init() {
		id = 0;
	}
	inline void set(int v) {
		latte[id++] = v;
	}
	inline void build() {
		sort(latte, latte + id);
		id = unique(latte, latte + id) - latte;
	}
	inline int ItoZ(int v) {
		return lower_bound(latte, latte + id, v) - latte;
	}
	inline int ZtoI(int v) {
		return latte[v];
	}
}

bool input() {
	if(cin >> S >> T);
	else return false;
	cin >> N;
	Z::init();
	for (int j : {-1, 0, 1}) {
		Z::set(S.r + j);
		Z::set(S.c + j);
		Z::set(T.r + j);
		Z::set(T.c + j);
	}
	for (int i : range(N)) {
		cin >> in[i];
		for (int j : {-1, 0, 1}) {
			Z::set(in[i].r + j);
			Z::set(in[i].c + j);
		}
	}
	Z::build();
	S.r = Z::ItoZ(S.r);	S.c = Z::ItoZ(S.c);
	T.r = Z::ItoZ(T.r);	T.c = Z::ItoZ(T.c);
	for (int i : range(N)) {
		in[i].r = Z::ItoZ(in[i].r);
		in[i].c = Z::ItoZ(in[i].c);
	}
#ifdef BTK
	cout << S.r << " " << S.c << endl;
	cout << T.r << " " << T.c << endl;
	cout << N << endl;
	for (int i : range(N)) {
		cout << in[i].r << " " << in[i].c << endl;
	}
#endif
	return true;
}
typedef vector<int> V;
typedef vector<V> VV;
typedef vector<VV> VVV;
constexpr int dr[4] = { 1,0,0,-1 };
constexpr int dc[4] = { 0,1,-1,0 };
const string ds = { "DRLU" };
struct Tate {
	static constexpr int index = 0;
	static inline bool comp(const int lr, const int lc, const int rr, const int rc) {
		return lr == rr ? lc < rc : lr < rr;
	}
};
struct Yoko {
	static constexpr int index = 1;
	static inline bool comp(const int lr, const int lc, const int rr, const int rc) {
		return lc == rc ? lr < rr : lc < rc;
	}
};

namespace pts {
	int pt[2][MAX_N];
	int cr[MAX_N];
	template<typename dir>
	inline bool ice_comp(const int li, const int ri) {
		return dir::comp(in[li].r, in[li].c, in[ri].r, in[ri].c);
	}
	void build() {
		iota(pt[Yoko::index], pt[Yoko::index] + N, 0);
		iota(pt[Tate::index], pt[Tate::index] + N, 0);
		sort(pt[Yoko::index], pt[Yoko::index] + N, ice_comp<Yoko>);
		sort(pt[Tate::index], pt[Tate::index] + N, ice_comp<Tate>);
	}
	template<typename dir>
	inline int lower_bound(int r, int c) {
		int lb = -1, ub = N;
		while (ub - lb > 1) {
			const int mid = (lb + ub) / 2;
			(!dir::comp(r, c, in[pt[dir::index][mid]].r, in[pt[dir::index][mid]].c) ? lb : ub) = mid;
		}
		return ub;
	}
	inline bool isIce(int r, int c) {
		int id = lower_bound<Yoko>(r, c);
		return id != N && in[pt[Yoko::index][id]].r == r && in[pt[Yoko::index][id]].c == c;
	}
}

struct Down {
	static constexpr int index = 0;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Yoko>(r, c);
		if (id != N && in[pts::pt[Yoko::index][id]].c == c)
			return pts::pt[Yoko::index][id];
		else return -1;
	}
};

struct Right {
	static constexpr int index = 1;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Tate>(r, c);
		if (id != N && in[pts::pt[Tate::index][id]].r == r)
			return pts::pt[Tate::index][id];
		else return -1;
	}
};
struct Left {
	static constexpr int index = 2;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Tate>(r, c) - 1;
		if (id != -1 && in[pts::pt[Tate::index][id]].r == r)
			return pts::pt[Tate::index][id];
		else return -1;
	}
};
struct Up {
	static constexpr int index = 3;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Yoko>(r, c) - 1;
		if (id != -1 && in[pts::pt[Yoko::index][id]].c == c)
			return pts::pt[Yoko::index][id];
		else return -1;
	}
};
		
inline bool isReachable(int r,int c,int nr,int nc) {
	if (r == nr) {
		if (c < nc) {
			const int id = Right::getIce(r, c);
			return id == -1 || nc < in[id].c;
		}
		else if (nc < c) {
			const int id = Left::getIce(r, c);
			return id == -1 || in[id].c < nc;
		}
		else return true;
	}
	else if (c == nc) {
		if (r < nr) {
			const int id = Down::getIce(r, c);
			return id == -1 || nr < in[id].r;
		}
		else if (nr < r) {
			const int id = Up::getIce(r, c);
			return id == -1 || in[id].r < nr;
		}
		else return true;
	}
	else return false;
}


vector<P> g[MAX_N][4];
vector<P> rg[MAX_N][4];

int dist[MAX_N][4];
int rdist[MAX_N][4];
template<typename dir> 
inline void addArc(const int i, const int j, const int r,const int c) {
	const int id = dir::getIce(r, c);
	if (id != -1) {
		g[i][j].push_back(P{ id,3 - dir::index });
		rg[id][3 - dir::index].push_back(P{ i,j });
	}
}
void buildGraph(){
	for (int i : range(N)) {
		for (int d : range(4)) {
			int r = in[i].r + dr[d];
			int c = in[i].c + dc[d];
			if (pts::isIce(r, c))continue;
			addArc<Down>(i, d, r, c);
			addArc<Up>(i, d, r, c);
			addArc<Left>(i, d, r, c);
			addArc<Right>(i, d, r, c);
		}
	}
}
template<typename dir>
void uku(){
	int id = dir::getIce(S.r, S.c);
	if (id != -1) {
		const int r = in[id].r + dr[3 - dir::index];
		const int c = in[id].c + dc[3 - dir::index];
		dist[id][3 - dir::index] = (S.r != r || S.c != c);
	}
}

constexpr int INF = 1e7;
queue<P> que;
void bfs() {
	uku<Down>();
	uku<Left>();
	uku<Right>();
	uku<Up>();
	for (int i : range(N)) {
		for (int d : range(4)) {
			if (dist[i][d] == 0)que.push(P{ i,d });
		}
	}
	for (int i : range(N)) {
		for (int d : range(4)) {
			if (dist[i][d] == 1)que.push(P{ i,d });
		}
	}
	while (!que.empty()) {
		int i = que.front().r;
		int j = que.front().c;
		que.pop();
		for (auto &it : g[i][j]) {
			int ni = it.r;
			int nj = it.c;
			if (chmin(dist[ni][nj], dist[i][j] + 1)) {
				que.push(it);
			}
		}
	}
	for (int i : range(N)) {
		for (int d : range(4)) {
			const int r = in[i].r + dr[d];
			const int c = in[i].c + dc[d];
			if (isReachable(r, c, T.r, T.c)) {
				rdist[i][d] = 0;
				que.push(P{ i,d });
			}
		}
	}
	while (!que.empty()) {
		int i = que.front().r;
		int j = que.front().c;
		que.pop();
		for (auto &it : rg[i][j]) {
			int ni = it.r;
			int nj = it.c;
			if (chmin(rdist[ni][nj], rdist[i][j] + 1)) {
				que.push(it);
			}
		}
	}
}

template<typename SEG> using SetInitialLeaf = function<void(SEG&, int)>;
template<typename SEG> using SetInitialSegment = function<void(SEG&, const int, const int)>;
template<typename RET, typename SEG> using GetSingleSegment = function<RET(SEG&, const int, const int)>;
template<typename RET> using GetMergedSegment = function<RET(RET, RET)>;
template<typename SEG, typename Q> using UpdateSingleSegment = function<void(SEG&, Q)>;

struct node { int ret; };

SetInitialLeaf<node>
set_leaf = [](node &v, const int id) {
	v.ret = INF;
};

SetInitialSegment<node>
set_segment = [](node &v, const int l, const int r) {};

GetSingleSegment<int, node>
segment_min = [](node &v, const int l, const int r) {
	return v.ret;
};

GetMergedSegment<int>
merge_segment = [](int l, int r) {
	return l < r ? l : r;
};

UpdateSingleSegment<node, int>
force_update = [](node &v, int l) {
	v.ret = l;
};

UpdateSingleSegment<node, int>
weak_update = [](node &v, int l) {
	if (v.ret < l)v.ret = l;
};

template<typename T>
struct BufferManager {
	T *mem;
	int ptr;
	BufferManager(T* mem) {
		ptr = 0;
		this->mem = mem;
	}
	T* get(int m) {
		ptr += m;
		return mem + ptr - m;
	}
	void reset() {
		ptr = 0;
	}
};

namespace NodeBuffer {
	constexpr int BufferSize = 812345;
	using NodeType = node;
	NodeType mem[BufferSize];
	BufferManager<NodeType> buffer(mem);
}

template<typename Node, typename RET>
struct SegmentTree {
	int size;
	Node *seg;
	GetSingleSegment<RET, Node> get_single_segment;
	GetMergedSegment<RET> get_merged_segment;
	void init(int l, int r, SetInitialSegment<Node>& init_segment, SetInitialLeaf<Node>& init_leaf, int k = 0) {
		auto &v = seg[k];
		init_segment(v, l, r);
		if (r - l == 1) {
			//葉の時の処理
			init_leaf(v, l);
		}
		else if (r - l>1) {
			int m = (l + r) / 2;
			init(l, m, init_segment, init_leaf, k * 2 + 1);
			init(m, r, init_segment, init_leaf, k * 2 + 2);
			v.ret = get_merged_segment(
				get_single_segment(seg[k * 2 + 1], l, m),
				get_single_segment(seg[k * 2 + 2], m, r)
			);
		}
	}
	SegmentTree(
		int n,
		GetSingleSegment<RET, Node> gss,
		GetMergedSegment<RET> gms,
		SetInitialSegment<Node> sis,
		SetInitialLeaf<Node> sil,
		BufferManager<Node> buf = NodeBuffer::buffer
	)
		:get_single_segment(gss),
		get_merged_segment(gms) {
		size = 1; while (size<n)size *= 2;
		seg = buf.get(size + 10);
		init(0, size, sis, sil);
	}
#define LQ a,b,k*2+1,l,m
#define RQ a,b,k*2+2,m,r
	RET get(int a, int b, int k, int l, int r) {
		if (a <= l && r <= b)return get_single_segment(seg[k], l, r);
		int m = (l + r) / 2;
		bool ll = !(m <= a || b <= l);
		bool rr = !(r <= a || b <= m);
		RET ret;
		if (ll&&rr)ret = get_merged_segment(get(LQ), get(RQ));
		else if (ll)ret = get(LQ); else ret = get(RQ);
		return ret;
	}
	RET get(int a, int b) {
		return get(a, b, 0, 0, size);
	}
	template<typename Q>
	void update(int a, int b, int k, int l, int r, UpdateSingleSegment<Node, Q> &update_segment, Q value) {
		if (r <= a || b <= l)return;
		if (a <= l && r <= b) {
			update_segment(seg[k], value);
		}
		else {
			int m = (l + r) / 2;
			update(LQ, update_segment, value);
			update(RQ, update_segment, value);
			seg[k].ret = get_merged_segment(
				get_single_segment(seg[k * 2 + 1], l, m),
				get_single_segment(seg[k * 2 + 2], m, r)
			);
		}
	}
	template<typename Q>
	void update_segment(int a, int b, UpdateSingleSegment<Node, Q> &update_segment, Q value) {
		update(a, b, 0, 0, size, update_segment, value);
	}

	template<typename Q>
	void update_element(int a, UpdateSingleSegment<Node, Q> &update_segment, Q value) {
		update(a, a + 1, 0, 0, size, update_segment, value);
	}
};

int ret = INF;
void solve_down() {
	constexpr int dir = Down::index;
	constexpr int s = Left::index;
	SegmentTree<node, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = 0; lb < N;) {
		int ub = lb;
		int* pt = pts::pt[Tate::index];
		while (ub < N&&
			in[pt[lb]].r == in[pt[ub]].r) {
			ub++;
		}
		chmin(ret, rdist[pt[lb]][s] + query(0, in[pt[lb]].c) + 1);
		for (int i : range(lb, ub-1)) {
			const int seg_cost = query(in[pt[i]].c + 1, in[pt[i + 1]].c);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[ub - 1]][3 - s] + query(in[pt[ub - 1]].c + 1, Z::id) + 1);
		for (int i : range(lb, ub)) {
			rmq.update_element(in[pt[i]].c, force_update, dist[pt[i]][dir]);
			rmq.update_element(in[pt[i]].c + dc[s], weak_update, dist[pt[i]][s]);
			rmq.update_element(in[pt[i]].c + dc[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}

void solve_right() {
	constexpr int dir = Right::index;
	constexpr int s = Up::index;
	SegmentTree<node, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = 0; lb < N;) {
		int ub = lb;
		int* pt = pts::pt[Yoko::index];
		while (ub < N&&
			in[pt[lb]].c == in[pt[ub]].c) {
			ub++;
		}
		chmin(ret, rdist[pt[lb]][s] + query(0, in[pt[lb]].r) + 1);
		for (int i : range(lb, ub - 1)) {
			const int seg_cost = query(in[pt[i]].r + 1, in[pt[i + 1]].r);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[ub - 1]][3 - s] + query(in[pt[ub - 1]].r + 1, Z::id) + 1);
		for (int i : range(lb, ub)) {
			rmq.update_element(in[pt[i]].r, force_update, dist[pt[i]][dir]);
			rmq.update_element(in[pt[i]].r + dr[s], weak_update, dist[pt[i]][s]);
			rmq.update_element(in[pt[i]].r + dr[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}

void solve_up() {
	constexpr int dir = Up::index;
	constexpr int s = Left::index;
	SegmentTree<node, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = N-1; lb >= 0;) {
		int ub = lb;
		int* pt = pts::pt[Tate::index];
		while (ub >=0 &&
			in[pt[lb]].r == in[pt[ub]].r) {
			ub--;
		}
		chmin(ret, rdist[pt[ub+1]][s] + query(0, in[pt[ub+1]].c) + 1);
		for (int i : range(ub+1, lb)) {
			const int seg_cost = query(in[pt[i]].c + 1, in[pt[i + 1]].c);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[lb]][3 - s] + query(in[pt[lb]].c + 1, Z::id) + 1);
		for (int i : range(ub+1, lb+1)) {
			rmq.update_element(in[pt[i]].c, force_update, dist[pt[i]][dir]);
			rmq.update_element(in[pt[i]].c + dc[s], weak_update, dist[pt[i]][s]);
			rmq.update_element(in[pt[i]].c + dc[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}

void solve_left() {
	constexpr int dir = Left::index;
	constexpr int s = Up::index;
	SegmentTree<node, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = N-1; lb >= 0;) {
		int ub = lb;
		int* pt = pts::pt[Yoko::index];
		while (ub >=0&&
			in[pt[lb]].c == in[pt[ub]].c) {
			ub--;
		}
		chmin(ret, rdist[pt[ub+1]][s] + query(0, in[pt[ub+1]].r) + 1);
		for (int i : range(ub+1, lb)) {
			const int seg_cost = query(in[pt[i]].r + 1, in[pt[i + 1]].r);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[lb]][3 - s] + query(in[pt[lb]].r + 1, Z::id) + 1);
		for (int i : range(ub+1, lb+1)) {
			rmq.update_element(in[pt[i]].r, force_update, dist[pt[i]][dir]);
			rmq.update_element(in[pt[i]].r + dr[s], weak_update, dist[pt[i]][s]);
			rmq.update_element(in[pt[i]].r + dr[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}
inline bool isReachableWithHop(int r,int c) {
	return (isReachable(r, c, r, T.c) &&
		isReachable(r, T.c, T.r, T.c)) ||
		(isReachable(r, c, T.r, c) &&
			isReachable(T.r, c, T.r, T.c));
}

int main() {
	while (input()) {
		pts::build();
		if (isReachableWithHop(S.r, S.c)) {
			cout << 0 << endl; continue;
		}
		for (int i : range(N)) {
			for (int j : range(4)) {
				g[i][j].clear();
				rg[i][j].clear();
				dist[i][j] = INF;
				rdist[i][j] = INF;
			}
		}
		buildGraph();
		bfs();
		
		for (int i : range(N)) {
			for (int j : range(4)) {
				const int r = in[i].r + dr[j];
				const int c = in[i].c + dc[j];
				if (isReachableWithHop(r, c)) {
					chmin(ret, dist[i][j]);
					isReachableWithHop(r, c);
				}
			}
		}

		for (int i : range(N)) {
			if (isReachable(S.r,S.c,S.r,in[i].c)) {
				const int r = S.r;
				const int c = in[i].c;
				if (Down::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Down::index] + 1);
				if (Left::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Left::index] + 1);

				if (Right::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Right::index] + 1);
				if (Up::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Up::index] + 1);
			}
			if (isReachable(S.r, S.c, in[i].r, S.c)) {
				const int r = in[i].r;
				const int c = S.c;
				if (Down::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Down::index] + 1);
				if (Left::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Left::index] + 1);
				if (Right::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Right::index] + 1);
				if (Up::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Up::index] + 1);
			}
		}
		solve_down();
		solve_up(); 
		solve_left();
		solve_right();
		if (ret == INF)cout << -1 << endl;
		else cout << ret << endl;
	}
	return 0;
}
accuracy: 0.175
time_ms: 50
memory_kb: 155548
final_rank: 17

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

using namespace std;
typedef long long LL;

#ifdef BTK
#define DEBUG if(1)
#else
#define CIN_ONLY if(1)
struct cww {cww() {CIN_ONLY{ios::sync_with_stdio(false); cin.tie(0);}}
}star;
#define DEBUG if(0)
#endif

#define ALL(v) (v).begin(),(v).end()
#define REC(ret, ...) std::function<ret (__VA_ARGS__)>
template <typename T>inline bool chmin(T &l, T r){bool a = l>r; if (a)l = r; return a;}
template <typename T>inline bool chmax(T &l, T r){bool a = l<r; if (a)l = r; return a;}
template <typename T>istream& operator>>(istream &is, vector<T> &v){for (auto &it : v)is >> it;return is;}

class range {private: struct I { int x; int operator*() { return x; }bool operator!=(I& lhs) { return x<lhs.x; }void operator++() { ++x; } }; I i, n;public:range(int n) :i({ 0 }), n({ n }) {}range(int i, int n) :i({ i }), n({ n }) {}I& begin() { return i; }I& end() { return n; }};

constexpr int MAX_N = 812345;
struct P{
	int r, c;
};
istream& operator>>(istream &is, P &v) { is >> v.r >> v.c; return is; }

P S, T;
int N;
P in[MAX_N];
namespace Z{
	int latte[MAX_N];
	int id;
	void init() {
		id = 0;
	}
	inline void set(int v) {
		latte[id++] = v;
	}
	inline void build() {
		sort(latte, latte + id);
		id = unique(latte, latte + id) - latte;
	}
	inline int ItoZ(int v) {
		return lower_bound(latte, latte + id, v) - latte;
	}
	inline int ZtoI(int v) {
		return latte[v];
	}
}

bool input() {
	if(cin >> S >> T);
	else return false;
	cin >> N;
	Z::init();
	for (int j : {-1, 0, 1}) {
		Z::set(S.r + j);
		Z::set(S.c + j);
		Z::set(T.r + j);
		Z::set(T.c + j);
	}
	for (int i : range(N)) {
		cin >> in[i];
		for (int j : {-1, 0, 1}) {
			Z::set(in[i].r + j);
			Z::set(in[i].c + j);
		}
	}
	Z::build();
	S.r = Z::ItoZ(S.r);	S.c = Z::ItoZ(S.c);
	T.r = Z::ItoZ(T.r);	T.c = Z::ItoZ(T.c);
	for (int i : range(N)) {
		in[i].r = Z::ItoZ(in[i].r);
		in[i].c = Z::ItoZ(in[i].c);
	}
#ifdef BTK
	cout << S.r << " " << S.c << endl;
	cout << T.r << " " << T.c << endl;
	cout << N << endl;
	for (int i : range(N)) {
		cout << in[i].r << " " << in[i].c << endl;
	}
#endif
	return true;
}
typedef vector<int> V;
typedef vector<V> VV;
typedef vector<VV> VVV;
constexpr int dr[4] = { 1,0,0,-1 };
constexpr int dc[4] = { 0,1,-1,0 };
const string ds = { "DRLU" };
struct Tate {
	static constexpr int index = 0;
	static inline bool comp(const int lr, const int lc, const int rr, const int rc) {
		return lr == rr ? lc < rc : lr < rr;
	}
};
struct Yoko {
	static constexpr int index = 1;
	static inline bool comp(const int lr, const int lc, const int rr, const int rc) {
		return lc == rc ? lr < rr : lc < rc;
	}
};

namespace pts {
	int pt[2][MAX_N];
	int cr[MAX_N];
	template<typename dir>
	inline bool ice_comp(const int li, const int ri) {
		return dir::comp(in[li].r, in[li].c, in[ri].r, in[ri].c);
	}
	void build() {
		iota(pt[Yoko::index], pt[Yoko::index] + N, 0);
		iota(pt[Tate::index], pt[Tate::index] + N, 0);
		sort(pt[Yoko::index], pt[Yoko::index] + N, ice_comp<Yoko>);
		sort(pt[Tate::index], pt[Tate::index] + N, ice_comp<Tate>);
	}
	template<typename dir>
	inline int lower_bound(int r, int c) {
		int lb = -1, ub = N;
		while (ub - lb > 1) {
			const int mid = (lb + ub) / 2;
			(!dir::comp(r, c, in[pt[dir::index][mid]].r, in[pt[dir::index][mid]].c) ? lb : ub) = mid;
		}
		return ub;
	}
	inline bool isIce(int r, int c) {
		int id = lower_bound<Yoko>(r, c);
		return id != N && in[pt[Yoko::index][id]].r == r && in[pt[Yoko::index][id]].c == c;
	}
}

struct Down {
	static constexpr int index = 0;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Yoko>(r, c);
		if (id != N && in[pts::pt[Yoko::index][id]].c == c)
			return pts::pt[Yoko::index][id];
		else return -1;
	}
};

struct Right {
	static constexpr int index = 1;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Tate>(r, c);
		if (id != N && in[pts::pt[Tate::index][id]].r == r)
			return pts::pt[Tate::index][id];
		else return -1;
	}
};
struct Left {
	static constexpr int index = 2;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Tate>(r, c) - 1;
		if (id != -1 && in[pts::pt[Tate::index][id]].r == r)
			return pts::pt[Tate::index][id];
		else return -1;
	}
};
struct Up {
	static constexpr int index = 3;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Yoko>(r, c) - 1;
		if (id != -1 && in[pts::pt[Yoko::index][id]].c == c)
			return pts::pt[Yoko::index][id];
		else return -1;
	}
};
		
inline bool isReachable(int r,int c,int nr,int nc) {
	if (r == nr) {
		if (c < nc) {
			const int id = Right::getIce(r, c);
			return id == -1 || nc < in[id].c;
		}
		else if (nc < c) {
			const int id = Left::getIce(r, c);
			return id == -1 || in[id].c < nc;
		}
		else return true;
	}
	else if (c == nc) {
		if (r < nr) {
			const int id = Down::getIce(r, c);
			return id == -1 || nr < in[id].r;
		}
		else if (nr < r) {
			const int id = Up::getIce(r, c);
			return id == -1 || in[id].r < nr;
		}
		else return true;
	}
	else return false;
}


vector<P> g[MAX_N][4];
vector<P> rg[MAX_N][4];

int dist[MAX_N][4];
int rdist[MAX_N][4];
template<typename dir> 
inline void addArc(const int i, const int j, const int r,const int c) {
	const int id = dir::getIce(r, c);
	if (id != -1) {
		g[i][j].push_back(P{ id,3 - dir::index });
		rg[id][3 - dir::index].push_back(P{ i,j });
	}
}
void buildGraph(){
	for (int i : range(N)) {
		for (int d : range(4)) {
			int r = in[i].r + dr[d];
			int c = in[i].c + dc[d];
			if (pts::isIce(r, c))continue;
			addArc<Down>(i, d, r, c);
			addArc<Up>(i, d, r, c);
			addArc<Left>(i, d, r, c);
			addArc<Right>(i, d, r, c);
		}
	}
}
template<typename dir>
void uku(){
	int id = dir::getIce(S.r, S.c);
	if (id != -1) {
		const int r = in[id].r + dr[3 - dir::index];
		const int c = in[id].c + dc[3 - dir::index];
		dist[id][3 - dir::index] = (S.r != r || S.c != c);
	}
}
constexpr int INF = 1e7;
queue<P> que;
void bfs() {
	uku<Down>();
	uku<Left>();
	uku<Right>();
	uku<Up>();
	for (int i : range(N)) {
		for (int d : range(4)) {
			if (dist[i][d] == 0)que.push(P{ i,d });
		}
	}
	for (int i : range(N)) {
		for (int d : range(4)) {
			if (dist[i][d] == 1)que.push(P{ i,d });
		}
	}
	while (!que.empty()) {
		int i = que.front().r;
		int j = que.front().c;
		que.pop();
		for (auto &it : g[i][j]) {
			int ni = it.r;
			int nj = it.c;
			if (chmin(dist[ni][nj], dist[i][j] + 1)) {
				que.push(it);
			}
		}
	}
	for (int i : range(N)) {
		for (int d : range(4)) {
			const int r = in[i].r + dr[d];
			const int c = in[i].c + dc[d];
			if (isReachable(r, c, T.r, T.c)) {
				rdist[i][d] = 0;
				que.push(P{ i,d });
			}
		}
	}
	while (!que.empty()) {
		int i = que.front().r;
		int j = que.front().c;
		que.pop();
		for (auto &it : rg[i][j]) {
			int ni = it.r;
			int nj = it.c;
			if (chmin(rdist[ni][nj], rdist[i][j] + 1)) {
				que.push(it);
			}
		}
	}
}

//default::min
template<typename SEG>
using SetInitialLeaf = function<void(SEG&, int)>;

template<typename SEG>
using SetInitialSegment = function<void(SEG&, const int, const int)>;

template<typename RET, typename SEG>
using GetSingleSegment = function<RET(SEG&, const int, const int)>;

template<typename RET>
using GetMergedSegment = function<RET(RET, RET)>;

template<typename SEG, typename Q>
using UpdateSingleSegment = function<void(SEG&, Q)>;

SetInitialLeaf<int>
set_leaf = [](int &v, const int id) {
	v = INF;
};

SetInitialSegment<int>
set_segment = [](int &v, const int l, const int r) {};

GetSingleSegment<int,int> 
segment_min = [](int &v, const int l, const int r) {
	return v;
};

GetMergedSegment<int>
merge_segment = [](const int l, const int r) {
	return l < r ? l : r;
};

UpdateSingleSegment<int,int>
force_update = [](int &v, int l) {
	v = l;
};

UpdateSingleSegment<int, int>
weak_update = [](int &v, int l) {
	chmin(v, l);
};


template<typename T>
struct BufferManager {
	T *mem;
	int ptr;
	BufferManager(T* mem) {
		ptr = 0;
		this->mem = mem;
	}
	T* get(int m) {
		ptr += m;
		return mem + ptr - m;
	}
	void reset() {
		ptr = 0;
	}
};

namespace NodeBuffer {
	constexpr int BufferSize = 812345;
	using NodeType = int;
	NodeType mem[BufferSize];
	BufferManager<NodeType> buffer(mem);
}

template<typename Node, typename RET>
struct SegmentTree{
	int size;
	Node *seg;
	GetSingleSegment<RET, Node> get_single_segment;
	GetMergedSegment<RET> get_merged_segment;
	void init(int l, int r, SetInitialSegment<Node>& init_segment ,SetInitialLeaf<Node>& init_leaf ,int k = 0) {
		auto &v = seg[k];
		init_segment(v, l, r);
		if (r - l == 1) {
			//葉の時の処理
			init_leaf(v, l);
		}
		else if (r - l>1) {
			int m = (l + r) / 2;
			init(l, m, init_segment, init_leaf, k * 2 + 1); 
			init(m, r, init_segment, init_leaf, k * 2 + 2);
			v = get_merged_segment(
				get_single_segment(seg[k * 2 + 1], l, m),
				get_single_segment(seg[k * 2 + 2], m, r)
			);
		}
	}
	SegmentTree(
		int n,
		GetSingleSegment<RET, Node> gss,
		GetMergedSegment<RET> gms,
		SetInitialSegment<Node> sis,
		SetInitialLeaf<Node> sil,
		BufferManager<Node> buf = NodeBuffer::buffer
		) 
		:get_single_segment(gss),
		 get_merged_segment(gms){
		size = 1; while (size<n)size *= 2;
		seg = buf.get(size + 10);
		init(0, size, sis, sil);
	}
#define LQ a,b,k*2+1,l,m
#define RQ a,b,k*2+2,m,r
	RET get(int a, int b, int k, int l, int r) {
		if (a <= l && r <= b)return get_single_segment(seg[k], l, r);
		int m = (l + r) / 2;
		bool ll = !(m <= a || b <= l);
		bool rr = !(r <= a || b <= m);
		RET ret;
		if (ll&&rr)ret = get_merged_segment(get(LQ), get(RQ));
		else if (ll)ret = get(LQ); else ret = get(RQ);
		return ret;
	}
	RET get(int a, int b) { 
		return get(a, b, 0, 0, size);
	}
	template<typename Q>
	void update(int a, int b, int k, int l, int r, UpdateSingleSegment<Node,Q> &update_segment, Q value) {
		if (r <= a || b <= l)return;
		if (a <= l && r <= b) {
			update_segment(seg[k], value);
		}
		else {
			int m = (l + r) / 2;
			update(LQ, update_segment, value);
			update(RQ, update_segment, value);
			seg[k] = get_merged_segment(
				get_single_segment(seg[k * 2 + 1], l, m), 
				get_single_segment(seg[k * 2 + 2], m, r)
			);
		}
	}
	template<typename Q>
	void update(int a, UpdateSingleSegment<Node, Q> &update_segment, Q value) {
		update(a, a+1, 0, 0, size, update_segment, value);
	}
};

int ret = INF;
void solve_down() {
	constexpr int dir = Down::index;
	constexpr int s = Left::index;
	SegmentTree<int, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = 0; lb < N;) {
		int ub = lb;
		int* pt = pts::pt[Tate::index];
		while (ub < N&&
			in[pt[lb]].r == in[pt[ub]].r) {
			ub++;
		}
		chmin(ret, rdist[pt[lb]][s] + query(0, in[pt[lb]].c) + 1);
		for (int i : range(lb, ub-1)) {
			const int seg_cost = query(in[pt[i]].c + 1, in[pt[i + 1]].c);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[ub - 1]][3 - s] + query(in[pt[ub - 1]].c + 1, Z::id) + 1);
		for (int i : range(lb, ub)) {
			rmq.update(in[pt[i]].c, force_update, dist[pt[i]][dir]);
			rmq.update(in[pt[i]].c + dc[s], weak_update, dist[pt[i]][s]);
			rmq.update(in[pt[i]].c + dc[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}

void solve_right() {
	constexpr int dir = Right::index;
	constexpr int s = Up::index;
	SegmentTree<int, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = 0; lb < N;) {
		int ub = lb;
		int* pt = pts::pt[Yoko::index];
		while (ub < N&&
			in[pt[lb]].c == in[pt[ub]].c) {
			ub++;
		}
		chmin(ret, rdist[pt[lb]][s] + query(0, in[pt[lb]].r) + 1);
		for (int i : range(lb, ub - 1)) {
			const int seg_cost = query(in[pt[i]].r + 1, in[pt[i + 1]].r);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[ub - 1]][3 - s] + query(in[pt[ub - 1]].r + 1, Z::id) + 1);
		for (int i : range(lb, ub)) {
			rmq.update(in[pt[i]].r, force_update, dist[pt[i]][dir]);
			rmq.update(in[pt[i]].r + dr[s], weak_update, dist[pt[i]][s]);
			rmq.update(in[pt[i]].r + dr[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}

void solve_up() {
	constexpr int dir = Up::index;
	constexpr int s = Left::index;
	SegmentTree<int, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = N-1; lb >= 0;) {
		int ub = lb;
		int* pt = pts::pt[Tate::index];
		while (ub >=0 &&
			in[pt[lb]].r == in[pt[ub]].r) {
			ub--;
		}
		chmin(ret, rdist[pt[ub+1]][s] + query(0, in[pt[ub+1]].c) + 1);
		for (int i : range(ub+1, lb)) {
			const int seg_cost = query(in[pt[i]].c + 1, in[pt[i + 1]].c);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[lb]][3 - s] + query(in[pt[lb]].c + 1, Z::id) + 1);
		for (int i : range(ub+1, lb+1)) {
			rmq.update(in[pt[i]].c, force_update, dist[pt[i]][dir]);
			rmq.update(in[pt[i]].c + dc[s], weak_update, dist[pt[i]][s]);
			rmq.update(in[pt[i]].c + dc[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}

void solve_left() {
	constexpr int dir = Left::index;
	constexpr int s = Up::index;
	SegmentTree<int, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = N-1; lb >= 0;) {
		int ub = lb;
		int* pt = pts::pt[Yoko::index];
		while (ub >=0&&
			in[pt[lb]].c == in[pt[ub]].c) {
			ub--;
		}
		chmin(ret, rdist[pt[ub+1]][s] + query(0, in[pt[ub+1]].r) + 1);
		for (int i : range(ub+1, lb)) {
			const int seg_cost = query(in[pt[i]].r + 1, in[pt[i + 1]].r);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[lb]][3 - s] + query(in[pt[lb]].r + 1, Z::id) + 1);
		for (int i : range(ub+1, lb+1)) {
			rmq.update(in[pt[i]].r, force_update, dist[pt[i]][dir]);
			rmq.update(in[pt[i]].r + dr[s], weak_update, dist[pt[i]][s]);
			rmq.update(in[pt[i]].r + dr[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}
inline bool isReachableWithHop(int r,int c) {
	return (isReachable(r, c, r, T.c) &&
		isReachable(r, T.c, T.r, T.c)) ||
		(isReachable(r, c, T.r, c) &&
			isReachable(T.r, c, T.r, T.c));
}

int main() {
	while (input()) {
		pts::build();
		if (isReachableWithHop(S.r, S.c)) {
			cout << 0 << endl; continue;
		}
		for (int i : range(N)) {
			for (int j : range(4)) {
				g[i][j].clear();
				rg[i][j].clear();
				dist[i][j] = INF;
				rdist[i][j] = INF;
			}
		}
		buildGraph();
		bfs();
		
		for (int i : range(N)) {
			for (int j : range(4)) {
				const int r = in[i].r + dr[j];
				const int c = in[i].c + dc[j];
				if (isReachableWithHop(r, c)) {
					chmin(ret, dist[i][j]);
					isReachableWithHop(r, c);
				}
			}
		}

		for (int i : range(N)) {
			if (isReachable(S.r,S.c,S.r,in[i].c)) {
				const int r = S.r;
				const int c = in[i].c;
				if (Down::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Down::index] + 1);
				if (Left::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Left::index] + 1);

				if (Right::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Right::index] + 1);
				if (Up::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Up::index] + 1);
			}
			if (isReachable(S.r, S.c, in[i].r, S.c)) {
				const int r = in[i].r;
				const int c = S.c;
				if (Down::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Down::index] + 1);
				if (Left::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Left::index] + 1);
				if (Right::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Right::index] + 1);
				if (Up::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Up::index] + 1);
			}
		}
		solve_down();
		solve_up(); 
		solve_left();
		solve_right();
		if (ret == INF)cout << -1 << endl;
		else cout << ret << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 880
memory_kb: 201184
final_rank: 4

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

using namespace std;
typedef long long LL;

#ifdef BTK
#define DEBUG if(1)
#else
#define CIN_ONLY if(1)
struct cww {cww() {CIN_ONLY{ios::sync_with_stdio(false); cin.tie(0);}}
}star;
#define DEBUG if(0)
#endif

#define ALL(v) (v).begin(),(v).end()
#define REC(ret, ...) std::function<ret (__VA_ARGS__)>
template <typename T>inline bool chmin(T &l, T r){bool a = l>r; if (a)l = r; return a;}
template <typename T>inline bool chmax(T &l, T r){bool a = l<r; if (a)l = r; return a;}
template <typename T>istream& operator>>(istream &is, vector<T> &v){for (auto &it : v)is >> it;return is;}

class range {private: struct I { int x; int operator*() { return x; }bool operator!=(I& lhs) { return x<lhs.x; }void operator++() { ++x; } }; I i, n;public:range(int n) :i({ 0 }), n({ n }) {}range(int i, int n) :i({ i }), n({ n }) {}I& begin() { return i; }I& end() { return n; }};

constexpr int MAX_N = 812345;
struct P{
	int r, c;
};
istream& operator>>(istream &is, P &v) { is >> v.r >> v.c; return is; }

P S, T;
int N;
P in[MAX_N];
namespace Z{
	int latte[MAX_N];
	int id;
	void init() {
		id = 0;
	}
	inline void set(int v) {
		latte[id++] = v;
	}
	inline void build() {
		sort(latte, latte + id);
		id = unique(latte, latte + id) - latte;
	}
	inline int ItoZ(int v) {
		return lower_bound(latte, latte + id, v) - latte;
	}
	inline int ZtoI(int v) {
		return latte[v];
	}
}

bool input() {
	if(cin >> S >> T);
	else return false;
	cin >> N;
	Z::init();
	for (int j : {-1, 0, 1}) {
		Z::set(S.r + j);
		Z::set(S.c + j);
		Z::set(T.r + j);
		Z::set(T.c + j);
	}
	for (int i : range(N)) {
		cin >> in[i];
		for (int j : {-1, 0, 1}) {
			Z::set(in[i].r + j);
			Z::set(in[i].c + j);
		}
	}
	Z::build();
	S.r = Z::ItoZ(S.r);	S.c = Z::ItoZ(S.c);
	T.r = Z::ItoZ(T.r);	T.c = Z::ItoZ(T.c);
	for (int i : range(N)) {
		in[i].r = Z::ItoZ(in[i].r);
		in[i].c = Z::ItoZ(in[i].c);
	}
#ifdef BTK
	cout << S.r << " " << S.c << endl;
	cout << T.r << " " << T.c << endl;
	cout << N << endl;
	for (int i : range(N)) {
		cout << in[i].r << " " << in[i].c << endl;
	}
#endif
	return true;
}
typedef vector<int> V;
typedef vector<V> VV;
typedef vector<VV> VVV;
constexpr int dr[4] = { 1,0,0,-1 };
constexpr int dc[4] = { 0,1,-1,0 };
const string ds = { "DRLU" };
struct Tate {
	static constexpr int index = 0;
	static inline bool comp(const int lr, const int lc, const int rr, const int rc) {
		return lr == rr ? lc < rc : lr < rr;
	}
};
struct Yoko {
	static constexpr int index = 1;
	static inline bool comp(const int lr, const int lc, const int rr, const int rc) {
		return lc == rc ? lr < rr : lc < rc;
	}
};

namespace pts {
	int pt[2][MAX_N];
	int cr[MAX_N];
	template<typename dir>
	inline bool ice_comp(const int li, const int ri) {
		return dir::comp(in[li].r, in[li].c, in[ri].r, in[ri].c);
	}
	void build() {
		iota(pt[Yoko::index], pt[Yoko::index] + N, 0);
		iota(pt[Tate::index], pt[Tate::index] + N, 0);
		sort(pt[Yoko::index], pt[Yoko::index] + N, ice_comp<Yoko>);
		sort(pt[Tate::index], pt[Tate::index] + N, ice_comp<Tate>);
	}
	template<typename dir>
	inline int lower_bound(int r, int c) {
		int lb = -1, ub = N;
		while (ub - lb > 1) {
			const int mid = (lb + ub) / 2;
			(!dir::comp(r, c, in[pt[dir::index][mid]].r, in[pt[dir::index][mid]].c) ? lb : ub) = mid;
		}
		return ub;
	}
	inline bool isIce(int r, int c) {
		int id = lower_bound<Yoko>(r, c);
		return id != N && in[pt[Yoko::index][id]].r == r && in[pt[Yoko::index][id]].c == c;
	}
}

struct Down {
	static constexpr int index = 0;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Yoko>(r, c);
		if (id != N && in[pts::pt[Yoko::index][id]].c == c)
			return pts::pt[Yoko::index][id];
		else return -1;
	}
};

struct Right {
	static constexpr int index = 1;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Tate>(r, c);
		if (id != N && in[pts::pt[Tate::index][id]].r == r)
			return pts::pt[Tate::index][id];
		else return -1;
	}
};
struct Left {
	static constexpr int index = 2;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Tate>(r, c) - 1;
		if (id != -1 && in[pts::pt[Tate::index][id]].r == r)
			return pts::pt[Tate::index][id];
		else return -1;
	}
};
struct Up {
	static constexpr int index = 3;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Yoko>(r, c) - 1;
		if (id != -1 && in[pts::pt[Yoko::index][id]].c == c)
			return pts::pt[Yoko::index][id];
		else return -1;
	}
};
		
inline bool isReachable(int r,int c,int nr,int nc) {
	if (r == nr) {
		if (c < nc) {
			const int id = Right::getIce(r, c);
			return id == -1 || nc < in[id].c;
		}
		else if (nc < c) {
			const int id = Left::getIce(r, c);
			return id == -1 || in[id].c < nc;
		}
		else return true;
	}
	else if (c == nc) {
		if (r < nr) {
			const int id = Down::getIce(r, c);
			return id == -1 || nr < in[id].r;
		}
		else if (nr < r) {
			const int id = Up::getIce(r, c);
			return id == -1 || in[id].r < nr;
		}
		else return true;
	}
	else return false;
}


vector<P> g[MAX_N][4];
vector<P> rg[MAX_N][4];

int dist[MAX_N][4];
int rdist[MAX_N][4];
template<typename dir> 
inline void addArc(const int i, const int j, const int r,const int c) {
	const int id = dir::getIce(r, c);
	if (id != -1) {
		g[i][j].push_back(P{ id,3 - dir::index });
		rg[id][3 - dir::index].push_back(P{ i,j });
	}
}
void buildGraph(){
	for (int i : range(N)) {
		for (int d : range(4)) {
			int r = in[i].r + dr[d];
			int c = in[i].c + dc[d];
			if (pts::isIce(r, c))continue;
			addArc<Down>(i, d, r, c);
			addArc<Up>(i, d, r, c);
			addArc<Left>(i, d, r, c);
			addArc<Right>(i, d, r, c);
		}
	}
}
template<typename dir>
void uku(){
	int id = dir::getIce(S.r, S.c);
	if (id != -1) {
		const int r = in[id].r + dr[3 - dir::index];
		const int c = in[id].c + dc[3 - dir::index];
		dist[id][3 - dir::index] = (S.r != r || S.c != c);
	}
}
constexpr int INF = 1e7;
queue<P> que;
void bfs() {
	uku<Down>();
	uku<Left>();
	uku<Right>();
	uku<Up>();
	for (int i : range(N)) {
		for (int d : range(4)) {
			if (dist[i][d] == 0)que.push(P{ i,d });
		}
	}
	for (int i : range(N)) {
		for (int d : range(4)) {
			if (dist[i][d] == 1)que.push(P{ i,d });
		}
	}
	while (!que.empty()) {
		int i = que.front().r;
		int j = que.front().c;
		que.pop();
		for (auto &it : g[i][j]) {
			int ni = it.r;
			int nj = it.c;
			if (chmin(dist[ni][nj], dist[i][j] + 1)) {
				que.push(it);
			}
		}
	}
	for (int i : range(N)) {
		for (int d : range(4)) {
			const int r = in[i].r + dr[d];
			const int c = in[i].c + dc[d];
			if (isReachable(r, c, T.r, T.c)) {
				rdist[i][d] = 0;
				que.push(P{ i,d });
			}
		}
	}
	while (!que.empty()) {
		int i = que.front().r;
		int j = que.front().c;
		que.pop();
		for (auto &it : rg[i][j]) {
			int ni = it.r;
			int nj = it.c;
			if (chmin(rdist[ni][nj], rdist[i][j] + 1)) {
				que.push(it);
			}
		}
	}
}

//default::min
template<typename SEG>
using SetInitialLeaf = function<void(SEG&, int)>;

template<typename SEG>
using SetInitialSegment = function<void(SEG&, const int, const int)>;

template<typename RET, typename SEG>
using GetSingleSegment = function<RET(SEG&, const int, const int)>;

template<typename RET>
using GetMergedSegment = function<RET(RET, RET)>;

template<typename SEG, typename Q>
using UpdateSingleSegment = function<void(SEG&, Q)>;

SetInitialLeaf<int>
set_leaf = [](int &v, const int id) {
	v = INF;
};

SetInitialSegment<int>
set_segment = [](int &v, const int l, const int r) {};

GetSingleSegment<int,int> 
segment_min = [](int &v, const int l, const int r) {
	return v;
};

GetMergedSegment<int>
merge_segment = [](const int l, const int r) {
	return min(l, r);
};

UpdateSingleSegment<int,int>
force_update = [](int &v, int l) {
	v = l;
};

UpdateSingleSegment<int, int>
weak_update = [](int &v, int l) {
	chmin(v, l);
};


template<typename T>
struct BufferManager {
	T *mem;
	int ptr;
	BufferManager(T* mem) {
		ptr = 0;
		this->mem = mem;
	}
	T* get(int m) {
		ptr += m;
		return mem + ptr - m;
	}
	void reset() {
		ptr = 0;
	}
};

namespace NodeBuffer {
	constexpr int BufferSize = 812345;
	using NodeType = int;
	NodeType mem[BufferSize];
	BufferManager<NodeType> buffer(mem);
}

template<typename Node, typename RET>
struct SegmentTree{
	int size;
	Node *seg;
	GetSingleSegment<RET, Node> get_single_segment;
	GetMergedSegment<RET> get_merged_segment;
	void init(int l, int r, SetInitialSegment<Node>& init_segment ,SetInitialLeaf<Node>& init_leaf ,int k = 0) {
		auto &v = seg[k];
		init_segment(v, l, r);
		if (r - l == 1) {
			//葉の時の処理
			init_leaf(v, l);
		}
		else if (r - l>1) {
			int m = (l + r) / 2;
			init(l, m, init_segment, init_leaf, k * 2 + 1); 
			init(m, r, init_segment, init_leaf, k * 2 + 2);
			v = get_merged_segment(
				get_single_segment(seg[k * 2 + 1], l, m),
				get_single_segment(seg[k * 2 + 2], m, r)
			);
		}
	}
	SegmentTree(
		int n,
		GetSingleSegment<RET, Node> gss,
		GetMergedSegment<RET> gms,
		SetInitialSegment<Node> sis,
		SetInitialLeaf<Node> sil,
		BufferManager<Node> buf = NodeBuffer::buffer
		) 
		:get_single_segment(gss),
		 get_merged_segment(gms){
		size = 1; while (size<n)size *= 2;
		seg = buf.get(size + 10);
		init(0, size, sis, sil);
	}
#define LQ a,b,k*2+1,l,m
#define RQ a,b,k*2+2,m,r
	RET get(int a, int b, int k, int l, int r) {
		if (a <= l && r <= b)return get_single_segment(seg[k], l, r);
		int m = (l + r) / 2;
		bool ll = !(m <= a || b <= l);
		bool rr = !(r <= a || b <= m);
		RET ret;
		if (ll&&rr)ret = get_merged_segment(get(LQ), get(RQ));
		else if (ll)ret = get(LQ); else ret = get(RQ);
		return ret;
	}
	RET get(int a, int b) { 
		return get(a, b, 0, 0, size);
	}
	template<typename Q>
	void update(int a, int b, int k, int l, int r, UpdateSingleSegment<Node,Q> &update_segment, Q value) {
		if (r <= a || b <= l)return;
		if (a <= l && r <= b) {
			update_segment(seg[k], value);
		}
		else {
			int m = (l + r) / 2;
			update(LQ, update_segment, value);
			update(RQ, update_segment, value);
			seg[k] = get_merged_segment(
				get_single_segment(seg[k * 2 + 1], l, m), 
				get_single_segment(seg[k * 2 + 2], m, r)
			);
		}
	}
	template<typename Q>
	void update(int a, UpdateSingleSegment<Node, Q> &update_segment, Q value) {
		update(a, a+1, 0, 0, size, update_segment, value);
	}
};

int ret = INF;
void solve_down() {
	constexpr int dir = Down::index;
	constexpr int s = Left::index;
	SegmentTree<int, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = 0; lb < N;) {
		int ub = lb;
		int* pt = pts::pt[Tate::index];
		while (ub < N&&
			in[pt[lb]].r == in[pt[ub]].r) {
			ub++;
		}
		chmin(ret, rdist[pt[lb]][s] + query(0, in[pt[lb]].c) + 1);
		for (int i : range(lb, ub-1)) {
			const int seg_cost = query(in[pt[i]].c + 1, in[pt[i + 1]].c);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[ub - 1]][3 - s] + query(in[pt[ub - 1]].c + 1, Z::id) + 1);
		for (int i : range(lb, ub)) {
			rmq.update(in[pt[i]].c, force_update, dist[pt[i]][dir]);
			rmq.update(in[pt[i]].c + dc[s], weak_update, dist[pt[i]][s]);
			rmq.update(in[pt[i]].c + dc[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}

void solve_right() {
	constexpr int dir = Right::index;
	constexpr int s = Up::index;
	SegmentTree<int, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = 0; lb < N;) {
		int ub = lb;
		int* pt = pts::pt[Yoko::index];
		while (ub < N&&
			in[pt[lb]].c == in[pt[ub]].c) {
			ub++;
		}
		chmin(ret, rdist[pt[lb]][s] + query(0, in[pt[lb]].r) + 1);
		for (int i : range(lb, ub - 1)) {
			const int seg_cost = query(in[pt[i]].r + 1, in[pt[i + 1]].r);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[ub - 1]][3 - s] + query(in[pt[ub - 1]].r + 1, Z::id) + 1);
		for (int i : range(lb, ub)) {
			rmq.update(in[pt[i]].r, force_update, dist[pt[i]][dir]);
			rmq.update(in[pt[i]].r + dr[s], weak_update, dist[pt[i]][s]);
			rmq.update(in[pt[i]].r + dr[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}

void solve_up() {
	constexpr int dir = Up::index;
	constexpr int s = Left::index;
	SegmentTree<int, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = N-1; lb >= 0;) {
		int ub = lb;
		int* pt = pts::pt[Tate::index];
		while (ub >=0 &&
			in[pt[lb]].r == in[pt[ub]].r) {
			ub--;
		}
		chmin(ret, rdist[pt[ub+1]][s] + query(0, in[pt[ub+1]].c) + 1);
		for (int i : range(ub+1, lb)) {
			const int seg_cost = query(in[pt[i]].c + 1, in[pt[i + 1]].c);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[lb]][3 - s] + query(in[pt[lb]].c + 1, Z::id) + 1);
		for (int i : range(ub+1, lb+1)) {
			rmq.update(in[pt[i]].c, force_update, dist[pt[i]][dir]);
			rmq.update(in[pt[i]].c + dc[s], weak_update, dist[pt[i]][s]);
			rmq.update(in[pt[i]].c + dc[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}

void solve_left() {
	constexpr int dir = Left::index;
	constexpr int s = Up::index;
	SegmentTree<int, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = N-1; lb >= 0;) {
		int ub = lb;
		int* pt = pts::pt[Yoko::index];
		while (ub >=0&&
			in[pt[lb]].c == in[pt[ub]].c) {
			ub--;
		}
		chmin(ret, rdist[pt[ub+1]][s] + query(0, in[pt[ub+1]].r) + 1);
		for (int i : range(ub+1, lb)) {
			const int seg_cost = query(in[pt[i]].r + 1, in[pt[i + 1]].r);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[lb]][3 - s] + query(in[pt[lb]].r + 1, Z::id) + 1);
		for (int i : range(ub+1, lb+1)) {
			rmq.update(in[pt[i]].r, force_update, dist[pt[i]][dir]);
			rmq.update(in[pt[i]].r + dr[s], weak_update, dist[pt[i]][s]);
			rmq.update(in[pt[i]].r + dr[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}
inline bool isReachableWithHop(int r,int c) {
	return (isReachable(r, c, r, T.c) &&
		isReachable(r, T.c, T.r, T.c)) ||
		(isReachable(r, c, T.r, c) &&
			isReachable(T.r, c, T.r, T.c));
}

int main() {
	while (input()) {
		pts::build();
		if (isReachableWithHop(S.r, S.c)) {
			cout << 0 << endl; continue;
		}
		for (int i : range(N)) {
			for (int j : range(4)) {
				g[i][j].clear();
				rg[i][j].clear();
				dist[i][j] = INF;
				rdist[i][j] = INF;
			}
		}
		buildGraph();
		bfs();
		
		for (int i : range(N)) {
			for (int j : range(4)) {
				const int r = in[i].r + dr[j];
				const int c = in[i].c + dc[j];
				if (isReachableWithHop(r, c)) {
					chmin(ret, dist[i][j]);
					isReachableWithHop(r, c);
				}
			}
		}

		for (int i : range(N)) {
			if (isReachable(S.r,S.c,S.r,in[i].c)) {
				const int r = S.r;
				const int c = in[i].c;
				if (Down::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Down::index] + 1);
				if (Left::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Left::index] + 1);

				if (Right::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Right::index] + 1);
				if (Up::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Up::index] + 1);
			}
			if (isReachable(S.r, S.c, in[i].r, S.c)) {
				const int r = in[i].r;
				const int c = S.c;
				if (Down::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Down::index] + 1);
				if (Left::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Left::index] + 1);
				if (Right::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Right::index] + 1);
				if (Up::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Up::index] + 1);
			}
		}
		solve_down();
		solve_up(); 
		solve_left();
		solve_right();
		if (ret == INF)cout << -1 << endl;
		else cout << ret << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 850
memory_kb: 201032
final_rank: 1

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

using namespace std;
typedef long long LL;

#ifdef BTK
#define DEBUG if(1)
#else
#define CIN_ONLY if(1)
struct cww {cww() {CIN_ONLY{ios::sync_with_stdio(false); cin.tie(0);}}
}star;
#define DEBUG if(0)
#endif

#define ALL(v) (v).begin(),(v).end()
#define REC(ret, ...) std::function<ret (__VA_ARGS__)>
template <typename T>inline bool chmin(T &l, T r){bool a = l>r; if (a)l = r; return a;}
template <typename T>inline bool chmax(T &l, T r){bool a = l<r; if (a)l = r; return a;}
template <typename T>istream& operator>>(istream &is, vector<T> &v){for (auto &it : v)is >> it;return is;}

class range {private: struct I { int x; int operator*() { return x; }bool operator!=(I& lhs) { return x<lhs.x; }void operator++() { ++x; } }; I i, n;public:range(int n) :i({ 0 }), n({ n }) {}range(int i, int n) :i({ i }), n({ n }) {}I& begin() { return i; }I& end() { return n; }};

constexpr int MAX_N = 812345;
struct P{
	int r, c;
};
istream& operator>>(istream &is, P &v) { is >> v.r >> v.c; return is; }

P S, T;
int N;
P in[MAX_N];
namespace Z{
	int latte[MAX_N];
	int id;
	void init() {
		id = 0;
	}
	inline void set(int v) {
		latte[id++] = v;
	}
	inline void build() {
		sort(latte, latte + id);
		id = unique(latte, latte + id) - latte;
	}
	inline int ItoZ(int v) {
		return lower_bound(latte, latte + id, v) - latte;
	}
	inline int ZtoI(int v) {
		return latte[v];
	}
}

bool input() {
	if(cin >> S >> T);
	else return false;
	cin >> N;
	Z::init();
	for (int j : {-1, 0, 1}) {
		Z::set(S.r + j);
		Z::set(S.c + j);
		Z::set(T.r + j);
		Z::set(T.c + j);
	}
	for (int i : range(N)) {
		cin >> in[i];
		for (int j : {-1, 0, 1}) {
			Z::set(in[i].r + j);
			Z::set(in[i].c + j);
		}
	}
	Z::build();
	S.r = Z::ItoZ(S.r);	S.c = Z::ItoZ(S.c);
	T.r = Z::ItoZ(T.r);	T.c = Z::ItoZ(T.c);
	for (int i : range(N)) {
		in[i].r = Z::ItoZ(in[i].r);
		in[i].c = Z::ItoZ(in[i].c);
	}
#ifdef BTK
	cout << S.r << " " << S.c << endl;
	cout << T.r << " " << T.c << endl;
	cout << N << endl;
	for (int i : range(N)) {
		cout << in[i].r << " " << in[i].c << endl;
	}
#endif
	return true;
}
typedef vector<int> V;
typedef vector<V> VV;
typedef vector<VV> VVV;
constexpr int dr[4] = { 1,0,0,-1 };
constexpr int dc[4] = { 0,1,-1,0 };
const string ds = { "DRLU" };
struct Tate {
	static constexpr int index = 0;
	static inline bool comp(const int lr, const int lc, const int rr, const int rc) {
		return lr == rr ? lc < rc : lr < rr;
	}
};
struct Yoko {
	static constexpr int index = 1;
	static inline bool comp(const int lr, const int lc, const int rr, const int rc) {
		return lc == rc ? lr < rr : lc < rc;
	}
};

namespace pts {
	int pt[2][MAX_N];
	int cr[MAX_N];
	template<typename dir>
	inline bool ice_comp(const int li, const int ri) {
		return dir::comp(in[li].r, in[li].c, in[ri].r, in[ri].c);
	}
	void build() {
		iota(pt[Yoko::index], pt[Yoko::index] + N, 0);
		iota(pt[Tate::index], pt[Tate::index] + N, 0);
		sort(pt[Yoko::index], pt[Yoko::index] + N, ice_comp<Yoko>);
		sort(pt[Tate::index], pt[Tate::index] + N, ice_comp<Tate>);
	}
	template<typename dir>
	inline int lower_bound(int r, int c) {
		int lb = -1, ub = N;
		while (ub - lb > 1) {
			const int mid = (lb + ub) / 2;
			(!dir::comp(r, c, in[pt[dir::index][mid]].r, in[pt[dir::index][mid]].c) ? lb : ub) = mid;
		}
		return ub;
	}
	inline bool isIce(int r, int c) {
		int id = lower_bound<Yoko>(r, c);
		return id != N && in[pt[Yoko::index][id]].r == r && in[pt[Yoko::index][id]].c == c;
	}
}

struct Down {
	static constexpr int index = 0;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Yoko>(r, c);
		if (id != N && in[pts::pt[Yoko::index][id]].c == c)
			return pts::pt[Yoko::index][id];
		else return -1;
	}
};

struct Right {
	static constexpr int index = 1;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Tate>(r, c);
		if (id != N && in[pts::pt[Tate::index][id]].r == r)
			return pts::pt[Tate::index][id];
		else return -1;
	}
};
struct Left {
	static constexpr int index = 2;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Tate>(r, c) - 1;
		if (id != -1 && in[pts::pt[Tate::index][id]].r == r)
			return pts::pt[Tate::index][id];
		else return -1;
	}
};
struct Up {
	static constexpr int index = 3;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Yoko>(r, c) - 1;
		if (id != -1 && in[pts::pt[Yoko::index][id]].c == c)
			return pts::pt[Yoko::index][id];
		else return -1;
	}
};
		
inline bool isReachable(int r,int c,int nr,int nc) {
	if (r == nr) {
		if (c < nc) {
			const int id = Right::getIce(r, c);
			return id == -1 || nc < in[id].c;
		}
		else if (nc < c) {
			const int id = Left::getIce(r, c);
			return id == -1 || in[id].c < nc;
		}
		else return true;
	}
	else if (c == nc) {
		if (r < nr) {
			const int id = Down::getIce(r, c);
			return id == -1 || nr < in[id].r;
		}
		else if (nr < r) {
			const int id = Up::getIce(r, c);
			return id == -1 || in[id].r < nr;
		}
		else return true;
	}
	else return false;
}


vector<P> g[MAX_N][4];
vector<P> rg[MAX_N][4];

int dist[MAX_N][4];
int rdist[MAX_N][4];
template<typename dir> 
inline void addArc(const int i, const int j, const int r,const int c) {
	const int id = dir::getIce(r, c);
	if (id != -1) {
		g[i][j].push_back(P{ id,3 - dir::index });
		rg[id][3 - dir::index].push_back(P{ i,j });
	}
}
void buildGraph(){
	for (int i : range(N)) {
		for (int d : range(4)) {
			int r = in[i].r + dr[d];
			int c = in[i].c + dc[d];
			if (pts::isIce(r, c))continue;
			addArc<Down>(i, d, r, c);
			addArc<Up>(i, d, r, c);
			addArc<Left>(i, d, r, c);
			addArc<Right>(i, d, r, c);
		}
	}
}
template<typename dir>
void uku(){
	int id = dir::getIce(S.r, S.c);
	if (id != -1) {
		const int r = in[id].r + dr[3 - dir::index];
		const int c = in[id].c + dc[3 - dir::index];
		dist[id][3 - dir::index] = (S.r != r || S.c != c);
	}
}
constexpr int INF = 1e7;
queue<P> que;
void bfs() {
	uku<Down>();
	uku<Left>();
	uku<Right>();
	uku<Up>();
	for (int i : range(N)) {
		for (int d : range(4)) {
			if (dist[i][d] == 0)que.push(P{ i,d });
		}
	}
	for (int i : range(N)) {
		for (int d : range(4)) {
			if (dist[i][d] == 1)que.push(P{ i,d });
		}
	}
	while (!que.empty()) {
		int i = que.front().r;
		int j = que.front().c;
		que.pop();
		for (auto &it : g[i][j]) {
			int ni = it.r;
			int nj = it.c;
			if (chmin(dist[ni][nj], dist[i][j] + 1)) {
				que.push(it);
			}
		}
	}
	for (int i : range(N)) {
		for (int d : range(4)) {
			const int r = in[i].r + dr[d];
			const int c = in[i].c + dc[d];
			if (isReachable(r, c, T.r, T.c)) {
				rdist[i][d] = 0;
				que.push(P{ i,d });
			}
		}
	}
	while (!que.empty()) {
		int i = que.front().r;
		int j = que.front().c;
		que.pop();
		for (auto &it : rg[i][j]) {
			int ni = it.r;
			int nj = it.c;
			if (chmin(rdist[ni][nj], rdist[i][j] + 1)) {
				que.push(it);
			}
		}
	}
}

//default::min
template<typename SEG>
using SetInitialLeaf = function<void(SEG&, int)>;

template<typename SEG>
using SetInitialSegment = function<void(SEG&, const int, const int)>;

template<typename RET, typename SEG>
using GetSingleSegment = function<RET(SEG&, const int, const int)>;

template<typename RET>
using GetMergedSegment = function<RET(RET, RET)>;

template<typename SEG, typename Q>
using UpdateSingleSegment = function<void(SEG&, Q)>;

SetInitialLeaf<int>
set_leaf = [](int &v, const int id) {
	v = INF;
};

SetInitialSegment<int>
set_segment = [](int &v, const int l, const int r) {};

GetSingleSegment<int,int> 
segment_min = [](int &v, const int l, const int r) {
	return v;
};

GetMergedSegment<int>
merge_segment = [](const int l, const int r) {
	return min(l, r);
};

UpdateSingleSegment<int,int>
force_update = [](int &v, int l) {
	v = l;
};

UpdateSingleSegment<int, int>
weak_update = [](int &v, int l) {
	chmin(v, l);
};


template<typename T>
struct BufferManager {
	T *mem;
	int ptr;
	BufferManager(T* mem) {
		ptr = 0;
		this->mem = mem;
	}
	T* get(int m) {
		ptr += m;
		return mem + ptr - m;
	}
	void reset() {
		ptr = 0;
	}
};

namespace NodeBuffer {
	constexpr int BufferSize = 812345;
	using NodeType = int;
	NodeType mem[BufferSize];
	BufferManager<NodeType> buffer(mem);
}

template<typename Node, typename RET>
struct SegmentTree{
	int size;
	Node *seg;
	GetSingleSegment<RET, Node> get_single_segment;
	GetMergedSegment<RET> get_merged_segment;
	void init(int l, int r, SetInitialSegment<Node> init_segment ,SetInitialLeaf<Node> init_leaf ,int k = 0) {
		auto &v = seg[k];
		init_segment(v, l, r);
		if (r - l == 1) {
			//葉の時の処理
			init_leaf(v, l);
		}
		else if (r - l>1) {
			int m = (l + r) / 2;
			init(l, m, init_segment, init_leaf, k * 2 + 1); 
			init(m, r, init_segment, init_leaf, k * 2 + 2);
			v = get_merged_segment(
				get_single_segment(seg[k * 2 + 1], l, m),
				get_single_segment(seg[k * 2 + 2], m, r)
			);
		}
	}
	SegmentTree(
		int n,
		GetSingleSegment<RET, Node> gss,
		GetMergedSegment<RET> gms,
		SetInitialSegment<Node> sis,
		SetInitialLeaf<Node> sil,
		BufferManager<Node> buf = NodeBuffer::buffer
		) 
		:get_single_segment(gss),
		 get_merged_segment(gms){
		size = 1; while (size<n)size *= 2;
		seg = buf.get(size + 10);
		init(0, size, sis, sil);
	}
#define LQ a,b,k*2+1,l,m
#define RQ a,b,k*2+2,m,r
	RET get(int a, int b, int k, int l, int r) {
		if (a <= l && r <= b)return get_single_segment(seg[k], l, r);
		int m = (l + r) / 2;
		bool ll = !(m <= a || b <= l);
		bool rr = !(r <= a || b <= m);
		RET ret;
		if (ll&&rr)ret = get_merged_segment(get(LQ), get(RQ));
		else if (ll)ret = get(LQ); else ret = get(RQ);
		return ret;
	}
	RET get(int a, int b) { 
		return get(a, b, 0, 0, size);
	}
	template<typename Q>
	void update(int a, int b, int k, int l, int r, UpdateSingleSegment<Node,Q> &update_segment, Q value) {
		if (r <= a || b <= l)return;
		if (a <= l && r <= b) {
			update_segment(seg[k], value);
		}
		else {
			int m = (l + r) / 2;
			update(LQ, update_segment, value);
			update(RQ, update_segment, value);
			seg[k] = get_merged_segment(
				get_single_segment(seg[k * 2 + 1], l, m), 
				get_single_segment(seg[k * 2 + 2], m, r)
			);
		}
	}
	template<typename Q>
	void update(int a, UpdateSingleSegment<Node, Q> &update_segment, Q value) {
		update(a, a+1, 0, 0, size, update_segment, value);
	}
};

int ret = INF;
void solve_down() {
	constexpr int dir = Down::index;
	constexpr int s = Left::index;
	SegmentTree<int, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = 0; lb < N;) {
		int ub = lb;
		int* pt = pts::pt[Tate::index];
		while (ub < N&&
			in[pt[lb]].r == in[pt[ub]].r) {
			ub++;
		}
		chmin(ret, rdist[pt[lb]][s] + query(0, in[pt[lb]].c) + 1);
		for (int i : range(lb, ub-1)) {
			const int seg_cost = query(in[pt[i]].c + 1, in[pt[i + 1]].c);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[ub - 1]][3 - s] + query(in[pt[ub - 1]].c + 1, Z::id) + 1);
		for (int i : range(lb, ub)) {
			rmq.update(in[pt[i]].c, force_update, dist[pt[i]][dir]);
			rmq.update(in[pt[i]].c + dc[s], weak_update, dist[pt[i]][s]);
			rmq.update(in[pt[i]].c + dc[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}

void solve_right() {
	constexpr int dir = Right::index;
	constexpr int s = Up::index;
	SegmentTree<int, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = 0; lb < N;) {
		int ub = lb;
		int* pt = pts::pt[Yoko::index];
		while (ub < N&&
			in[pt[lb]].c == in[pt[ub]].c) {
			ub++;
		}
		chmin(ret, rdist[pt[lb]][s] + query(0, in[pt[lb]].r) + 1);
		for (int i : range(lb, ub - 1)) {
			const int seg_cost = query(in[pt[i]].r + 1, in[pt[i + 1]].r);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[ub - 1]][3 - s] + query(in[pt[ub - 1]].r + 1, Z::id) + 1);
		for (int i : range(lb, ub)) {
			rmq.update(in[pt[i]].r, force_update, dist[pt[i]][dir]);
			rmq.update(in[pt[i]].r + dr[s], weak_update, dist[pt[i]][s]);
			rmq.update(in[pt[i]].r + dr[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}

void solve_up() {
	constexpr int dir = Up::index;
	constexpr int s = Left::index;
	SegmentTree<int, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = N-1; lb >= 0;) {
		int ub = lb;
		int* pt = pts::pt[Tate::index];
		while (ub >=0 &&
			in[pt[lb]].r == in[pt[ub]].r) {
			ub--;
		}
		chmin(ret, rdist[pt[ub+1]][s] + query(0, in[pt[ub+1]].c) + 1);
		for (int i : range(ub+1, lb)) {
			const int seg_cost = query(in[pt[i]].c + 1, in[pt[i + 1]].c);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[lb]][3 - s] + query(in[pt[lb]].c + 1, Z::id) + 1);
		for (int i : range(ub+1, lb+1)) {
			rmq.update(in[pt[i]].c, force_update, dist[pt[i]][dir]);
			rmq.update(in[pt[i]].c + dc[s], weak_update, dist[pt[i]][s]);
			rmq.update(in[pt[i]].c + dc[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}

void solve_left() {
	constexpr int dir = Left::index;
	constexpr int s = Up::index;
	SegmentTree<int, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = N-1; lb >= 0;) {
		int ub = lb;
		int* pt = pts::pt[Yoko::index];
		while (ub >=0&&
			in[pt[lb]].c == in[pt[ub]].c) {
			ub--;
		}
		chmin(ret, rdist[pt[ub+1]][s] + query(0, in[pt[ub+1]].r) + 1);
		for (int i : range(ub+1, lb)) {
			const int seg_cost = query(in[pt[i]].r + 1, in[pt[i + 1]].r);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[lb]][3 - s] + query(in[pt[lb]].r + 1, Z::id) + 1);
		for (int i : range(ub+1, lb+1)) {
			rmq.update(in[pt[i]].r, force_update, dist[pt[i]][dir]);
			rmq.update(in[pt[i]].r + dr[s], weak_update, dist[pt[i]][s]);
			rmq.update(in[pt[i]].r + dr[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}
inline bool isReachableWithHop(int r,int c) {
	return (isReachable(r, c, r, T.c) &&
		isReachable(r, T.c, T.r, T.c)) ||
		(isReachable(r, c, T.r, c) &&
			isReachable(T.r, c, T.r, T.c));
}

int main() {
	while (input()) {
		pts::build();
		if (isReachableWithHop(S.r, S.c)) {
			cout << 0 << endl; continue;
		}
		for (int i : range(N)) {
			for (int j : range(4)) {
				g[i][j].clear();
				rg[i][j].clear();
				dist[i][j] = INF;
				rdist[i][j] = INF;
			}
		}
		buildGraph();
		bfs();
		
		for (int i : range(N)) {
			for (int j : range(4)) {
				const int r = in[i].r + dr[j];
				const int c = in[i].c + dc[j];
				if (isReachableWithHop(r, c)) {
					chmin(ret, dist[i][j]);
					isReachableWithHop(r, c);
				}
			}
		}

		for (int i : range(N)) {
			if (isReachable(S.r,S.c,S.r,in[i].c)) {
				const int r = S.r;
				const int c = in[i].c;
				if (Down::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Down::index] + 1);
				if (Left::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Left::index] + 1);

				if (Right::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Right::index] + 1);
				if (Up::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Up::index] + 1);
			}
			if (isReachable(S.r, S.c, in[i].r, S.c)) {
				const int r = in[i].r;
				const int c = S.c;
				if (Down::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Down::index] + 1);
				if (Left::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Left::index] + 1);
				if (Right::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Right::index] + 1);
				if (Up::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Up::index] + 1);
			}
		}
		solve_down();
		solve_up(); 
		solve_left();
		solve_right();
		if (ret == INF)cout << -1 << endl;
		else cout << ret << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 850
memory_kb: 201128
final_rank: 2

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

using namespace std;
typedef long long LL;

#ifdef BTK
#define DEBUG if(1)
#else
#define CIN_ONLY if(1)
struct cww {cww() {CIN_ONLY{ios::sync_with_stdio(false); cin.tie(0);}}
}star;
#define DEBUG if(0)
#endif

#define ALL(v) (v).begin(),(v).end()
#define REC(ret, ...) std::function<ret (__VA_ARGS__)>
template <typename T>inline bool chmin(T &l, T r){bool a = l>r; if (a)l = r; return a;}
template <typename T>inline bool chmax(T &l, T r){bool a = l<r; if (a)l = r; return a;}
template <typename T>istream& operator>>(istream &is, vector<T> &v){for (auto &it : v)is >> it;return is;}

class range {private: struct I { int x; int operator*() { return x; }bool operator!=(I& lhs) { return x<lhs.x; }void operator++() { ++x; } }; I i, n;public:range(int n) :i({ 0 }), n({ n }) {}range(int i, int n) :i({ i }), n({ n }) {}I& begin() { return i; }I& end() { return n; }};

constexpr int MAX_N = 812345;
struct P{
	int r, c;
};
istream& operator>>(istream &is, P &v) { is >> v.r >> v.c; return is; }

P S, T;
int N;
P in[MAX_N];
namespace Z{
	int latte[MAX_N];
	int id;
	void init() {
		id = 0;
	}
	inline void set(int v) {
		latte[id++] = v;
	}
	inline void build() {
		sort(latte, latte + id);
		id = unique(latte, latte + id) - latte;
	}
	inline int ItoZ(int v) {
		return lower_bound(latte, latte + id, v) - latte;
	}
	inline int ZtoI(int v) {
		return latte[v];
	}
}

bool input() {
	if(cin >> S >> T);
	else return false;
	cin >> N;
	Z::init();
	for (int j : {-1, 0, 1}) {
		Z::set(S.r + j);
		Z::set(S.c + j);
		Z::set(T.r + j);
		Z::set(T.c + j);
	}
	for (int i : range(N)) {
		cin >> in[i];
		for (int j : {-1, 0, 1}) {
			Z::set(in[i].r + j);
			Z::set(in[i].c + j);
		}
	}
	Z::build();
	S.r = Z::ItoZ(S.r);	S.c = Z::ItoZ(S.c);
	T.r = Z::ItoZ(T.r);	T.c = Z::ItoZ(T.c);
	for (int i : range(N)) {
		in[i].r = Z::ItoZ(in[i].r);
		in[i].c = Z::ItoZ(in[i].c);
	}
#ifdef BTK
	cout << S.r << " " << S.c << endl;
	cout << T.r << " " << T.c << endl;
	cout << N << endl;
	for (int i : range(N)) {
		cout << in[i].r << " " << in[i].c << endl;
	}
#endif
	return true;
}
typedef vector<int> V;
typedef vector<V> VV;
typedef vector<VV> VVV;
constexpr int dr[4] = { 1,0,0,-1 };
constexpr int dc[4] = { 0,1,-1,0 };
const string ds = { "DRLU" };
struct Tate {
	static constexpr int index = 0;
	static inline bool comp(const int lr, const int lc, const int rr, const int rc) {
		return lr == rr ? lc < rc : lr < rr;
	}
};
struct Yoko {
	static constexpr int index = 1;
	static inline bool comp(const int lr, const int lc, const int rr, const int rc) {
		return lc == rc ? lr < rr : lc < rc;
	}
};

namespace pts {
	int pt[2][MAX_N];
	int cr[MAX_N];
	template<typename dir>
	inline bool ice_comp(const int li, const int ri) {
		return dir::comp(in[li].r, in[li].c, in[ri].r, in[ri].c);
	}
	void build() {
		iota(pt[Yoko::index], pt[Yoko::index] + N, 0);
		iota(pt[Tate::index], pt[Tate::index] + N, 0);
		sort(pt[Yoko::index], pt[Yoko::index] + N, ice_comp<Yoko>);
		sort(pt[Tate::index], pt[Tate::index] + N, ice_comp<Tate>);
	}
	template<typename dir>
	inline int lower_bound(int r, int c) {
		int lb = -1, ub = N;
		while (ub - lb > 1) {
			const int mid = (lb + ub) / 2;
			(!dir::comp(r, c, in[pt[dir::index][mid]].r, in[pt[dir::index][mid]].c) ? lb : ub) = mid;
		}
		return ub;
	}
	inline bool isIce(int r, int c) {
		int id = lower_bound<Yoko>(r, c);
		return id != N && in[pt[Yoko::index][id]].r == r && in[pt[Yoko::index][id]].c == c;
	}
}

struct Down {
	static constexpr int index = 0;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Yoko>(r, c);
		if (id != N && in[pts::pt[Yoko::index][id]].c == c)
			return pts::pt[Yoko::index][id];
		else return -1;
	}
};

struct Right {
	static constexpr int index = 1;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Tate>(r, c);
		if (id != N && in[pts::pt[Tate::index][id]].r == r)
			return pts::pt[Tate::index][id];
		else return -1;
	}
};
struct Left {
	static constexpr int index = 2;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Tate>(r, c) - 1;
		if (id != -1 && in[pts::pt[Tate::index][id]].r == r)
			return pts::pt[Tate::index][id];
		else return -1;
	}
};
struct Up {
	static constexpr int index = 3;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Yoko>(r, c) - 1;
		if (id != -1 && in[pts::pt[Yoko::index][id]].c == c)
			return pts::pt[Yoko::index][id];
		else return -1;
	}
};
		
inline bool isReachable(int r,int c,int nr,int nc) {
	if (r == nr) {
		if (c < nc) {
			const int id = Right::getIce(r, c);
			return id == -1 || nc < in[id].c;
		}
		else if (nc < c) {
			const int id = Left::getIce(r, c);
			return id == -1 || in[id].c < nc;
		}
		else return true;
	}
	else if (c == nc) {
		if (r < nr) {
			const int id = Down::getIce(r, c);
			return id == -1 || nr < in[id].r;
		}
		else if (nr < r) {
			const int id = Up::getIce(r, c);
			return id == -1 || in[id].r < nr;
		}
		else return true;
	}
	else return false;
}


vector<P> g[MAX_N][4];
vector<P> rg[MAX_N][4];

int dist[MAX_N][4];
int rdist[MAX_N][4];
template<typename dir> 
inline void addArc(const int i, const int j, const int r,const int c) {
	const int id = dir::getIce(r, c);
	if (id != -1) {
		g[i][j].push_back(P{ id,3 - dir::index });
		rg[id][3 - dir::index].push_back(P{ i,j });
	}
}
void buildGraph(){
	for (int i : range(N)) {
		for (int d : range(4)) {
			int r = in[i].r + dr[d];
			int c = in[i].c + dc[d];
			if (pts::isIce(r, c))continue;
			addArc<Down>(i, d, r, c);
			addArc<Up>(i, d, r, c);
			addArc<Left>(i, d, r, c);
			addArc<Right>(i, d, r, c);
		}
	}
}
template<typename dir>
void uku(){
	int id = dir::getIce(S.r, S.c);
	if (id != -1) {
		const int r = in[id].r + dr[3 - dir::index];
		const int c = in[id].c + dc[3 - dir::index];
		dist[id][3 - dir::index] = (S.r != r || S.c != c);
	}
}
constexpr int INF = 1e7;
queue<P> que;
void bfs() {
	uku<Down>();
	uku<Left>();
	uku<Right>();
	uku<Up>();
	for (int i : range(N)) {
		for (int d : range(4)) {
			if (dist[i][d] == 0)que.push(P{ i,d });
		}
	}
	for (int i : range(N)) {
		for (int d : range(4)) {
			if (dist[i][d] == 1)que.push(P{ i,d });
		}
	}
	while (!que.empty()) {
		int i = que.front().r;
		int j = que.front().c;
		que.pop();
		for (auto &it : g[i][j]) {
			int ni = it.r;
			int nj = it.c;
			if (chmin(dist[ni][nj], dist[i][j] + 1)) {
				que.push(it);
			}
		}
	}
	for (int i : range(N)) {
		for (int d : range(4)) {
			const int r = in[i].r + dr[d];
			const int c = in[i].c + dc[d];
			if (isReachable(r, c, T.r, T.c)) {
				rdist[i][d] = 0;
				que.push(P{ i,d });
			}
		}
	}
	while (!que.empty()) {
		int i = que.front().r;
		int j = que.front().c;
		que.pop();
		for (auto &it : rg[i][j]) {
			int ni = it.r;
			int nj = it.c;
			if (chmin(rdist[ni][nj], rdist[i][j] + 1)) {
				que.push(it);
			}
		}
	}
}

//default::min
template<typename SEG>
using SetInitialLeaf = function<void(SEG&, int)>;

template<typename SEG>
using SetInitialSegment = function<void(SEG&, const int, const int)>;

template<typename RET, typename SEG>
using GetSingleSegment = function<RET(SEG&, const int, const int)>;

template<typename RET>
using GetMergedSegment = function<RET(RET, RET)>;

template<typename SEG, typename Q>
using UpdateSingleSegment = function<void(SEG&, Q)>;

SetInitialLeaf<int>
set_leaf = [](int &v, const int id) {
	v = INF;
};

SetInitialSegment<int>
set_segment = [](int &v, const int l, const int r) {};

GetSingleSegment<int,int> 
segment_min = [](int &v, const int l, const int r) {
	return v;
};

GetMergedSegment<int>
merge_segment = [](const int l, const int r) {
	return min(l, r);
};

UpdateSingleSegment<int,int>
force_update = [](int &v, int l) {
	v = l;
};

UpdateSingleSegment<int, int>
weak_update = [](int &v, int l) {
	chmin(v, l);
};


template<typename T>
struct BufferManager {
	T *mem;
	int ptr;
	BufferManager(T* mem) {
		ptr = 0;
		this->mem = mem;
	}
	T* get(int m) {
		ptr += m;
		return mem + ptr - m;
	}
	void reset() {
		ptr = 0;
	}
};

namespace NodeBuffer {
	constexpr int BufferSize = 812345;
	using NodeType = int;
	NodeType mem[BufferSize];
	BufferManager<NodeType> buffer(mem);
}

template<typename Node, typename RET>
struct SegmentTree{
	int size;
	Node *seg;
	GetSingleSegment<RET, Node> get_single_segment;
	GetMergedSegment<RET> get_merged_segment;
	void init(int l, int r, SetInitialSegment<Node> init_segment ,SetInitialLeaf<Node> init_leaf ,int k = 0) {
		auto &v = seg[k];
		init_segment(v, l, r);
		if (r - l == 1) {
			//葉の時の処理
			init_leaf(v, l);
		}
		else if (r - l>1) {
			int m = (l + r) / 2;
			init(l, m, init_segment, init_leaf, k * 2 + 1); 
			init(m, r, init_segment, init_leaf, k * 2 + 2);
			v = get_merged_segment(
				get_single_segment(seg[k * 2 + 1], l, m),
				get_single_segment(seg[k * 2 + 2], m, r)
			);
		}
	}
	SegmentTree(
		int n,
		GetSingleSegment<RET, Node> gss,
		GetMergedSegment<RET> gms,
		SetInitialSegment<Node> sis,
		SetInitialLeaf<Node> sil,
		BufferManager<Node> buf = NodeBuffer::buffer
		) 
		:get_single_segment(gss),
		 get_merged_segment(gms){
		size = 1; while (size<n)size *= 2;
		seg = buf.get(size + 10);
		init(0, size, sis, sil);
	}
#define LQ a,b,k*2+1,l,m
#define RQ a,b,k*2+2,m,r
	RET get(int a, int b, int k, int l, int r) {
		if (a <= l && r <= b)return get_single_segment(seg[k], l, r);
		int m = (l + r) / 2;
		bool ll = !(m <= a || b <= l);
		bool rr = !(r <= a || b <= m);
		RET ret;
		if (ll&&rr)ret = get_merged_segment(get(LQ), get(RQ));
		else if (ll)ret = get(LQ); else ret = get(RQ);
		return ret;
	}
	RET get(int a, int b) { 
		return get(a, b, 0, 0, size);
	}
	template<typename Q>
	void update(int a, int b, int k, int l, int r, UpdateSingleSegment<Node,Q> update_segment, Q value) {
		if (r <= a || b <= l)return;
		if (a <= l && r <= b) {
			update_segment(seg[k], value);
		}
		else {
			int m = (l + r) / 2;
			update(LQ, update_segment, value);
			update(RQ, update_segment, value);
			seg[k] = get_merged_segment(
				get_single_segment(seg[k * 2 + 1], l, m), 
				get_single_segment(seg[k * 2 + 2], m, r)
			);
		}
	}
	template<typename Q>
	void update(int a, UpdateSingleSegment<Node, Q> update_segment, Q value) {
		update(a, a+1, 0, 0, size, update_segment, value);
	}
};

int ret = INF;
void solve_down() {
	constexpr int dir = Down::index;
	constexpr int s = Left::index;
	SegmentTree<int, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = 0; lb < N;) {
		int ub = lb;
		int* pt = pts::pt[Tate::index];
		while (ub < N&&
			in[pt[lb]].r == in[pt[ub]].r) {
			ub++;
		}
		chmin(ret, rdist[pt[lb]][s] + query(0, in[pt[lb]].c) + 1);
		for (int i : range(lb, ub-1)) {
			const int seg_cost = query(in[pt[i]].c + 1, in[pt[i + 1]].c);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[ub - 1]][3 - s] + query(in[pt[ub - 1]].c + 1, Z::id) + 1);
		for (int i : range(lb, ub)) {
			rmq.update(in[pt[i]].c, force_update, dist[pt[i]][dir]);
			rmq.update(in[pt[i]].c + dc[s], weak_update, dist[pt[i]][s]);
			rmq.update(in[pt[i]].c + dc[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}

void solve_right() {
	constexpr int dir = Right::index;
	constexpr int s = Up::index;
	SegmentTree<int, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = 0; lb < N;) {
		int ub = lb;
		int* pt = pts::pt[Yoko::index];
		while (ub < N&&
			in[pt[lb]].c == in[pt[ub]].c) {
			ub++;
		}
		chmin(ret, rdist[pt[lb]][s] + query(0, in[pt[lb]].r) + 1);
		for (int i : range(lb, ub - 1)) {
			const int seg_cost = query(in[pt[i]].r + 1, in[pt[i + 1]].r);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[ub - 1]][3 - s] + query(in[pt[ub - 1]].r + 1, Z::id) + 1);
		for (int i : range(lb, ub)) {
			rmq.update(in[pt[i]].r, force_update, dist[pt[i]][dir]);
			rmq.update(in[pt[i]].r + dr[s], weak_update, dist[pt[i]][s]);
			rmq.update(in[pt[i]].r + dr[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}

void solve_up() {
	constexpr int dir = Up::index;
	constexpr int s = Left::index;
	SegmentTree<int, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = N-1; lb >= 0;) {
		int ub = lb;
		int* pt = pts::pt[Tate::index];
		while (ub >=0 &&
			in[pt[lb]].r == in[pt[ub]].r) {
			ub--;
		}
		chmin(ret, rdist[pt[ub+1]][s] + query(0, in[pt[ub+1]].c) + 1);
		for (int i : range(ub+1, lb)) {
			const int seg_cost = query(in[pt[i]].c + 1, in[pt[i + 1]].c);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[lb]][3 - s] + query(in[pt[lb]].c + 1, Z::id) + 1);
		for (int i : range(ub+1, lb+1)) {
			rmq.update(in[pt[i]].c, force_update, dist[pt[i]][dir]);
			rmq.update(in[pt[i]].c + dc[s], weak_update, dist[pt[i]][s]);
			rmq.update(in[pt[i]].c + dc[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}

void solve_left() {
	constexpr int dir = Left::index;
	constexpr int s = Up::index;
	SegmentTree<int, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = N-1; lb >= 0;) {
		int ub = lb;
		int* pt = pts::pt[Yoko::index];
		while (ub >=0&&
			in[pt[lb]].c == in[pt[ub]].c) {
			ub--;
		}
		chmin(ret, rdist[pt[ub+1]][s] + query(0, in[pt[ub+1]].r) + 1);
		for (int i : range(ub+1, lb)) {
			const int seg_cost = query(in[pt[i]].r + 1, in[pt[i + 1]].r);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[lb]][3 - s] + query(in[pt[lb]].r + 1, Z::id) + 1);
		for (int i : range(ub+1, lb+1)) {
			rmq.update(in[pt[i]].r, force_update, dist[pt[i]][dir]);
			rmq.update(in[pt[i]].r + dr[s], weak_update, dist[pt[i]][s]);
			rmq.update(in[pt[i]].r + dr[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}
inline bool isReachableWithHop(int r,int c) {
	return (isReachable(r, c, r, T.c) &&
		isReachable(r, T.c, T.r, T.c)) ||
		(isReachable(r, c, T.r, c) &&
			isReachable(T.r, c, T.r, T.c));
}

int main() {
	while (input()) {
		pts::build();
		if (isReachableWithHop(S.r, S.c)) {
			cout << 0 << endl; continue;
		}
		for (int i : range(N)) {
			for (int j : range(4)) {
				g[i][j].clear();
				rg[i][j].clear();
				dist[i][j] = INF;
				rdist[i][j] = INF;
			}
		}
		buildGraph();
		bfs();
		
		for (int i : range(N)) {
			for (int j : range(4)) {
				const int r = in[i].r + dr[j];
				const int c = in[i].c + dc[j];
				if (isReachableWithHop(r, c)) {
					chmin(ret, dist[i][j]);
					isReachableWithHop(r, c);
				}
			}
		}

		for (int i : range(N)) {
			if (isReachable(S.r,S.c,S.r,in[i].c)) {
				const int r = S.r;
				const int c = in[i].c;
				if (Down::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Down::index] + 1);
				if (Left::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Left::index] + 1);

				if (Right::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Right::index] + 1);
				if (Up::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Up::index] + 1);
			}
			if (isReachable(S.r, S.c, in[i].r, S.c)) {
				const int r = in[i].r;
				const int c = S.c;
				if (Down::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Down::index] + 1);
				if (Left::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Left::index] + 1);
				if (Right::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Right::index] + 1);
				if (Up::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Up::index] + 1);
			}
		}
		solve_down();
		solve_up(); 
		solve_left();
		solve_right();
		if (ret == INF)cout << -1 << endl;
		else cout << ret << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 1130
memory_kb: 201192
final_rank: 5

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

using namespace std;
typedef long long LL;

#ifdef BTK
#define DEBUG if(1)
#else
#define CIN_ONLY if(1)
struct cww {cww() {CIN_ONLY{ios::sync_with_stdio(false); cin.tie(0);}}
}star;
#define DEBUG if(0)
#endif

#define ALL(v) (v).begin(),(v).end()
#define REC(ret, ...) std::function<ret (__VA_ARGS__)>
template <typename T>inline bool chmin(T &l, T r){bool a = l>r; if (a)l = r; return a;}
template <typename T>inline bool chmax(T &l, T r){bool a = l<r; if (a)l = r; return a;}
template <typename T>istream& operator>>(istream &is, vector<T> &v){for (auto &it : v)is >> it;return is;}

class range {private: struct I { int x; int operator*() { return x; }bool operator!=(I& lhs) { return x<lhs.x; }void operator++() { ++x; } }; I i, n;public:range(int n) :i({ 0 }), n({ n }) {}range(int i, int n) :i({ i }), n({ n }) {}I& begin() { return i; }I& end() { return n; }};

constexpr int MAX_N = 812345;
struct P{
	int r, c;
};
istream& operator>>(istream &is, P &v) { is >> v.r >> v.c; return is; }

P S, T;
int N;
P in[MAX_N];
namespace Z{
	int latte[MAX_N];
	int id;
	void init() {
		id = 0;
	}
	inline void set(int v) {
		latte[id++] = v;
	}
	inline void build() {
		sort(latte, latte + id);
		id = unique(latte, latte + id) - latte;
	}
	inline int ItoZ(int v) {
		return lower_bound(latte, latte + id, v) - latte;
	}
	inline int ZtoI(int v) {
		return latte[v];
	}
}

bool input() {
	if(cin >> S >> T);
	else return false;
	cin >> N;
	Z::init();
	for (int j : {-1, 0, 1}) {
		Z::set(S.r + j);
		Z::set(S.c + j);
		Z::set(T.r + j);
		Z::set(T.c + j);
	}
	for (int i : range(N)) {
		cin >> in[i];
		for (int j : {-1, 0, 1}) {
			Z::set(in[i].r + j);
			Z::set(in[i].c + j);
		}
	}
	Z::build();
	S.r = Z::ItoZ(S.r);	S.c = Z::ItoZ(S.c);
	T.r = Z::ItoZ(T.r);	T.c = Z::ItoZ(T.c);
	for (int i : range(N)) {
		in[i].r = Z::ItoZ(in[i].r);
		in[i].c = Z::ItoZ(in[i].c);
	}
#ifdef BTK
	cout << S.r << " " << S.c << endl;
	cout << T.r << " " << T.c << endl;
	cout << N << endl;
	for (int i : range(N)) {
		cout << in[i].r << " " << in[i].c << endl;
	}
#endif
	return true;
}
typedef vector<int> V;
typedef vector<V> VV;
typedef vector<VV> VVV;
constexpr int dr[4] = { 1,0,0,-1 };
constexpr int dc[4] = { 0,1,-1,0 };
const string ds = { "DRLU" };
struct Tate {
	static constexpr int index = 0;
	static inline bool comp(const int lr, const int lc, const int rr, const int rc) {
		return lr == rr ? lc < rc : lr < rr;
	}
};
struct Yoko {
	static constexpr int index = 1;
	static inline bool comp(const int lr, const int lc, const int rr, const int rc) {
		return lc == rc ? lr < rr : lc < rc;
	}
};

namespace pts {
	int pt[2][MAX_N];
	int cr[MAX_N];
	template<typename dir>
	inline bool ice_comp(const int li, const int ri) {
		return dir::comp(in[li].r, in[li].c, in[ri].r, in[ri].c);
	}
	void build() {
		iota(pt[Yoko::index], pt[Yoko::index] + N, 0);
		iota(pt[Tate::index], pt[Tate::index] + N, 0);
		sort(pt[Yoko::index], pt[Yoko::index] + N, ice_comp<Yoko>);
		sort(pt[Tate::index], pt[Tate::index] + N, ice_comp<Tate>);
	}
	template<typename dir>
	inline int lower_bound(int r, int c) {
		int lb = -1, ub = N;
		while (ub - lb > 1) {
			const int mid = (lb + ub) / 2;
			(!dir::comp(r, c, in[pt[dir::index][mid]].r, in[pt[dir::index][mid]].c) ? lb : ub) = mid;
		}
		return ub;
	}
	inline bool isIce(int r, int c) {
		int id = lower_bound<Yoko>(r, c);
		return id != N && in[pt[Yoko::index][id]].r == r && in[pt[Yoko::index][id]].c == c;
	}
}

struct Down {
	static constexpr int index = 0;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Yoko>(r, c);
		if (id != N && in[pts::pt[Yoko::index][id]].c == c)
			return pts::pt[Yoko::index][id];
		else return -1;
	}
};

struct Right {
	static constexpr int index = 1;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Tate>(r, c);
		if (id != N && in[pts::pt[Tate::index][id]].r == r)
			return pts::pt[Tate::index][id];
		else return -1;
	}
};
struct Left {
	static constexpr int index = 2;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Tate>(r, c) - 1;
		if (id != -1 && in[pts::pt[Tate::index][id]].r == r)
			return pts::pt[Tate::index][id];
		else return -1;
	}
};
struct Up {
	static constexpr int index = 3;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Yoko>(r, c) - 1;
		if (id != -1 && in[pts::pt[Yoko::index][id]].c == c)
			return pts::pt[Yoko::index][id];
		else return -1;
	}
};
		
inline bool isReachable(int r,int c,int nr,int nc) {
	if (r == nr) {
		if (c < nc) {
			const int id = Right::getIce(r, c);
			return id == -1 || nc < in[id].c;
		}
		else if (nc < c) {
			const int id = Left::getIce(r, c);
			return id == -1 || in[id].c < nc;
		}
		else return true;
	}
	else if (c == nc) {
		if (r < nr) {
			const int id = Down::getIce(r, c);
			return id == -1 || nr < in[id].r;
		}
		else if (nr < r) {
			const int id = Up::getIce(r, c);
			return id == -1 || in[id].r < nr;
		}
		else return true;
	}
	else return false;
}


vector<P> g[MAX_N][4];
vector<P> rg[MAX_N][4];

int dist[MAX_N][4];
int rdist[MAX_N][4];
template<typename dir> 
inline void addArc(const int i, const int j, const int r,const int c) {
	const int id = dir::getIce(r, c);
	if (id != -1) {
		g[i][j].push_back(P{ id,3 - dir::index });
		rg[id][3 - dir::index].push_back(P{ i,j });
	}
}
void buildGraph(){
	for (int i : range(N)) {
		for (int d : range(4)) {
			int r = in[i].r + dr[d];
			int c = in[i].c + dc[d];
			if (pts::isIce(r, c))continue;
			addArc<Down>(i, d, r, c);
			addArc<Up>(i, d, r, c);
			addArc<Left>(i, d, r, c);
			addArc<Right>(i, d, r, c);
		}
	}
}
template<typename dir>
void uku(){
	int id = dir::getIce(S.r, S.c);
	if (id != -1) {
		const int r = in[id].r + dr[3 - dir::index];
		const int c = in[id].c + dc[3 - dir::index];
		dist[id][3 - dir::index] = (S.r != r || S.c != c);
	}
}
constexpr int INF = 1e7;
queue<P> que;
void bfs() {
	uku<Down>();
	uku<Left>();
	uku<Right>();
	uku<Up>();
	for (int i : range(N)) {
		for (int d : range(4)) {
			if (dist[i][d] == 0)que.push(P{ i,d });
		}
	}
	for (int i : range(N)) {
		for (int d : range(4)) {
			if (dist[i][d] == 1)que.push(P{ i,d });
		}
	}
	while (!que.empty()) {
		int i = que.front().r;
		int j = que.front().c;
		que.pop();
		for (auto &it : g[i][j]) {
			int ni = it.r;
			int nj = it.c;
			if (chmin(dist[ni][nj], dist[i][j] + 1)) {
				que.push(it);
			}
		}
	}
	for (int i : range(N)) {
		for (int d : range(4)) {
			const int r = in[i].r + dr[d];
			const int c = in[i].c + dc[d];
			if (isReachable(r, c, T.r, T.c)) {
				rdist[i][d] = 0;
				que.push(P{ i,d });
			}
		}
	}
	while (!que.empty()) {
		int i = que.front().r;
		int j = que.front().c;
		que.pop();
		for (auto &it : rg[i][j]) {
			int ni = it.r;
			int nj = it.c;
			if (chmin(rdist[ni][nj], rdist[i][j] + 1)) {
				que.push(it);
			}
		}
	}
}

//default::min
template<typename SEG>
using SetInitialLeaf = function<void(SEG&, int)>;

template<typename SEG>
using SetInitialSegment = function<void(SEG&, const int, const int)>;

template<typename RET, typename SEG>
using GetSingleSegment = function<RET(SEG&, const int, const int)>;

template<typename RET>
using GetMergedSegment = function<RET(RET, RET)>;

template<typename SEG, typename Q>
using UpdateSingleSegment = function<void(SEG&, Q)>;

SetInitialLeaf<int>
set_leaf = [](int &v, const int id) {
	v = INF;
};

SetInitialSegment<int>
set_segment = [](int &v, const int l, const int r) {};

GetSingleSegment<int,int> 
segment_min = [](int &v, const int l, const int r) {
	return v;
};

GetMergedSegment<int>
merge_segment = [](const int l, const int r) {
	return min(l, r);
};

UpdateSingleSegment<int,int>
force_update = [](int &v, int l) {
	v = l;
};

UpdateSingleSegment<int, int>
weak_update = [](int &v, int l) {
	chmin(v, l);
};


template<typename T>
struct BufferManager {
	T *mem;
	int ptr;
	BufferManager(T* mem) {
		ptr = 0;
		this->mem = mem;
	}
	T* get(int m) {
		ptr += m;
		return mem + ptr - m;
	}
	void reset() {
		ptr = 0;
	}
};

namespace NodeBuffer {
	constexpr int BufferSize = 812345;
	using NodeType = int;
	NodeType mem[BufferSize];
	BufferManager<NodeType> buffer(mem);
}

template<typename Node, typename RET>
struct SegmentTree{
	int size;
	Node *seg;
	GetSingleSegment<RET, Node> get_single_segment;
	GetMergedSegment<RET> get_merged_segment;
	void init(int l, int r, SetInitialSegment<Node> init_segment ,SetInitialLeaf<Node> init_leaf ,int k = 0) {
		auto &v = seg[k];
		init_segment(v, l, r);
		if (r - l == 1) {
			//葉の時の処理
			init_leaf(v, l);
		}
		else if (r - l>1) {
			int m = (l + r) / 2;
			init(l, m, init_segment, init_leaf, k * 2 + 1); 
			init(m, r, init_segment, init_leaf, k * 2 + 2);
			v = get_merged_segment(
				get_single_segment(seg[k * 2 + 1], l, m),
				get_single_segment(seg[k * 2 + 2], m, r)
			);
		}
	}
	SegmentTree(
		int n,
		GetSingleSegment<RET, Node> gss,
		GetMergedSegment<RET> gms,
		SetInitialSegment<Node> sis,
		SetInitialLeaf<Node> sil,
		BufferManager<Node> buf = NodeBuffer::buffer
		) 
		:get_single_segment(gss),
		 get_merged_segment(gms){
		size = 1; while (size<n)size *= 2;
		seg = buf.get(size + 10);
		init(0, size, sis, sil);
	}
#define LQ a,b,k*2+1,l,m
#define RQ a,b,k*2+2,m,r
	RET get(int a, int b, int k, int l, int r) {
		if (a <= l && r <= b)return get_single_segment(seg[k], l, r);
		int m = (l + r) / 2;
		bool ll = !(m <= a || b <= l);
		bool rr = !(r <= a || b <= m);
		RET ret;
		if (ll&&rr)ret = get_merged_segment(get(LQ), get(RQ));
		else if (ll)ret = get(LQ); else ret = get(RQ);
		return ret;
	}
	RET get(int a, int b) { 
		return get(a, b, 0, 0, size);
	}
	template<typename Q>
	void update(int a, int b, int k, int l, int r, UpdateSingleSegment<Node,Q> update_segment, Q value) {
		if (r <= a || b <= l)return;
		if (a <= l && r <= b) {
			update_segment(seg[k], value);
		}
		else {
			int m = (l + r) / 2;
			update(LQ, update_segment, value);
			update(RQ, update_segment, value);
			seg[k] = get_merged_segment(
				get_single_segment(seg[k * 2 + 1], l, m), 
				get_single_segment(seg[k * 2 + 2], m, r)
			);
		}
	}
	template<typename Q>
	void update(int a, UpdateSingleSegment<Node, Q> update_segment, Q value) {
		update(a, a+1, 0, 0, size, update_segment, value);
	}
};

int ret = INF;
void solve_down() {
	constexpr int dir = Down::index;
	constexpr int s = Left::index;
	SegmentTree<int, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = 0; lb < N;) {
		int ub = lb;
		int* pt = pts::pt[Tate::index];
		while (ub < N&&
			in[pt[lb]].r == in[pt[ub]].r) {
			ub++;
		}
		chmin(ret, rdist[pt[lb]][s] + query(0, in[pt[lb]].c) + 1);
		for (int i : range(lb, ub-1)) {
			const int seg_cost = query(in[pt[i]].c + 1, in[pt[i + 1]].c);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[ub - 1]][3 - s] + query(in[pt[ub - 1]].c + 1, Z::id) + 1);
		for (int i : range(lb, ub)) {
			rmq.update(in[pt[i]].c, force_update, dist[pt[i]][dir]);
			rmq.update(in[pt[i]].c + dc[s], weak_update, dist[pt[i]][s]);
			rmq.update(in[pt[i]].c + dc[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}

void solve_right() {
	constexpr int dir = Right::index;
	constexpr int s = Up::index;
	SegmentTree<int, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = 0; lb < N;) {
		int ub = lb;
		int* pt = pts::pt[Yoko::index];
		while (ub < N&&
			in[pt[lb]].c == in[pt[ub]].c) {
			ub++;
		}
		chmin(ret, rdist[pt[lb]][s] + query(0, in[pt[lb]].r) + 1);
		for (int i : range(lb, ub - 1)) {
			const int seg_cost = query(in[pt[i]].r + 1, in[pt[i + 1]].r);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[ub - 1]][3 - s] + query(in[pt[ub - 1]].r + 1, Z::id) + 1);
		for (int i : range(lb, ub)) {
			rmq.update(in[pt[i]].r, force_update, dist[pt[i]][dir]);
			rmq.update(in[pt[i]].r + dr[s], weak_update, dist[pt[i]][s]);
			rmq.update(in[pt[i]].r + dr[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}

void solve_up() {
	constexpr int dir = Up::index;
	constexpr int s = Left::index;
	SegmentTree<int, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = N-1; lb >= 0;) {
		int ub = lb;
		int* pt = pts::pt[Tate::index];
		while (ub >=0 &&
			in[pt[lb]].r == in[pt[ub]].r) {
			ub--;
		}
		chmin(ret, rdist[pt[ub+1]][s] + query(0, in[pt[ub+1]].c) + 1);
		for (int i : range(ub+1, lb)) {
			const int seg_cost = query(in[pt[i]].c + 1, in[pt[i + 1]].c);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[lb]][3 - s] + query(in[pt[lb]].c + 1, Z::id) + 1);
		for (int i : range(ub+1, lb+1)) {
			rmq.update(in[pt[i]].c, force_update, dist[pt[i]][dir]);
			rmq.update(in[pt[i]].c + dc[s], weak_update, dist[pt[i]][s]);
			rmq.update(in[pt[i]].c + dc[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}

void solve_left() {
	constexpr int dir = Left::index;
	constexpr int s = Up::index;
	SegmentTree<int, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = N-1; lb >= 0;) {
		int ub = lb;
		int* pt = pts::pt[Yoko::index];
		while (ub >=0&&
			in[pt[lb]].c == in[pt[ub]].c) {
			ub--;
		}
		chmin(ret, rdist[pt[ub+1]][s] + query(0, in[pt[ub+1]].r) + 1);
		for (int i : range(ub+1, lb)) {
			const int seg_cost = query(in[pt[i]].r + 1, in[pt[i + 1]].r);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[lb]][3 - s] + query(in[pt[lb]].r + 1, Z::id) + 1);
		for (int i : range(ub+1, lb+1)) {
			rmq.update(in[pt[i]].r, force_update, dist[pt[i]][dir]);
			rmq.update(in[pt[i]].r + dr[s], weak_update, dist[pt[i]][s]);
			rmq.update(in[pt[i]].r + dr[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}
inline bool isReachableWithHop(int r,int c) {
	return (isReachable(r, c, r, T.c) &&
		isReachable(r, T.c, T.r, T.c)) ||
		(isReachable(r, c, T.r, c) &&
			isReachable(T.r, c, T.r, T.c));
}

int main() {
	while (input()) {
		pts::build();
		if (isReachableWithHop(S.r, S.c)) {
			cout << 0 << endl; continue;
		}
		for (int i : range(N)) {
			for (int j : range(4)) {
				g[i][j].clear();
				rg[i][j].clear();
				dist[i][j] = INF;
				rdist[i][j] = INF;
			}
		}
		buildGraph();
		bfs();
		
		for (int i : range(N)) {
			for (int j : range(4)) {
				const int r = in[i].r + dr[j];
				const int c = in[i].c + dc[j];
				if (isReachableWithHop(r, c)) {
					chmin(ret, dist[i][j]);
					isReachableWithHop(r, c);
				}
			}
		}

		for (int i : range(N)) {
			if (isReachable(S.r,S.c,S.r,in[i].c)) {
				const int r = S.r;
				const int c = in[i].c;
				if (Down::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Down::index] + 1);
				if (Left::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Left::index] + 1);

				if (Right::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Right::index] + 1);
				if (Up::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Up::index] + 1);
			}
			if (isReachable(S.r, S.c, in[i].r, S.c)) {
				const int r = in[i].r;
				const int c = S.c;
				if (Down::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Down::index] + 1);
				if (Left::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Left::index] + 1);
				if (Right::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Right::index] + 1);
				if (Up::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Up::index] + 1);
			}
		}
		solve_down();assert(ret >= 4);
		solve_up(); assert(ret >= 4);
		solve_left(); assert(ret >= 4);
		solve_right(); assert(ret >= 4);
		if (ret == INF)cout << -1 << endl;
		else cout << ret << endl;
	}
	return 0;
}
accuracy: 0.5
time_ms: 70
memory_kb: 155684
final_rank: 7

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

using namespace std;
typedef long long LL;

#ifdef BTK
#define DEBUG if(1)
#else
#define CIN_ONLY if(1)
struct cww {cww() {CIN_ONLY{ios::sync_with_stdio(false); cin.tie(0);}}
}star;
#define DEBUG if(0)
#endif

#define ALL(v) (v).begin(),(v).end()
#define REC(ret, ...) std::function<ret (__VA_ARGS__)>
template <typename T>inline bool chmin(T &l, T r){bool a = l>r; if (a)l = r; return a;}
template <typename T>inline bool chmax(T &l, T r){bool a = l<r; if (a)l = r; return a;}
template <typename T>istream& operator>>(istream &is, vector<T> &v){for (auto &it : v)is >> it;return is;}

class range {private: struct I { int x; int operator*() { return x; }bool operator!=(I& lhs) { return x<lhs.x; }void operator++() { ++x; } }; I i, n;public:range(int n) :i({ 0 }), n({ n }) {}range(int i, int n) :i({ i }), n({ n }) {}I& begin() { return i; }I& end() { return n; }};

constexpr int MAX_N = 812345;
struct P{
	int r, c;
};
istream& operator>>(istream &is, P &v) { is >> v.r >> v.c; return is; }

P S, T;
int N;
P in[MAX_N];
namespace Z{
	int latte[MAX_N];
	int id;
	void init() {
		id = 0;
	}
	inline void set(int v) {
		latte[id++] = v;
	}
	inline void build() {
		sort(latte, latte + id);
		id = unique(latte, latte + id) - latte;
	}
	inline int ItoZ(int v) {
		return lower_bound(latte, latte + id, v) - latte;
	}
	inline int ZtoI(int v) {
		return latte[v];
	}
}

bool input() {
	if(cin >> S >> T);
	else return false;
	cin >> N;
	Z::init();
	for (int j : {-1, 0, 1}) {
		Z::set(S.r + j);
		Z::set(S.c + j);
		Z::set(T.r + j);
		Z::set(T.c + j);
	}
	for (int i : range(N)) {
		cin >> in[i];
		for (int j : {-1, 0, 1}) {
			Z::set(in[i].r + j);
			Z::set(in[i].c + j);
		}
	}
	Z::build();
	S.r = Z::ItoZ(S.r);	S.c = Z::ItoZ(S.c);
	T.r = Z::ItoZ(T.r);	T.c = Z::ItoZ(T.c);
	for (int i : range(N)) {
		in[i].r = Z::ItoZ(in[i].r);
		in[i].c = Z::ItoZ(in[i].c);
	}
#ifdef BTK
	cout << S.r << " " << S.c << endl;
	cout << T.r << " " << T.c << endl;
	cout << N << endl;
	for (int i : range(N)) {
		cout << in[i].r << " " << in[i].c << endl;
	}
#endif
	return true;
}
typedef vector<int> V;
typedef vector<V> VV;
typedef vector<VV> VVV;
constexpr int dr[4] = { 1,0,0,-1 };
constexpr int dc[4] = { 0,1,-1,0 };
const string ds = { "DRLU" };
struct Tate {
	static constexpr int index = 0;
	static inline bool comp(const int lr, const int lc, const int rr, const int rc) {
		return lr == rr ? lc < rc : lr < rr;
	}
};
struct Yoko {
	static constexpr int index = 1;
	static inline bool comp(const int lr, const int lc, const int rr, const int rc) {
		return lc == rc ? lr < rr : lc < rc;
	}
};

namespace pts {
	int pt[2][MAX_N];
	int cr[MAX_N];
	template<typename dir>
	inline bool ice_comp(const int li, const int ri) {
		return dir::comp(in[li].r, in[li].c, in[ri].r, in[ri].c);
	}
	void build() {
		iota(pt[Yoko::index], pt[Yoko::index] + N, 0);
		iota(pt[Tate::index], pt[Tate::index] + N, 0);
		sort(pt[Yoko::index], pt[Yoko::index] + N, ice_comp<Yoko>);
		sort(pt[Tate::index], pt[Tate::index] + N, ice_comp<Tate>);
	}
	template<typename dir>
	inline int lower_bound(int r, int c) {
		int lb = -1, ub = N;
		while (ub - lb > 1) {
			const int mid = (lb + ub) / 2;
			(!dir::comp(r, c, in[pt[dir::index][mid]].r, in[pt[dir::index][mid]].c) ? lb : ub) = mid;
		}
		return ub;
	}
	inline bool isIce(int r, int c) {
		int id = lower_bound<Yoko>(r, c);
		return id != N && in[pt[Yoko::index][id]].r == r && in[pt[Yoko::index][id]].c == c;
	}
}

struct Down {
	static constexpr int index = 0;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Yoko>(r, c);
		if (id != N && in[pts::pt[Yoko::index][id]].c == c)
			return pts::pt[Yoko::index][id];
		else return -1;
	}
};

struct Right {
	static constexpr int index = 1;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Tate>(r, c);
		if (id != N && in[pts::pt[Tate::index][id]].r == r)
			return pts::pt[Tate::index][id];
		else return -1;
	}
};
struct Left {
	static constexpr int index = 2;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Tate>(r, c) - 1;
		if (id != -1 && in[pts::pt[Tate::index][id]].r == r)
			return pts::pt[Tate::index][id];
		else return -1;
	}
};
struct Up {
	static constexpr int index = 3;
	static inline int getIce(int r, int c) {
		int id = pts::lower_bound<Yoko>(r, c) - 1;
		if (id != -1 && in[pts::pt[Yoko::index][id]].c == c)
			return pts::pt[Yoko::index][id];
		else return -1;
	}
};
		
inline bool isReachable(int r,int c,int nr,int nc) {
	if (r == nr) {
		if (c < nc) {
			const int id = Right::getIce(r, c);
			return id == -1 || nc < in[id].c;
		}
		else if (nc < c) {
			const int id = Left::getIce(r, c);
			return id == -1 || in[id].c < nc;
		}
		else return true;
	}
	else if (c == nc) {
		if (r < nr) {
			const int id = Down::getIce(r, c);
			return id == -1 || nr < in[id].r;
		}
		else if (nr < r) {
			const int id = Up::getIce(r, c);
			return id == -1 || in[id].r < nr;
		}
		else return true;
	}
	else return false;
}


vector<P> g[MAX_N][4];
vector<P> rg[MAX_N][4];

int dist[MAX_N][4];
int rdist[MAX_N][4];
template<typename dir> 
inline void addArc(const int i, const int j, const int r,const int c) {
	const int id = dir::getIce(r, c);
	if (id != -1) {
		g[i][j].push_back(P{ id,3 - dir::index });
		rg[id][3 - dir::index].push_back(P{ i,j });
	}
}
void buildGraph(){
	for (int i : range(N)) {
		for (int d : range(4)) {
			int r = in[i].r + dr[d];
			int c = in[i].c + dc[d];
			if (pts::isIce(r, c))continue;
			addArc<Down>(i, d, r, c);
			addArc<Up>(i, d, r, c);
			addArc<Left>(i, d, r, c);
			addArc<Right>(i, d, r, c);
		}
	}
}
template<typename dir>
void uku(){
	int id = dir::getIce(S.r, S.c);
	if (id != -1) {
		const int r = in[id].r + dr[3 - dir::index];
		const int c = in[id].c + dc[3 - dir::index];
		dist[id][3 - dir::index] = (S.r != r || S.c != c);
	}
}
constexpr int INF = 1e7;
queue<P> que;
void bfs() {
	uku<Down>();
	uku<Left>();
	uku<Right>();
	uku<Up>();
	for (int i : range(N)) {
		for (int d : range(4)) {
			if (dist[i][d] == 0)que.push(P{ i,d });
		}
	}
	for (int i : range(N)) {
		for (int d : range(4)) {
			if (dist[i][d] == 1)que.push(P{ i,d });
		}
	}
	while (!que.empty()) {
		int i = que.front().r;
		int j = que.front().c;
		que.pop();
		for (auto &it : g[i][j]) {
			int ni = it.r;
			int nj = it.c;
			if (chmin(dist[ni][nj], dist[i][j] + 1)) {
				que.push(it);
			}
		}
	}
	for (int i : range(N)) {
		for (int d : range(4)) {
			const int r = in[i].r + dr[d];
			const int c = in[i].c + dc[d];
			if (isReachable(r, c, T.r, T.c)) {
				rdist[i][d] = 0;
				que.push(P{ i,d });
			}
		}
	}
	while (!que.empty()) {
		int i = que.front().r;
		int j = que.front().c;
		que.pop();
		for (auto &it : rg[i][j]) {
			int ni = it.r;
			int nj = it.c;
			if (chmin(rdist[ni][nj], rdist[i][j] + 1)) {
				que.push(it);
			}
		}
	}
}

//default::min
template<typename SEG>
using SetInitialLeaf = function<void(SEG&, int)>;

template<typename SEG>
using SetInitialSegment = function<void(SEG&, const int, const int)>;

template<typename RET, typename SEG>
using GetSingleSegment = function<RET(SEG&, const int, const int)>;

template<typename RET>
using GetMergedSegment = function<RET(RET, RET)>;

template<typename SEG, typename Q>
using UpdateSingleSegment = function<void(SEG&, Q)>;

SetInitialLeaf<int>
set_leaf = [](int &v, const int id) {
	v = INF;
};

SetInitialSegment<int>
set_segment = [](int &v, const int l, const int r) {
	v = INF;
};

GetSingleSegment<int,int> 
segment_min = [](int &v, const int l, const int r) {
	return v;
};

GetMergedSegment<int>
merge_segment = [](const int l, const int r) {
	return min(l, r);
};

UpdateSingleSegment<int,int>
force_update = [](int &v, int l) {
	v = l;
};

UpdateSingleSegment<int, int>
weak_update = [](int &v, int l) {
	chmin(v, l);
};


template<typename T>
struct BufferManager {
	T *mem;
	int ptr;
	BufferManager(T* mem) {
		ptr = 0;
		this->mem = mem;
	}
	T* get(int m) {
		ptr += m;
		return mem + ptr - m;
	}
	void reset() {
		ptr = 0;
	}
};

namespace NodeBuffer {
	constexpr int BufferSize = 812345;
	using NodeType = int;
	NodeType mem[BufferSize];
	BufferManager<NodeType> buffer(mem);
}

template<typename Node, typename RET>
struct SegmentTree{
	int size;
	Node *seg;
	GetSingleSegment<RET, Node> get_single_segment;
	GetMergedSegment<RET> get_merged_segment;
	void init(int l, int r, SetInitialSegment<Node> init_segment ,SetInitialLeaf<Node> init_leaf ,int k = 0) {
		auto &v = seg[k];
		if (r - l == 1) {
			//葉の時の処理
			init_leaf;
		}
		else if (r - l>1) {
			int m = (l + r) / 2;
			init(l, m, init_segment, init_leaf, k * 2 + 1); 
			init(m, r, init_segment, init_leaf, k * 2 + 2);
			v = get_merged_segment(
				get_single_segment(seg[k * 2 + 1], l, m),
				get_single_segment(seg[k * 2 + 2], m, r)
			);
		}
	}
	SegmentTree(
		int n,
		GetSingleSegment<RET, Node> gss,
		GetMergedSegment<RET> gms,
		SetInitialSegment<Node> sis,
		SetInitialLeaf<Node> sil,
		BufferManager<Node> buf = NodeBuffer::buffer
		) 
		:get_single_segment(gss),
		 get_merged_segment(gms){
		size = 1; while (size<n)size *= 2;
		seg = buf.get(size + 10);
		init(0, size, sis, sil);
	}
#define LQ a,b,k*2+1,l,m
#define RQ a,b,k*2+2,m,r
	RET get(int a, int b, int k, int l, int r) {
		if (a <= l && r <= b)return get_single_segment(seg[k], l, r);
		int m = (l + r) / 2;
		bool ll = !(m <= a || b <= l);
		bool rr = !(r <= a || b <= m);
		RET ret;
		if (ll&&rr)ret = get_merged_segment(get(LQ), get(RQ));
		else if (ll)ret = get(LQ); else ret = get(RQ);
		return ret;
	}
	RET get(int a, int b) { 
		return get(a, b, 0, 0, size);
	}
	template<typename Q>
	void update(int a, int b, int k, int l, int r, UpdateSingleSegment<Node,Q> update_segment, Q value) {
		if (r <= a || b <= l)return;
		if (a <= l && r <= b) {
			update_segment(seg[k], value);
		}
		else {
			int m = (l + r) / 2;
			update(LQ, update_segment, value);
			update(RQ, update_segment, value);
			seg[k] = get_merged_segment(
				get_single_segment(seg[k * 2 + 1], l, m), 
				get_single_segment(seg[k * 2 + 2], m, r)
			);
		}
	}
	template<typename Q>
	void update(int a, UpdateSingleSegment<Node, Q> update_segment, Q value) {
		update(a, a+1, 0, 0, size, update_segment, value);
	}
};

int ret = INF;
void solve_down() {
	constexpr int dir = Down::index;
	constexpr int s = Left::index;
	SegmentTree<int, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = 0; lb < N;) {
		int ub = lb;
		int* pt = pts::pt[Tate::index];
		while (ub < N&&
			in[pt[lb]].r == in[pt[ub]].r) {
			ub++;
		}
		chmin(ret, rdist[pt[lb]][s] + query(0, in[pt[lb]].c) + 1);
		for (int i : range(lb, ub-1)) {
			const int seg_cost = query(in[pt[i]].c + 1, in[pt[i + 1]].c);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[ub - 1]][3 - s] + query(in[pt[ub - 1]].c + 1, Z::id) + 1);
		for (int i : range(lb, ub)) {
			rmq.update(in[pt[i]].c, force_update, dist[pt[i]][dir]);
			rmq.update(in[pt[i]].c + dc[s], weak_update, dist[pt[i]][s]);
			rmq.update(in[pt[i]].c + dc[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}

void solve_right() {
	constexpr int dir = Right::index;
	constexpr int s = Up::index;
	SegmentTree<int, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = 0; lb < N;) {
		int ub = lb;
		int* pt = pts::pt[Yoko::index];
		while (ub < N&&
			in[pt[lb]].c == in[pt[ub]].c) {
			ub++;
		}
		chmin(ret, rdist[pt[lb]][s] + query(0, in[pt[lb]].r) + 1);
		for (int i : range(lb, ub - 1)) {
			const int seg_cost = query(in[pt[i]].r + 1, in[pt[i + 1]].r);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[ub - 1]][3 - s] + query(in[pt[ub - 1]].r + 1, Z::id) + 1);
		for (int i : range(lb, ub)) {
			rmq.update(in[pt[i]].r, force_update, dist[pt[i]][dir]);
			rmq.update(in[pt[i]].r + dr[s], weak_update, dist[pt[i]][s]);
			rmq.update(in[pt[i]].r + dr[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}

void solve_up() {
	constexpr int dir = Up::index;
	constexpr int s = Left::index;
	SegmentTree<int, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = N-1; lb >= 0;) {
		int ub = lb;
		int* pt = pts::pt[Tate::index];
		while (ub >=0 &&
			in[pt[lb]].r == in[pt[ub]].r) {
			ub--;
		}
		chmin(ret, rdist[pt[ub+1]][s] + query(0, in[pt[ub+1]].c) + 1);
		for (int i : range(ub+1, lb)) {
			const int seg_cost = query(in[pt[i]].c + 1, in[pt[i + 1]].c);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[lb]][3 - s] + query(in[pt[lb]].c + 1, Z::id) + 1);
		for (int i : range(ub+1, lb+1)) {
			rmq.update(in[pt[i]].c, force_update, dist[pt[i]][dir]);
			rmq.update(in[pt[i]].c + dc[s], weak_update, dist[pt[i]][s]);
			rmq.update(in[pt[i]].c + dc[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}

void solve_left() {
	constexpr int dir = Left::index;
	constexpr int s = Up::index;
	SegmentTree<int, int> rmq(Z::id, segment_min, merge_segment, set_segment, set_leaf);
	auto query = [&](int l, int r) {
		if (r - l >= 1)return rmq.get(l, r);
		else return INF;
	};
	for (int lb = N-1; lb >= 0;) {
		int ub = lb;
		int* pt = pts::pt[Yoko::index];
		while (ub >=0&&
			in[pt[lb]].c == in[pt[ub]].c) {
			ub--;
		}
		chmin(ret, rdist[pt[ub+1]][s] + query(0, in[pt[ub+1]].r) + 1);
		for (int i : range(ub+1, lb)) {
			const int seg_cost = query(in[pt[i]].r + 1, in[pt[i + 1]].r);
			chmin(ret, rdist[pt[i]][3 - s] + seg_cost + 1);
			chmin(ret, rdist[pt[i + 1]][s] + seg_cost + 1);
		}
		chmin(ret, rdist[pt[lb]][3 - s] + query(in[pt[lb]].r + 1, Z::id) + 1);
		for (int i : range(ub+1, lb+1)) {
			rmq.update(in[pt[i]].r, force_update, dist[pt[i]][dir]);
			rmq.update(in[pt[i]].r + dr[s], weak_update, dist[pt[i]][s]);
			rmq.update(in[pt[i]].r + dr[3 - s], weak_update, dist[pt[i]][3 - s]);
		}
		lb = ub;
	}
	NodeBuffer::buffer.reset();
}
inline bool isReachableWithHop(int r,int c) {
	return (isReachable(r, c, r, T.c) &&
		isReachable(r, T.c, T.r, T.c)) ||
		(isReachable(r, c, T.r, c) &&
			isReachable(T.r, c, T.r, T.c));
}

int main() {
	while (input()) {
		pts::build();
		if (isReachableWithHop(S.r, S.c)) {
			cout << 0 << endl; continue;
		}
		for (int i : range(N)) {
			for (int j : range(4)) {
				g[i][j].clear();
				rg[i][j].clear();
				dist[i][j] = INF;
				rdist[i][j] = INF;
			}
		}
		buildGraph();
		bfs();
		
		for (int i : range(N)) {
			for (int j : range(4)) {
				const int r = in[i].r + dr[j];
				const int c = in[i].c + dc[j];
				if (isReachableWithHop(r, c)) {
					chmin(ret, dist[i][j]);
					isReachableWithHop(r, c);
				}
			}
		}

		for (int i : range(N)) {
			if (isReachable(S.r,S.c,S.r,in[i].c)) {
				const int r = S.r;
				const int c = in[i].c;
				if (Down::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Down::index] + 1);
				if (Left::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Left::index] + 1);

				if (Right::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Right::index] + 1);
				if (Up::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Up::index] + 1);
			}
			if (isReachable(S.r, S.c, in[i].r, S.c)) {
				const int r = in[i].r;
				const int c = S.c;
				if (Down::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Down::index] + 1);
				if (Left::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Left::index] + 1);
				if (Right::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Right::index] + 1);
				if (Up::getIce(r, c) == i)
					chmin(ret, rdist[i][3 - Up::index] + 1);
			}
		}
		solve_down();
		solve_up();
		solve_left();
		solve_right();
		if (ret == INF)cout << -1 << endl;
		else cout << ret << endl;
	}
	return 0;
}
accuracy: 0.025
time_ms: 50
memory_kb: 155560
final_rank: 20