Problem:
Score : 1200 points

Problem Statement

Snuke loves flags.

Snuke is placing N flags on a line.

The i-th flag can be placed at either coordinate x_i or coordinate y_i.

Snuke thinks that the flags look nicer when the smallest distance between two of them, d, is larger. Find the maximum possible value of d.

Constraints

2 ≤ N ≤ 10^{4}

1 ≤ x_i, y_i ≤ 10^{9}

x_i and y_i are integers.

Input

The input is given from Standard Input in the following format:

N
x_1 y_1
:
x_N y_N

Output

Print the answer.

Sample Input 1

3
1 3
2 5
1 9

Sample Output 1

4

The optimal solution is to place the first flag at coordinate 1, the second flag at coordinate 5 and the third flag at coordinate 9. The smallest distance between two of the flags is 4 in this case.

Sample Input 2

5
2 2
2 2
2 2
2 2
2 2

Sample Output 2

0

There can be more than one flag at the same position.

Sample Input 3

22
93 6440
78 6647
862 11
8306 9689
798 99
801 521
188 206
6079 971
4559 209
50 94
92 6270
5403 560
803 83
1855 99
42 504
75 484
629 11
92 122
3359 37
28 16
648 14
11 269

Sample Output 3

17

Solution in Java8 (OpenJDK 1.8.0) (judge verdict: Runtime Error)

// package atcoder.arc.arc069;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.*;

public class Main {
    public static void main(String[] args) {
        InputReader in = new InputReader(System.in);
        PrintWriter out = new PrintWriter(System.out);

        int n = in.nextInt();
        pair = new Point[n][2];
        pt = new ArrayList<>();
        for (int i = 0; i < n ; i++) {
            for (int j = 0; j < 2 ; j++) {
                pair[i][j] = new Point(in.nextInt(), i*2+j);
                pt.add(pair[i][j]);
            }
        }
        Collections.sort(pt, (p, q) -> Long.compare(p.sortValue(), q.sortValue()));

        foundIds = new int[1000];
        M = Integer.highestOneBit(2*n-1)<<1;
        for (int i = 0 ; i < pt.size() ; i++) {
            pt.get(i).id = M-1+i;
        }
        sat = new SAT2(2*M);

        int ok = 0;
        int ng = 1000000000;
        while (ng - ok > 1) {
            int med = (ng + ok) / 2;
            if (canBuild(med)) {
                ok = med;
            } else {
                ng = med;
            }
        }

        out.println(ok);
        out.flush();
    }

    static Point[][] pair;
    static List<Point> pt;
    static SAT2 sat;

    private static boolean canBuild(int range) {
        sat.clear();

        for (int i = 0; i < pair.length ; i++) {
            sat.xor(pair[i][0].id, pair[i][1].id);
        }
        for (int p = 1 ; p < 2*M-2 ; p++) {
            sat.then(p, (p-1)/2);
        }

        int pn = pt.size();
        int L = 0;
        int R = 0;
        for (int i = 0 ; i < pn ; i++) {
            Point c = pt.get(i);
            int p = c.pos;
            while (L < i && pt.get(L).pos + range <= p) {
                L++;
            }
            while (R < pn && pt.get(R).pos < p + range) {
                R++;
            }

            findSegments(L, i);
            for (int j = 0; j < fn; j++) {
                sat.or(sat.not(foundIds[j]), sat.not(c.id));
            }
            findSegments(i+1, R);
            for (int j = 0; j < fn; j++) {
                sat.or(sat.not(foundIds[j]), sat.not(c.id));
            }
        }

        return sat.hasValidAssign();
    }


    static int M;

    static int fn;

    static int[] foundIds;

    static void findSegments(int ql, int qr) {
        fn = 0;
        findSegments(ql, qr, 0, 0, M);
        if (fn >= 30) {
            throw new RuntimeException();
        }
    }

    static void findSegments(int ql, int qr, int idx, int fr, int to) {
        if (qr <= fr || to <= ql) {
            return;
        }

        if (ql <= fr && to <= qr) {
            foundIds[fn++] = idx;
            return;
        }

        int med = (fr + to) / 2;
        findSegments(ql, qr, idx*2+1, fr, med);
        findSegments(ql, qr, idx*2+2, med, to);
    }

    static class Point {
        int id;
        int pos;
        int pos2;

        Point(int p, int i) {
            pos = p;
            pos2 = i;
        }

        long sortValue() {
            return (long)pos * 114514 + pos2;
        }
    }

    public static class DirectedGraph {
        int[] head;
        int[] next;
        int[] to;
        int eidx;

        public DirectedGraph(int v, int e) {
            head = new int[v];
            next = new int[e];
            to = new int[e];
            clear();
        }

        public void clear() {
            Arrays.fill(head, -1);
            eidx = 0;
        }

        public void add(int a, int b) {
            next[eidx] = head[a];
            head[a] = eidx;
            to[eidx++] = b;
        }

        public Iterable<Integer> nexts(int v) {
            final int firstE = head[v];
            return () -> new Iterator<Integer>() {
                int cursor = firstE;

                @Override
                public boolean hasNext() {
                    return cursor != -1;
                }

                @Override
                public Integer next() {
                    int ret = to[cursor];
                    cursor = next[cursor];
                    return ret;
                }
            };
        }
    }

