#include <bits/stdc++.h>

#define rep(i, n) for (ll i = 0; i < (n); i++)
#define rep2(i, a, b) for (ll i = (a); i < (b); i++)
#define chmax(x, v) do { x = max(x, v); } while(0)
typedef uint64_t ull;
typedef int64_t ll;
typedef std::pair<ll, ll> PLL;

using namespace std;

// p: 左端が最も右側にある区間
// q: 右端が最も左側にある区間
//
// -----------
//        <-----p---
//   -q----->
//    -------------
//       --------------
//     -----------------------
//
// 1. p と q を同じグループ A にする場合
//    それ以外の区間を p と q に追加してもグループ A の長さは変わらない
//    ので、p と q 以外でもっとも長い区間を B とすれば良い。
//
// *******---*****************
// *******<--*****************
// *******-->*****************
// *******---*****************
// *******---*****************
// *******---*****************
//
//  2. p をグループA、 q をグループBにする場合
//
//  グループA: 区間iを追加する場合、左端はL_p、右端をR_iなので、その長さは a_i = max(R_i - L_p, 0)
//  グループB: 区間iを追加する場合、左端はL_i、右端をR_qなので、その長さは b_i = max(R_q - L_i, 0)
//
//  a_i の大きいほうから K 個をグループAに追加する（ただしa_iが同じ場合は、b_iが小さいものから）。
//  0 <= K <= N-2 で試す

// Segment Tree {{{
template <typename T>
class SegTree {
 private:
    int _n;
    T _init_val;
    std::vector<T> _data;
    std::function<T(T, T)> _f;

    T _query(int a, int b, int k, int l, int r) {
        // [a b)と[l r]が交差しない
        if (r <= a || b <= l) return _init_val;

        // [a b)が[l r]を含む
        if (a <= l && r <= b) return _data[k];

        T vl = _query(a, b, k*2+1, l, (l+r)/2);
        T vr = _query(a, b, k*2+2, (l+r)/2, r);

        return _f(vl, vr);
    }

 public:
    SegTree(int n, T init_val, std::function<T(T, T)> f) {
        _init_val = init_val;
        _n = 1;
        _f = f;

        while (_n < n)
            _n *= 2;
        _data.resize(2 * _n, init_val);
    }

    T get(int k) {
        return _data[k + _n - 1];
    }

    void update(int k, T a) {
        k += _n-1;
        _data[k] = a;
        while (k > 0) {
            k = (k-1)/2;
            _data[k] = _f(_data[k*2+1], _data[k*2+2]);
        }
    }

    // [a b)の範囲でfを適用
    T query(int a, int b) {
        return _query(a, b, 0, 0, _n);
    }

    // 先頭からチェックし，はじめてxを満たしたインデックス
    int lower_bound(T x) {
        return _lower_bound(x, 0);
    }

    int _lower_bound(T x, int k) {
        if (k >= _n-1) {
            return k - (_n - 1);  // 葉
        } else if (_data[k] < x) {
            return _n;  // 該当なし
        } else if (x <= _data[k * 2 + 1]) {
            return _lower_bound(x, k * 2 + 1);
        } else {
            return _lower_bound(x - _data[k * 2 + 1] , k * 2 + 2);
        }
    }
};
// }}}

struct P { ll l, r; }; // rは開区間

ll N;
vector<P> v;

signed main() {
  cin >> N;
  rep(i, N) {
    ll l, r;
    cin >> l >> r;
    v.push_back({l,r+1});
  }

  ll p = 0, q = 0;
  rep(i,N){
    if (v[i].l > v[p].l)
      p = i;
    if (v[i].r < v[q].r)
      q = i;
  }

  // printf("p=%d q=%d\n", p, q);

  if (p == q) {
    ll lenA = v[p].r - v[p].l, lenB = -1;
    rep(id,N)
      if (id != p)
        chmax(lenB, v[id].r - v[id].l);
    cout << lenA + lenB << endl;
    return 0;
  }

  ll ans = -1;

  // 戦略1
  {
    ll lenA = max(min(v[q].r, v[q].r) - max(v[p].l, v[q].l), (ll)0), lenB = -1;
    rep(id,N)
      if (id != p && id != q)
        chmax(lenB, v[id].r - v[id].l);
    chmax(ans, lenA + lenB);
    // printf("strategy1 ans=%d\n", lenA + lenB);
  }

  // 戦略2
  {
    struct T { ll a,b; };
    vector<T> sec;
    rep(id, N) {
      if (id != p && id != q)
        sec.push_back({max(v[id].r - v[p].l, (ll)0), max(v[q].r - v[id].l, (ll)0)});
    }
    sort(begin(sec), end(sec), [](const T &lhs, const T &rhs){
        if (lhs.a == rhs.a)
          return lhs.b < rhs.b;
        else
          return lhs.a > rhs.a;
        });

    ll lenP = v[p].r - v[p].l;
    ll lenQ = v[q].r - v[q].l;
    SegTree<ll> \
      az(N, lenP, [](const ll &x, const ll &y) { return min(x,y); }), \
      bz(N, lenQ, [](const ll &x, const ll &y) { return min(x,y); });

    // まずは、N-2個すべてをBに追加しておく
    rep(i,sec.size()) {
      bz.update(i, sec[i].b);
    }
    chmax(ans, az.query(0, N) + bz.query(0, N));
    // printf("strategy2 #items=%d, ans=%d\n", 0, az.query(0, N) + bz.query(0, N));

    rep(i,sec.size()) {
      bz.update(i, lenQ);
      az.update(i, sec[i].a);
      chmax(ans, az.query(0, N) + bz.query(0, N));
      // printf("strategy2 #items=%d, ans=%d\n", i+1, az.query(0, N) + bz.query(0, N));
    }
  }

  cout << ans << endl;
  return 0;
}


Measured memory_bytes: 7536