#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
using namespace std;
// #define int long long
// #define double long double
#define rep(i,n) for (int i=0; i<(int)(n); ++i)
#define rep1(i,n) for (int i=1; i<(int)(n); ++i)
#define repeq(i,n) for (int i=0; i<=(int)(n); ++i)
#define rep1eq(i,n) for (int i=1; i<=(int)(n); ++i)
#define rrep(i,n) for (int i=(int)(n)-1; i>=0; --i)
#define rrep1(i,n) for (int i=(int)(n)-1; i>0; --i)
#define rrepeq(i,n) for (int i=(int)(n); i>=0; --i)
#define rrep1eq(i,n) for (int i=(int)(n); i>0; --i)
#define REP(i,a,b) for (int i=(int)(a); i<=(int)(b); ++i)
#define RREP(i,a,b) for (int i=(int)(a); i>=(int)(b); --i)
#define ALL(a) (a).begin(), (a).end()
#define RALL(a) (a).rbegin(), (a).rend()
using ll = long long;
using vi = vector<int>;
using vl = vector<ll>;
using vb = vector<bool>;
template<typename T> using Graph = vector<vector<T>>;
template<typename T> using Spacial = vector<vector<vector<T>>>;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
const int MOD = 1e9+7;
const int MOD2 = 998244353;
// const double EPS = 1e-9;
const int dx[4] = {1, 0, -1, 0};
const int dy[4] = {0, 1, 0, -1};
string interval[2] = {" ", "\n"}; // {" ", "\n"}

template<typename T> struct is_plural : false_type{};
template<typename T1, typename T2> struct is_plural<pair<T1, T2>> : true_type{};
template<typename T> struct is_plural<vector<T>> : true_type{};
template<typename T> struct is_plural<complex<T>> : true_type{};
 
template<typename T1, typename T2> istream &operator>>(istream &is, pair<T1, T2> &p) { return is >> p.first >> p.second; }
template<typename T1, typename T2> ostream &operator<<(ostream &os, const pair<T1, T2> &p) { return os << p.first << " " << p.second; }
template<typename T> istream &operator>>(istream &is, vector<T> &vec) { for (auto itr = vec.begin(); itr != vec.end(); ++itr) is >> *itr; return is; }
template<typename T> ostream &operator<<(ostream &os, const vector<T> &vec) { if (vec.empty()) return os; bool pl = is_plural<T>(); os << vec.front(); for (auto itr = ++vec.begin(); itr != vec.end(); ++itr) os << interval[pl] << *itr; return os; }
 
bool CoutYN(bool a, string y = "Yes", string n = "No") { cout << (a ? y : n) << "\n"; return a; }

template<typename T1, typename T2> inline bool chmax(T1 &a, T2 b) { return a < b && (a = b, true); }
template<typename T1, typename T2> inline bool chmin(T1 &a, T2 b) { return a > b && (a = b, true); }

long long modpow(int a, long long n, int mod = MOD) { long long ret = 1; do { if (n & 1) ret = ret * a % mod; a = 1LL * a * a % mod; } while (n >>= 1); return ret; }

template<typename T> T GCD(T a, T b) { return b ? GCD(b, a%b) : a; }
template<typename T> T LCM(T a, T b) { return a / GCD(a, b) * b; }

template<typename T1, typename T2> bool CompareBySecond(pair<T1, T2> a, pair<T1, T2> b) { return a.second != b.second ? a.second < b.second : a.first < b.first; }
template<typename T1, typename T2> bool CompareByInverse(pair<T1, T2> a, pair<T1, T2> b) { return a.first != b.first ? a.first < b.first : a.second > b.second; }


/* -------- <templates end> -------- */


template<typename Monoid, typename OperatorMonoid = Monoid>
struct LazySegmentTree {
  using F = function<Monoid(Monoid, Monoid)>;
  using G = function<Monoid(Monoid, OperatorMonoid)>;
  using H = function<OperatorMonoid(OperatorMonoid, OperatorMonoid)>;

  int sz, height;
  vector<Monoid> data;
  vector<OperatorMonoid> lazy;
  const F f;
  const G g;
  const H h;
  const Monoid M1;
  const OperatorMonoid OM0;

  LazySegmentTree(int n, const F f, const G g, const H h, const Monoid &M1, const OperatorMonoid OM0) : f(f), g(g), h(h), M1(M1), OM0(OM0) {
    sz = 1;
    height = 0;
    while (sz < n) sz <<= 1, ++height;
    data.assign(2*sz, M1);
    lazy.assign(2*sz, OM0);
  }