    public static class SAT2 {
        boolean[] visited;
        int[] nodeId;
        int[] rev;
        int rvn;

        int n;
        int vn;
        DirectedGraph graph;
        DirectedGraph revGraph;

        public SAT2(int maxN) {
            n = maxN;
            vn = n * 2;
            graph = new DirectedGraph(vn, 1000000);
            revGraph = new DirectedGraph(vn, 1000000);
            nodeId = new int[vn];
            visited = new boolean[vn];
            rev = new int[vn];
        }

        public void clear() {
            Arrays.fill(nodeId, 0);
            Arrays.fill(visited, false);
            graph.clear();
            revGraph.clear();
            rvn = 0;
        }

        public int not(int v) {
            return v >= n ? v - n : v + n;
        }

        public void xor(int a, int b) {
            // a xor b => [a or b] and [(not a) or (not b)]
            or(a, b);
            or(not(a), not(b));
        }

        public void or(int a, int b) {
            // a or b => [(not a) then b] and [(not b) then a]
            then(not(a), b);
            then(not(b), a);
        }

        public void then(int a, int b) {
            graph.add(a, b);
            revGraph.add(b, a);
        }

        public void doit() {
            for (int i = 0; i < vn ; i++) {
                if (!visited[i]) {
                    dfs(i);
                }
            }
            Arrays.fill(visited, false);
            int id = 0;
            for (int i = rvn-1 ; i >= 0; i--) {
                if (!visited[rev[i]]) {
                    rdfs(rev[i], id);
                    id++;
                }
            }
        }

        private boolean hasValidAssign() {
            doit();
            for (int i = 0; i < n ; i++) {
                if (nodeId[i] == nodeId[i+n]) {
                    return false;
                }
            }
            return true;
        }

        private boolean[] findValidAssign() {
            doit();
            boolean[] ret = new boolean[n];
            for (int i = 0; i < n ; i++) {
                if (nodeId[i] == nodeId[i+n]) {
                    return null;
                }
                ret[i] = nodeId[i] > nodeId[i+n];
            }
            return ret;
        }

        private void dfs(int i) {
            visited[i] = true;
            for (int next : graph.nexts(i)) {
                if (!visited[next]) {
                    dfs(next);
                }
            }
            rev[rvn++] = i;
        }

        private void rdfs(int i, int id) {
            visited[i] = true;
            nodeId[i] = id;
            for (int next : revGraph.nexts(i)) {
                if (!visited[next]) {
                    rdfs(next, id);
                }
            }
        }
    }


    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        private int[] nextInts(int n) {
            int[] ret = new int[n];
            for (int i = 0; i < n; i++) {
                ret[i] = nextInt();
            }
            return ret;
        }

        private int[][] nextIntTable(int n, int m) {
            int[][] ret = new int[n][m];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    ret[i][j] = nextInt();
                }
            }
            return ret;
        }

        private long[] nextLongs(int n) {
            long[] ret = new long[n];
            for (int i = 0; i < n; i++) {
                ret[i] = nextLong();
            }
            return ret;
        }

        private long[][] nextLongTable(int n, int m) {
            long[][] ret = new long[n][m];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    ret[i][j] = nextLong();
                }
            }
            return ret;
        }

        private double[] nextDoubles(int n) {
            double[] ret = new double[n];
            for (int i = 0; i < n; i++) {
                ret[i] = nextDouble();
            }
            return ret;
        }

        private int next() {
            if (numChars == -1)
                throw new InputMismatchException();
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0)
                    return -1;
            }
            return buf[curChar++];
        }

        public char nextChar() {
            int c = next();
            while (isSpaceChar(c))
                c = next();
            if ('a' <= c && c <= 'z') {
                return (char) c;
            }
            if ('A' <= c && c <= 'Z') {
                return (char) c;
            }
            throw new InputMismatchException();
        }

        public String nextToken() {
            int c = next();
            while (isSpaceChar(c))
                c = next();
            StringBuilder res = new StringBuilder();
            do {
                res.append((char) c);
                c = next();
            } while (!isSpaceChar(c));
            return res.toString();
        }

        public int nextInt() {
            int c = next();
            while (isSpaceChar(c))
                c = next();
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = next();
            }
            int res = 0;
            do {
                if (c < '0' || c > '9')
                    throw new InputMismatchException();
                res *= 10;
                res += c-'0';
                c = next();
            } while (!isSpaceChar(c));
            return res*sgn;
        }

        public long nextLong() {
            int c = next();
            while (isSpaceChar(c))
                c = next();
            long sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = next();
            }
            long res = 0;
            do {
                if (c < '0' || c > '9')
                    throw new InputMismatchException();
                res *= 10;
                res += c-'0';
                c = next();
            } while (!isSpaceChar(c));
            return res*sgn;
        }

        public double nextDouble() {
            return Double.valueOf(nextToken());
        }

        public boolean isSpaceChar(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);
        }
    }

    static void debug(Object... o) {
        System.err.println(Arrays.deepToString(o));
    }
}