Two Array Problem
Difficulty: Hard

In this problem you operate on two arrays of $N$ integers. We will call them the $0^{th}$ and the $1^{st}$ respectively.  
Your goal is just to maintain them under the modification operations, such as:   

+ 1 $id$ $l$ $r$: Reverse the subarray of the $id^{th}$ array, starting at the $l^{th}$ number, ending at the $r^{th}$ number, inclusively;  
+ 2 $id$ $l_1$ $r_1$ $l_2$ $r_2$: Swap two consecutive fragments of the $id^{th}$ array, the first is from the $l_1^{th}$ number to the $r_1^{th}$, the second is from the $l_2^{th}$ number to the $r_2^{th}$;  
+ 3 $l$ $r$: Swap the piece that starts at the $l^{th}$ number and end at the $r^{th}$ one between the $0^{th}$ and the $1^{st}$ array;  
+ 4 $l$ $r$: We consider only the piece from the $l^{th}$ number to the $r^{th}$ one. The numbers in the $0^{th}$ array are $X$-coordinates of some set of points and the numbers in the $1^{st}$ array are $Y$-coordinates of them. For the obtained set of points we would like to place such a circle on a plane that would contain all the points in it and would have the minimal radius. Find this minimal radius.  

**Input Format**  
The first line of input contains two space separated integers $N$ and $M$ denoting the number of integers in arrays and the number of queries respectively.  
The second line contains $N$ space separated integers: the initial elements of the $0^{th}$ array.  
The third line contains $N$ space separated integers: the initial elements of the $1^{th}$ array.  
Then there are $M$ lines containing queries in the format listed above.  

**Output Format**  
For each type-**4** query output the sought minimal radius with **exactly** two symbols after the decimal point precision.  

**Constraints**  
$1 \le N, M \le 10^5$  
All the numbers in arrays are non-negative and don't exceed $10^6$.  
The sum of $R-L$ over the type-**4** queries won't exceed $10^6$.  
In the query of the type 2, $1 \le l_1 \le r_1 < l_2 \le r_2 \le N$.  
In the queries of the types 1, 3, 4, $1 \le l \le r \le N$; $0 \le id < 2$.

**Sample Input**

    10 10
    1 2 3 4 5 6 7 8 9 10
    1 2 3 4 5 6 7 8 9 10
    3 2 6
    1 0 9 9
    4 6 9
    2 0 2 7 9 9
    1 0 3 6
    2 1 2 3 4 5
    1 1 7 10
    2 1 8 8 9 10
    4 6 9
    2 0 2 2 4 6

**Example Output**

    2.12
    2.50



Input Format:

Output Format:

Sample Input:

Sample Output:

Python 3 starter code:


