#include <algorithm>
#include <cassert>
#include <iostream>
#include <vector>
using namespace std;

struct SCC {
    int V = 0;
    vector<vector<int>> adj;
    vector<int> tour_index, low_link;
    int tour;

    vector<int> stack;
    vector<bool> in_stack;
    int S = 0;

    vector<vector<int>> components;
    vector<int> which_component;

    SCC(int v = 0) {
        init(v);
    }

    SCC(const vector<vector<int>> &_adj) {
        init(_adj);
    }

    void init(int v) {
        V = v;
        adj.assign(V, {});
    }

    void init(const vector<vector<int>> &_adj) {
        adj = _adj;
        V = adj.size();
    }

    void add_edge(int a, int b) {
        adj[a].push_back(b);
    }

    // Tarjan's algorithm.
    void dfs(int node) {
        tour_index[node] = tour++;
        low_link[node] = tour_index[node];
        stack[S++] = node;
        in_stack[node] = true;

        for (int neighbor : adj[node])
            if (tour_index[neighbor] < 0) {
                // neighbor is part of our subtree.
                dfs(neighbor);
                low_link[node] = min(low_link[node], low_link[neighbor]);
            } else if (in_stack[neighbor]) {
                // neighbor is our tree ancestor, so it's a candidate for low_link.
                low_link[node] = min(low_link[node], tour_index[neighbor]);
            }

        if (low_link[node] == tour_index[node]) {
            // node is the highest node in an SCC, which includes everything on the stack up to it.
            components.emplace_back();
            vector<int> &component = components.back();
            int x;

            do {
                assert(S > 0);
                x = stack[--S];
                in_stack[x] = false;
                which_component[x] = (int) components.size() - 1;
                component.push_back(x);
            } while (x != node);
        }
    }

    void build() {
        tour_index.assign(V, -1);
        low_link.assign(V, -1);
        which_component.assign(V, -1);

        S = 0;
        stack.resize(V);
        in_stack.assign(V, false);
        tour = 0;

        // Note that Tarjan's algorithm provides the SCCs in reverse topological order.
        components = {};

        for (int i = 0; i < V; i++)
            if (tour_index[i] < 0)
                dfs(i);
    }
};

struct two_sat {
    int n = 0;
    vector<vector<int>> adj;
    vector<bool> assignment;
    SCC scc;

    int inv(int var) {
        return var ^ 1;
    }

    int new_var() {
        adj.emplace_back();
        adj.emplace_back();
        return 2 * n++;
    }

    void implies(int a, int b) {
        adj[a].push_back(b);
        adj[inv(b)].push_back(inv(a));
    }

    void either(int a, int b) {
        adj[inv(a)].push_back(b);
        adj[inv(b)].push_back(a);
    }

    void set_value(int a) {
        adj[inv(a)].push_back(a);
    }

    void equal(int a, int b) {
        implies(a, b);
        implies(inv(a), inv(b));
    }

    void unequal(int a, int b) {
        implies(a, inv(b));
        implies(inv(a), b);
    }

    // Warning: this only creates an implication in the negative direction. It is still possible for
    // a = b = true with and_var = false. In particular, it does not work to call set_value on inv(and_var).
    int create_and(int a, int b) {
        if (a < 0 || b < 0) return max(a, b);
        int result = new_var();
        implies(result, a);
        implies(result, b);
        return result;
    }

    // Warning: this only creates an implication in the positive direction. It is still possible for
    // a = b = false with or_var = true. In particular, it does not work to call set_value on or_var.
    int create_or(int a, int b) {
        if (a < 0 || b < 0) return max(a, b);
        int result = new_var();
        implies(a, result);
        implies(b, result);
        return result;
    }

    int create_at_most_one(int a, int b) {
        if (a < 0 || b < 0) return max(a, b);
        either(inv(a), inv(b));
        return create_or(a, b);
    }

    template<typename T_iterable>
    int create_at_most_one(const T_iterable &vars) {
        int aux = -1;

        for (int var : vars)
            aux = create_at_most_one(aux, var);

        return aux;
    }

    bool solve() {
        scc.init(adj);
        scc.build();

        for (int i = 0; i < n; i++)
            if (scc.which_component[2 * i] == scc.which_component[2 * i + 1])
                return false;

        assignment.resize(2 * n);
        vector<bool> done(n, false);

        // Tarjan's algorithm provides the SCCs in reverse topological order.
        for (auto &component : scc.components)
            for (int x : component) {
                assignment[x] = !done[x / 2];
                done[x / 2] = true;
            }

        for (int i = 0; i < n; i++)
            assert(assignment[2 * i] ^ assignment[2 * i + 1]);

        return true;
    }
};


const int INF = 1e9 + 5;

int N, T;
vector<pair<int, int>> sorted;
two_sat solver;
vector<int> tree;

void build_tree() {
    T = 2 * N;
    tree.assign(2 * T, -1);

    for (int t = 1; t < 2 * T; t++)
        tree[t] = solver.new_var();

    for (int t = 2; t < 2 * T; t++)
        solver.implies(tree[t / 2], tree[t]);

    for (int t = 0; t < T; t++)
        solver.implies(tree[T + t], solver.inv(sorted[t].second));
}

void add_range(int from, int start, int end) {
    for (start += T, end += T; start < end; start /= 2, end /= 2) {
        if (start & 1)
            solver.implies(from, tree[start++]);

        if (end & 1)
            solver.implies(from, tree[--end]);
    }
}

bool possible(int d) {
    solver = two_sat();

    for (int i = 0; i < N; i++)
        solver.new_var();

    build_tree();

    for (int i = 0; i < T; i++) {
        int start = lower_bound(sorted.begin(), sorted.end(), make_pair(sorted[i].first - d + 1, 0)) - sorted.begin();
        int end = lower_bound(sorted.begin(), sorted.end(), make_pair(sorted[i].first + d, 0)) - sorted.begin();
        add_range(sorted[i].second, start, i);
        add_range(sorted[i].second, i + 1, end);
    }

    return solver.solve();
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    cin >> N;

    for (int i = 0; i < N; i++) {
        int x, y;
        cin >> x >> y;
        sorted.emplace_back(x, 2 * i);
        sorted.emplace_back(y, 2 * i + 1);
    }

    sort(sorted.begin(), sorted.end());
    int low = 0, high = INF;

    while (low < high) {
        int mid = (low + high + 1) / 2;

        if (possible(mid))
            low = mid;
        else
            high = mid - 1;
    }

    cout << low << '\n';
}


Measured memory_bytes: 27252