  void set(int k, const Monoid &x) {
    data[k+sz] = x;
  }

  void build() {
    for (int k = sz-1; k>0; --k) {
      data[k] = f(data[2*k+0], data[2*k+1]);
    }
  }

  inline void propagate(int k) {
    if (lazy[k] != OM0) {
      lazy[2*k+0] = h(lazy[2*k+0], lazy[k]);
      lazy[2*k+1] = h(lazy[2*k+1], lazy[k]);
      data[k] = reflect(k);
      lazy[k] = OM0;
    }
  }

  inline Monoid reflect(int k) {
    return lazy[k] == OM0 ? data[k] : g(data[k], lazy[k]);
  }

  inline void recalc(int k) {
    while (k >>= 1) data[k] = f(reflect(2*k+0), reflect(2*k+1));
  }

  inline void thrust(int k) {
    for (int i = height; i>0; --i) propagate(k >> i);
  }

  void update(int a, int b, const OperatorMonoid &x) {
    thrust(a += sz);
    thrust(b += sz-1);
    for (int l = a, r = b + 1; l < r; l >>= 1, r >>= 1) {
      if (l & 1) lazy[l] = h(lazy[l], x), ++l;
      if (r & 1) --r, lazy[r] = h(lazy[r], x);
    }
    recalc(a);
    recalc(b);
  }

  Monoid query(int a, int b) {
    thrust(a += sz);
    thrust(b += sz-1);
    Monoid L = M1, R = M1;
    for (int l = a, r = b + 1; l < r; l >>= 1, r >>= 1) {
      if (l & 1) L = f(L, reflect(l++));
      if (r & 1) R = f(reflect(--r), R);
    }
    return f(L, R);
  }

  Monoid operator[](const int &k) {
    return query(k, k+1);
  }

  template<typename C>
  int find_subtree(int a, const C &check, Monoid &M, bool type) {
    while (a < sz) {
      propagate(a);
      Monoid nxt = type ? f(reflect(2*a+type), M) : f(M, reflect(2*a+type));
      if (check(nxt)) a = 2*a + type;
      else M = nxt, a = 2*a+1 - type;
    }
    return a - sz;
  }

  template<typename C>
  int find_first(int a, const C &check) {
    Monoid L = M1;
    if (a <= 0) {
      if (check(f(L, reflect(1)))) return find_subtree(1, check, L, false);
      return -1;
    }
    thrust(a + sz);
    int b = sz;
    for (a += sz, b += sz; a < b; a >>= 1, b >>= 1) {
      if (a & 1) {
        Monoid nxt = f(L, reflect(a));
        if (check(nxt)) return find_subtree(a, check, L, false);
        L = nxt;
        ++a;
      }
    }
    return -1;
  }

  template<typename C>
  int find_last(int b, const C &check) {
    Monoid R = M1;
    if (b >= sz) {
      if (check(f(reflect(1), R))) return find_subtree(1, check, R, true);
      return -1;
    }
    thrust(b + sz-1);
    int a = sz;
    for (b += sz; a < b; a >>= 1, b >>= 1) {
      if (b & 1) {
        Monoid nxt = f(reflect(--b), R);
        if (check(nxt)) return find_subtree(b, check, R, true);
        R = nxt;
      }
    }
    return -1;
  }
};

struct Point {
  int x, y;

  Point(int x, int y) : x(x), y(y) {}

  int operator-(const Point &p) const {
    return abs(x - p.x) + abs(y - p.y);
  }
};

