#include <map>
#include <cstdio>

using namespace std;
typedef long long int LL;
const int Max_N(100050);

void Get_Val(int &Ret)
{
	Ret = 0;
	char ch;
	while (ch = getchar(), ch > '9' || ch < '0')
		;
	do
	{
		(Ret *= 10) += ch - '0';
	}
	while (ch = getchar(), ch >= '0' && ch <= '9');
}

constexpr LL Abs(LL x)
{
	return x >= 0LL ? x : -x;
}

/*
若d(i, j) = d(a, b)就连一条(i, j)的无向边。那么指南针的状态可以用一条无向边来表示，指南针状态的改变就是移动到了一条相邻的无向边
显然两条无向边在同一联通块中时，就可以互相走到
考虑从a点出发BFS，求出a点和b点所在的联通块，然后求出联通块中的边数即可。这些操作都可以用线段树优化
*/

struct point
{
	LL x, y;
};
int N, All[Max_N];
LL Dis;
point V[Max_N];

#define LCH (segt[cur].lch)
#define RCH (segt[cur].rch)
#define REC (segt[cur].rec)

struct node
{
	int lch, rch, rec;
};
int tot, A, B;
bool COUNT;
node segt[(Max_N << 1) * 40];
map<LL, int> rootX, rootY;

inline void pushup(int cur)
{
	if (COUNT)
		REC = segt[LCH].rec + segt[RCH].rec;
	else
		REC = (segt[LCH].rec ? segt[LCH].rec : segt[RCH].rec);
}

void insert(int &cur, LL p, int r = 1, LL LEFT = -1000000000LL, LL RIGHT = +2000000000LL)
{
	if (!cur)
		segt[++tot] = segt[cur], cur = tot;
	if (LEFT == RIGHT)
	{
		if (COUNT)
			++REC;
		else
			REC = r;
		return;
	}
	LL MID = LEFT + ((RIGHT - LEFT) >> 1LL);
	p <= MID ? insert(LCH, p, r, LEFT, MID) : insert(RCH, p, r, MID + 1LL, RIGHT);
	pushup(cur);
}

int query(int &cur, LL l, LL r, LL LEFT = -1000000000LL, LL RIGHT = +2000000000LL)
{
	l = max(l, LEFT), r = min(r, RIGHT);
	if (l > r)
		return 0;
	if (!cur)
		return 0;
	if (LEFT == l && RIGHT == r)
		return REC;
	LL MID = LEFT + ((RIGHT - LEFT) >> 1LL);
	if (r <= MID)
		return query(LCH, l, r, LEFT, MID);
	else
		if (l > MID)
			return query(RCH, l, r, MID + 1LL, RIGHT);
		else
		{
			if (COUNT)
				return query(LCH, l, MID, LEFT, MID) + query(RCH, MID + 1LL, r, MID + 1LL, RIGHT);
			int x = query(LCH, l, MID, LEFT, MID);
			return x ? x : query(RCH, MID + 1LL, r, MID + 1LL, RIGHT);
		}
}

void DFS(int u)
{
	All[++All[0]] = u, insert(rootX[V[u].x], V[u].y, 0), insert(rootY[V[u].y], V[u].x, 0);
	int rt;
	if (rootX.count(V[u].x - Dis))
	{
		rt = rootX[V[u].x - Dis];
		for (int v;v = query(rt, V[u].y - Dis, V[u].y + Dis);)
			DFS(v);
	}
	if (rootX.count(V[u].x + Dis))
	{
		rt = rootX[V[u].x + Dis];
		for (int v;v = query(rt, V[u].y - Dis, V[u].y + Dis);)
			DFS(v);
	}
	if (rootY.count(V[u].y - Dis))
	{
		rt = rootY[V[u].y - Dis];
		for (int v;v = query(rt, V[u].x - Dis, V[u].x + Dis);)
			DFS(v);
	}
	if (rootY.count(V[u].y + Dis))
	{
		rt = rootY[V[u].y + Dis];
		for (int v;v = query(rt, V[u].x - Dis, V[u].x + Dis);)
			DFS(v);
	}
}

int main()
{
	Get_Val(N), Get_Val(A), Get_Val(B);
	for (int i = 1, x, y;i <= N;++i)
	{
		Get_Val(x), Get_Val(y), V[i].x = x - y, V[i].y = x + y;
		insert(rootX[V[i].x], V[i].y, i), insert(rootY[V[i].y], V[i].x, i);
	}
	Dis = max(Abs(V[A].x - V[B].x), Abs(V[A].y - V[B].y)), DFS(A);
	tot = 0, rootX.clear(), rootY.clear(), COUNT = true;
	LL Ans(0LL);
	for (int i = 1, u, rt;i <= All[0];++i)
	{
		u = All[i];
		if (rootX.count(V[u].x - Dis))
			rt = rootX[V[u].x - Dis], Ans += query(rt, V[u].y - Dis, V[u].y + Dis) - query(rt, V[u].y - Dis, V[u].y - Dis);
		if (rootX.count(V[u].x + Dis))
			rt = rootX[V[u].x + Dis], Ans += query(rt, V[u].y - Dis, V[u].y + Dis) - query(rt, V[u].y + Dis, V[u].y + Dis);
		if (rootY.count(V[u].y - Dis))
			rt = rootY[V[u].y - Dis], Ans += query(rt, V[u].x - Dis, V[u].x + Dis) - query(rt, V[u].x + Dis, V[u].x + Dis);
		if (rootY.count(V[u].y + Dis))
			rt = rootY[V[u].y + Dis], Ans += query(rt, V[u].x - Dis, V[u].x + Dis) - query(rt, V[u].x - Dis, V[u].x - Dis);
		insert(rootX[V[u].x], V[u].y), insert(rootY[V[u].y], V[u].x);
	}
	printf("%lld", Ans);
	return 0;
}

Measured memory_bytes: 95488