Reference solution (C++):
    #ifdef ssu1
    #define _GLIBCXX_DEBUG
    #endif
    #undef NDEBUG

    #include <algorithm>
    #include <functional>
    #include <numeric>
    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <cstdlib>
    #include <ctime>
    #include <cstring>
    #include <cassert>
    #include <vector>
    #include <list>
    #include <map>
    #include <set>
    #include <deque>
    #include <queue>
    #include <bitset>
    #include <sstream>

    using namespace std;

    #define fore(i, l, r) for(int i = (l); i < (r); ++i)
    #define forn(i, n) fore(i, 0, n)
    #define fori(i, l, r) fore(i, l, (r) + 1)
    #define sz(v) int((v).size())
    #define all(v) (v).begin(), (v).end()
    #define pb push_back
    #define mp make_pair
    #define X first
    #define Y second

    typedef long long li;
    typedef long double ld;
    typedef pair<int, int> pt;

    template<typename T> T abs(T a) { return a < 0 ? -a : a; }
    template<typename T> T sqr(T a) { return a*a; }

    const int INF = (int)1e9;
    const ld EPS = 1e-9;
    const ld PI = 3.1415926535897932384626433832795;

    /*

        This is just to check correctness of input

    */
    int readInt(int l, int r){
        int x;
        if(scanf("%d", &x) != 1){
            fprintf(stderr, "Expected int in range [%d, %d], but haven't found!", l, r);
            throw;
        }
        if(!(l <= x && x <= r)){
            fprintf(stderr, "Expected int in range [%d, %d], but found %d!", l, r, x);
            throw;
        }
        return x;
    }
    int readInt(int l, int r, string name){
        int x;
        if(scanf("%d", &x) != 1){
            fprintf(stderr, "Expected int %s in range [%d, %d], but haven't found!", name.c_str(), l, r);
            throw;
        }
        if(!(l <= x && x <= r)){
            fprintf(stderr, "Expected int %s in range [%d, %d], but found %d!", name.c_str(), l, r, x);
            throw;
        }
        return x;
    }
    li readLong(li l, li r){
        li x;
        if(scanf("%lld", &x) != 1){
            fprintf(stderr, "Expected long long in range [%lld, %lld], but haven't found!", l, r);
            throw;
        }
        if(!(l <= x && x <= r)){
            fprintf(stderr, "Expected long long in range [%lld, %lld], but found %lld!", l, r, x);
            throw;
        }
        return x;
    }
    li readLong(li l, li r, string name){
        li x;
        if(scanf("%lld", &x) != 1){
            fprintf(stderr, "Expected long long %s in range [%lld, %lld], but haven't found!", name.c_str(), l, r);
            throw;
        }
        if(!(l <= x && x <= r)){
            fprintf(stderr, "Expected long long %s in range [%lld, %lld], but found %lld!", name.c_str(), l, r, x);
            throw;
        }
        return x;
    }
    const ld __EPS__ = 1e-15;
    ld readDouble(double l, double r){
        double x;
        if(scanf("%lf", &x) != 1){
            fprintf(stderr, "Expected double in range [%lf, %lf], but haven't found!", l, r);
            throw;
        }
        if(!(l <= x + __EPS__ && x <= r + __EPS__)){
            fprintf(stderr, "Expected double in range [%lf, %lf], but found %lf!", l, r, x);
            throw;
        }
        return x;
    }
    ld readDouble(double l, double r, string name){
        double x;
        if(scanf("%lf", &x) != 1){
            fprintf(stderr, "Expected double %s in range [%lf, %lf], but haven't found!", name.c_str(), l, r);
            throw;
        }
        if(!(l <= x + __EPS__ && x <= r + __EPS__)){
            fprintf(stderr, "Expected double %s in range [%lf, %lf], but found %lf!", name.c_str(), l, r, x);
            throw;
        }
        return x;
    }

    struct explicit_treap{
        struct node{
            int cnt, pr, info;
            bool rev;
            node *l, *r, *par;
            node(){
                cnt = 1;
                pr = info = 0;
                rev = false;
                l = r = par = 0;
            }
        }; 
        typedef node* tree;

        tree root;

        explicit_treap(){
            root = 0;
        }

        int random(){
            return ((rand() & ((1 << 15) - 1)) << 15) ^ rand();
        }

        tree allocate(int info){
            tree cur = new node();
            cur->pr = random();
            cur->info = info;
            return cur;
        }

        int get_cnt(tree t){
            return !t ? 0 : t->cnt;
        }

        void rev(tree t){
            if(!t)
                return;
            t->rev ^= 1;
        }

        template<typename T>
        void swap(T& o1, T& o2){
            T tmp = o1;
            o1 = o2;
            o2 = tmp;
        }

        void push(tree t){
            if(!t) return;

            if(t->rev){
                swap(t->l, t->r);
                rev(t->l), rev(t->r);
                t->rev ^= 1;    
            }
        }

        void update(tree t){
            if(t){
                t->cnt = get_cnt(t->l) + get_cnt(t->r) + 1;
                t->par = 0;
            }
        }

        void split(tree t, int key, tree& l, tree& r){
            push(t);
            if(!t){
                l = r = 0;
                return;
            }
            int ckey = get_cnt(t->l);
            if(ckey < key){
                split(t->r, key - ckey - 1, t->r, r);
                l = t;
            }else{
                split(t->l, key, l, t->l);
                r = t;
            }
            update(l), update(r);
        }

        tree merge(tree l, tree r){
            push(l), push(r);
            if(!l || !r)
                return !l ? r : l;
            tree t;
            if(l->pr > r->pr){
                l->r = merge(l->r, r);
                t = l; 
            }else{
                r->l = merge(l, r->l);
                t = r;
            }
            update(t);
            return t;
        }

        void append(int number){
            tree t = allocate(number);
            root = merge(root, t);
        } 

        void reverse(int l, int r){
            assert(0 <= l && l <= r && r < get_cnt(root));
            tree lf_t, mid_t, rg_t;
            split(root, r + 1, mid_t, rg_t);
            split(mid_t, l, lf_t, mid_t);
            assert(get_cnt(mid_t) == r - l + 1);
            rev(mid_t);
            root = merge(lf_t, merge(mid_t, rg_t));
        }

        void swap(int l1, int r1, int l2, int r2){
            if(l1 > l2)
                swap(l1, l2);
            assert(0 <= l1 && l1 <= r1 && r1 < l2 && l2 <= r2 && r2 < get_cnt(root));
            tree p1, p2, p3, p4, p5;
            split(root, r2 + 1, root, p5);
            split(root, l2, root, p4);
            split(root, r1 + 1, root, p3);
            split(root, l1, p1, p2);
            root = merge(p1, merge(p4, merge(p3, merge(p2, p5))));
        }

        void swap(int l, int r, explicit_treap& t2){
            assert(0 <= l && l <= r && r < get_cnt(root));
            assert(0 <= l && l <= r && r < get_cnt(t2.root));

            tree lf_t, mid_t, rg_t;
            split(root, r + 1, mid_t, rg_t);
            split(mid_t, l, lf_t, mid_t);

            tree lf_t2, mid_t2, rg_t2;
            split(t2.root, r + 1, mid_t2, rg_t2);
            split(mid_t2, l, lf_t2, mid_t2);

            assert(get_cnt(mid_t) == r - l + 1);
            assert(get_cnt(mid_t2) == r - l + 1);

            root = merge(lf_t, merge(mid_t2, rg_t));
            t2.root = merge(lf_t2, merge(mid_t, rg_t2));
        }

        void fill_dfs(tree t, vector<int>& order){
            if(!t)
                return;
            push(t);
            fill_dfs(t->l, order);
            order.pb(t->info);
            fill_dfs(t->r, order);
        }

        void fill(int l, int r, vector<int>& order){
            assert(0 <= l && l <= r && r < get_cnt(root));
            tree lf_t, mid_t, rg_t;
            split(root, r + 1, mid_t, rg_t);
            split(mid_t, l, lf_t, mid_t);
            fill_dfs(mid_t, order);
            root = merge(lf_t, merge(mid_t, rg_t));
        }

        void print(){
            vector<int> tmp;
            fill_dfs(root, tmp);
            forn(i, sz(tmp))
                printf("%d ", tmp[i]);
            puts("");
        }
    };

    struct point{
        ld x, y;
        point(){
            x = y = 0;
        }
        point(ld _x, ld _y) : x(_x), y(_y) {}
    };

    point operator - (const point& a, const point& b){
        return point(a.x - b.x, a.y - b.y);
    }

    point operator + (const point& a, const point& b){
        return point(a.x + b.x, a.y + b.y);
    }

    point operator * (const point& a, const ld& b){
        return point(a.x * b, a.y * b);
    }

    ld dot(const point& a, const point& b){
        return a.x * b.x + a.y * b.y;
    }

    ld cross(const point& a, const point& b){
        return a.x * b.y - a.y * b.x;
    }

    bool operator < (const point& o1, const point& o2){
        if(abs(o1.x - o2.x) > EPS)
            return o1.x < o2.x;
        return o1.y < o2.y;
    }

    bool operator == (const point& o1, const point& o2){
        return abs(o1.x - o2.x) < EPS && abs(o1.y - o2.y) < EPS;
    }

    ld dist(const point& o1, const point& o2){
        return sqrt(sqr(o1.x - o2.x) + sqr(o1.y - o2.y));
    }

    ld det(ld a, ld b, ld c, ld d){
        return a * d - b * c;
    }

    bool inter(ld A1, ld B1, ld C1, ld A2, ld B2, ld C2, point& res){
        ld dt = det(A1, B1, A2, B2),
           dx = -det(C1, B1, C2, B2),
           dy = -det(A1, C1, A2, C2);
        if(abs(dt) < EPS)
            return false;
        res.x = dx / dt,
        res.y = dy / dt;
        return true;
    }

    pair<point, ld> circle(const point& a, const point& b, const point& c){
        point m1 = (a + b) * 0.5,
              m2 = (a + c) * 0.5,
              v1 = b - a,
              v2 = c - a;
        point o;
        assert(inter(v1.x, v1.y, -dot(v1, m1), v2.x, v2.y, -dot(v2, m2), o));
        return make_pair(o, dist(o, a));
    }

    pair<point, ld> min_circle(vector<point> p, point q, point w){
        pair<point, ld> ans((q + w) * 0.5, dist(q, w) * 0.5);
        forn(i, sz(p)){
            if(dist(ans.first, p[i]) > ans.second + EPS){
                ans = circle(p[i], q, w);
            }
        }
        return ans;
    }

    pair<point, ld> min_circle(vector<point> p, point q){
        pair<point, ld> ans((p[0] + q) * 0.5, dist(p[0], q) * 0.5);
        fore(i, 1, sz(p)){
            if(dist(ans.first, p[i]) > ans.second + EPS){
                ans = min_circle(vector<point>(p.begin(), p.begin() + i), p[i], q);
            }
        }
        return ans;
    }

    pair<point, ld> min_circle(vector<point> p){
        if(p.empty())
            return pair<point, ld>();
        if(sz(p) == 1)
            return make_pair(p[0], 0);
        random_shuffle(all(p));
        pair<point, ld> ans((p[0] + p[1]) * 0.5, dist(p[0], p[1]) * 0.5);
        fore(i, 2, sz(p)){
            if(dist(ans.first, p[i]) > ans.second + EPS){
                ans = min_circle(vector<point>(p.begin(), p.begin() + i), p[i]);
            }
        }
        return ans;
    }

    int main(){
    #ifdef ssu1
        assert(freopen("input.txt", "rt", stdin));
        //assert(freopen("output.txt", "wt", stdout));
    #endif
        int n, m; 
        n = readInt(1, 100000);
        m = readInt(1, 100000);
        explicit_treap t[2];
        forn(i, 2){
            forn(j, n){
                int v = readInt(0, 1000000);
                t[i].append(v);
            }
        }
        int sum = 0;
        forn(mi, m){
            int type = readInt(1, 4) - 1;
            if(type == 0){
                int id, l, r;
                id = readInt(0, 1);
                l = readInt(1, n);
                r = readInt(l, n);
                t[id].reverse(l - 1, r - 1);
            }else if(type == 1){
                int id, l1, r1, l2, r2;
                id = readInt(0, 1);
                l1 = readInt(1, n);
                r1 = readInt(l1, n);
                l2 = readInt(r1 + 1, n);
                r2 = readInt(l2, n);
                t[id].swap(l1 - 1, r1 - 1, l2 - 1, r2 - 1);
            }else if(type == 2){
                int l = readInt(1, n), r = readInt(l, n);
                t[0].swap(l - 1, r - 1, t[1]);
            }else if(type == 3){
                vector<int> x, y;
                int l = readInt(1, n), r = readInt(l, n);
                t[0].fill(l - 1, r - 1, x);
                t[1].fill(l - 1, r - 1, y);
                sum += r - l;
                assert(sum <= 1000000);
                vector<point> p(sz(x));
                forn(i, sz(p)){
                    p[i].x = x[i], p[i].y = y[i];
                }
                sort(all(p));
                p.erase(unique(all(p)), p.end());
                ld R = min_circle(p).second;
                printf("%.2lf\n", double(R));
            }
        }
        return 0;
    }