void solve() {
  int n, a, b; cin >> n >> a >> b; --a, --b;

  vector<Point> points;
  rep(i,n) {
    int x, y; cin >> x >> y;
    points.emplace_back(x, y);
  }

  map<ll, vector<pll>> Ldist, Rdist;
  Point L(0, 0), R(1e9+1, 0);
  
  rep(i,n) {
    Ldist[points[i] - L].emplace_back(points[i].x, i);
    Rdist[points[i] - R].emplace_back(points[i].x, i);
  }

  map<ll, int> Lidx, Ridx;
  int lidx = 0, ridx = 0;

  for (auto &vec : Ldist) {
    sort(ALL(vec.second));
    Lidx[vec.first] = lidx;
    lidx += vec.second.size();
  }
  for (auto &vec : Rdist) {
    sort(ALL(vec.second));
    Ridx[vec.first] = ridx;
    ridx += vec.second.size();
  }

  auto f = [](bool a, bool b) { return a & b; };
  LazySegmentTree<bool, bool> Lseg(n, f, f, f, false, false), Rseg(n, f, f, f, false, false);
  auto c = [](bool a) { return !a; };

  ll dist = points[a] - points[b];

  queue<tuple<int, bool, bool>> que;
  que.emplace(a, true, true);
  vb seen(n, false);

  ll ans = 0;

  while (!que.empty()) {
    int v; bool l, r;
    tie(v, l, r) = que.front(); que.pop();
    if (seen[v]) continue;
    seen[v] = true;

    ll lx = points[v].x - dist;
    ll mx = points[v].x;
    ll rx = points[v].x + dist;

    ll ld = points[v] - L;

    if (Ldist.count(ld - dist)) {
      auto &vec = Ldist[ld - dist];
      auto litr = lower_bound(ALL(vec), pll(lx, -1));
      auto ritr = upper_bound(ALL(vec), pll(mx, n));

      if (litr != ritr) {
        ans += ritr - litr;

        if (l) {
          int add = Lidx[ld - dist];
          int lidx = Lseg.find_first(add + (litr - vec.begin()), c) - add;
          int ridx = Lseg.find_last(add + (ritr - vec.begin()), c) - add;

          if (lidx <= ridx) {
            que.emplace(vec[lidx].second, true, true);
            if (lidx != ridx) que.emplace(vec[ridx].second, true, true);
            REP(j,lidx+1,ridx-1) {
              que.emplace(vec[j].second, false, true);
            }
            Lseg.update(lidx, ridx + 1, true);
          }
        }
      }
    }

    if (Ldist.count(ld + dist)) {
      auto &vec = Ldist[ld + dist];
      auto litr = lower_bound(ALL(vec), pll(mx, -1));
      auto ritr = upper_bound(ALL(vec), pll(rx, n));

      if (litr != ritr) {
        ans += ritr - litr;

        if (l) {
          int add = Lidx[ld + dist];
          int lidx = Lseg.find_first(add + (litr - vec.begin()), c) - add;
          int ridx = Lseg.find_last(add + (ritr - vec.begin()), c) - add;

          if (lidx <= ridx) {
            que.emplace(vec[lidx].second, true, true);
            if (lidx != ridx) que.emplace(vec[ridx].second, true, true);
            REP(j,lidx+1,ridx-1) {
              que.emplace(vec[j].second, false, true);
            }
            Lseg.update(lidx, ridx + 1, true);
          }
        }
      }
    }

    ll rd = points[v] - R;

    if (Rdist.count(rd - dist)) {
      auto &vec = Rdist[rd - dist];
      auto litr = upper_bound(ALL(vec), pll(mx, n));
      auto ritr = lower_bound(ALL(vec), pll(rx, -1));

      if (litr != ritr) {
        ans += ritr - litr;

        if (r) {
          int add = Ridx[rd - dist];
          int lidx = Rseg.find_first(add + (litr - vec.begin()), c) - add;
          int ridx = Rseg.find_last(add + (ritr - vec.begin()), c) - add;

          if (lidx <= ridx) {
            que.emplace(vec[lidx].second, true, true);
            if (lidx != ridx) que.emplace(vec[ridx].second, true, true);
            REP(j,lidx+1,ridx-1) {
              que.emplace(vec[j].second, true, false);
            }
            Rseg.update(lidx, ridx + 1, true);
          }
        }
      }
    }

    if (Rdist.count(rd + dist)) {
      auto &vec = Rdist[rd + dist];
      auto litr = upper_bound(ALL(vec), pll(lx, n));
      auto ritr = lower_bound(ALL(vec), pll(mx, -1));

      if (litr != ritr) {
        ans += ritr - litr;

        if (r) {
          int add = Ridx[rd + dist];
          int lidx = Rseg.find_first(add + (litr - vec.begin()), c) - add;
          int ridx = Rseg.find_last(add + (ritr - vec.begin()), c) - add;

          if (lidx <= ridx) {
            que.emplace(vec[lidx].second, true, true);
            if (lidx != ridx) que.emplace(vec[ridx].second, true, true);
            REP(j,lidx+1,ridx-1) {
              que.emplace(vec[j].second, true, false);
            }
            Rseg.update(lidx, ridx + 1, true);
          }
        }
      }
    }
  }

  cout << ans / 2 << endl;
}


/* -------- <programs end> -------- */


signed main() {
  cin.tie(nullptr);
  ios::sync_with_stdio(false);
  cout << fixed << setprecision(10);
  solve();
  return 0;
}


Measured memory_bytes: 52548