Problem:
Problem E: 街を駆ける道
ネーヴァ王国には、トタタ族とツテテ族、２種類の民族が暮らしている。トタタ族の最大の特徴は、
酢豚にパイナップルを入れて食べることである。だがツテテ族は、パイナップルに酢豚を入れて食べ
る。こんな２つの民族がお互いに仲良くやっていけるはずもなく、トタタ族とツテテ族は、何百年も
の昔からずっといがみ合いを続けてきた。
そんなある日、ネーヴァ王のもとに、２つの民族から嘆願書が届いた。それによるとトタタ族は、自
分たちが暮らす街Ａと街Ｂのあいだを結ぶ道を建設してほしいらしい。一方でツテテ族も、自分たち
が暮らす街Ｃと街Ｄのあいだを結ぶ道を建設してほしいらしい。
２つの民族が衝突するのを防ぐため、トタタ族が通る道とツテテ族が通る道を交差させることはでき
ない。また、技術的な制約により、２つの街のあいだを一直線に結ぶような道しか建設することはで
きない。つまり、必要ならば街Ａと街Ｂを直接道で結ばずに、いくつかのトタタ族の街を経由して街
Ａと街Ｂを間接的に結ぶことになるだろう（もちろん、ツテテ族の街を経由してはならない）。その
際、トタタ族の街を結ぶ道どうしは交差していてもよい。街Ｃと街Ｄについても同様である。
道を建設するには、その長さに比例したコストがかかる。なので、条件をみたしつつ、できるだけ建
設する道の長さの合計が短くなるようにしたい。さて、長さの最小値はいくつになるだろうか。
Input
N
A
N
B
x
A
,1
y
A
,1
x
A
,2
y
A
,2
.
.
.
x
A
,
N
A
y
A
,
N
A
x
B
,1
y
B
,1
x
B
,2
y
B
,2
.
.
.
x
B
,
N
B
y
B
,
N
B
入力の１行目には、整数
N
A
（2 ≤
N
A
≤ 1,000）と整数
N
B
（2 ≤
N
B
≤ 1,000）が、空白区切りで書かれている。これは、ネーヴァ王国にはトタタ族が暮らす街がNA 個、ツテテ族が暮らす街がNB 個あることをあらわす。初期状態では、どこにも道は建設されていない。
続く
N
A
行には、整数
x
A,i
（-10,000 ≤
x
A,i
≤ 10,000）と整数
y
A,i
（-10,000 ≤
y
A,i
≤ 10,000）が、空白区切りで書かれている。ネーヴァ王国の地理は２次元直交座標平面であらわされ、１＋ i 行目に書かれた整数
x
A,i
と
y
A,i
は、トタタ族が暮らすi 番目の街の位置座標が(
x
A,i
,
y
A,i
) であることをあらわす。(
x
A,1
,
y
A,1
) と(
x
A,2
,
y
A,2
) が、結ぶべき２つの街の座標である。
続く
N
B
行には、整数
x
B,i
（-10,000 ≤
x
B,i
≤ 10,000）と整数
y
B,i
（-10,000 ≤
y
B,i
≤ 10,000）が、空白区切りで書かれている。１＋
N
A
＋ i 行目に書かれた整数
x
B,i
と
y
B,i
は、ツテテ族が暮らすi 番目の街の位置座標が(
x
B,i
,
y
B,i
) であることをあらわす。(
x
B,1
,
y
B,1
) と(
x
B,2
,
y
B,2
) が、結ぶべき２つの街の座標である。
どの２つの街の座標も異なっており、どの３つの街も同一直線上にないと仮定してよい。
Output
問題文の条件をみたすように道を建設したとき、道の長さの合計の最小値を出力せよ。ここで言う
「長さ」とは、ユークリッド距離のことである。ただし、どうやっても条件をみたす道を建設できな
いときは、代わりに-1 を出力せよ。出力は誤差を含んでいてもよいが、真の値との相対誤差が10
-9
未満でなければならない。
Sample Input 1
2 2
0 0
1 1
2 0
2 -1
Sample Output 1
2.414213562373
Sample Input 2
2 3
4 0
0 0
2 3
2 -2
3 1
Sample Output 2
-1
Sample Input 3
5 2
-2 1
1 2
-1 3
-1 5
1 4
0 4
0 0
Sample Output 3
12.359173603117

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
#define rep(i,n) for(int i = 0; i < (n); i++)
using namespace std;
typedef long long ll;

using Real = double;
using Point = complex< Real >;
using Polygon = vector< Point >;
const Real EPS = 1e-9, PI = acos(-1);
constexpr int COUNTER_CLOCKWISE = +1;
constexpr int CLOCKWISE = -1;
constexpr int ONLINE_BACK = +2;  // c-a-b
constexpr int ONLINE_FRONT = -2; // a-b-c
constexpr int ON_SEGMENT = 0;    // a-c-b

Point operator*(const Point &p, const Real &d) {
    return Point(real(p) * d, imag(p) * d);
}

Point operator/(const Point &p, const Real &d) {
    return Point(real(p) / d, imag(p) / d);
}

istream &operator>>(istream &is, Point &p) {
    Real a, b; is >> a >> b;
    p = Point(a, b);
    return is;
}

ostream &operator<<(ostream &os, const Point &p) {
    return os << fixed << setprecision(10) << real(p) << " " << imag(p);
}

namespace std {
    bool operator<(const Point &a, const Point &b) {
        return a.real() != b.real() ? a.real() < b.real() : a.imag() < b.imag();
    }
}

// 符号
inline int sign(const Real &r) {
    return r <= -EPS ? -1 : r >= EPS ? 1 : 0;
}

// a = b ? 
inline bool equals(const Real &a, const Real &b) {
    return sign(a - b) == 0;
}


// 単位ベクトル
Point unitVec(const Point &a){ return a / abs(a); }

// 法線ベクトル 半時計周り
Point normVec(const Point &a){ return a * Point(0, 1); }
//Point normVec(const Point &a){ return a * Point(0,-1); }

// 内積
Real dot(const Point &a, const Point &b) {
    return (a.real() * b.real() + a.imag() * b.imag());
}

// 外積
Real cross(const Point &a, const Point &b) {
    return (a.real() * b.imag() - a.imag() * b.real());
}

Point rotate(const Point &p, const Real &theta) {
    return Point(cos(theta) * p.real() - sin(theta) * p.imag(),
                 sin(theta) * p.real() + cos(theta) * p.imag());
}

Real Radian_To_Degree(const Real &radian){ return radian * 180.0 / PI; }
Real Degree_To_Radian(const Real &degree){ return degree * PI / 180.0; }

struct Line {
    Point a, b;
    Line() = default;
    Line(Point a, Point b) : a(a), b(b) {}

    // Ax + By = C
    Line(Real A, Real B, Real C) {
        if(equals(A, 0)) {
            a = Point(0, C / B), b = Point(1, C / B);
        }else if(equals(B,0)) {
            b = Point(C / A, 0), b = Point(C / A, 1);
        }else{
            a = Point(0, C / B), b = Point(C / A, 0);
        }
    }

    friend ostream &operator<<(ostream &os, Line &p) {
        return os << p.a << " " << p.b;
    }

    friend istream &operator>>(istream &is, Line &a) {
        return is >> a.a >> a.b;
    }
};

struct Segment : Line {
    Segment() = default;
    Segment(Point a, Point b) : Line(a, b) {}
};

struct Circle {
    Point p;
    Real r;
    Circle() = default;
    Circle(Point p, Real r) : p(p), r(r) {}

    friend ostream &operator<<(ostream &os, Circle &c) {
        return os << c.p << " " << c.r;
    }

    friend istream &operator>>(istream &is, Circle &c) {
        return is >> c.p >> c.r;
    }
};

// 直線lに点pから引いた垂線の足を求める
Point projection(const Line &l, const Point &p) {
    Real t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
    return l.a + (l.a - l.b) * t;
}

Point projection(const Segment &l, const Point &p) {
    Real t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
    return l.a + (l.a - l.b) * t;
}

// 直線lに関して点pと対称な点を求める
Point reflection(const Line &l, const Point &p) {
    return p + (projection(l, p) - p) * 2.0;
}

// 点の回転方向
// 点aを基準に点b,cの位置関係
int ccw(const Point &a, Point b, Point c) {
    b = b - a, c = c - a;
    if(sign(cross(b, c)) == +1) return COUNTER_CLOCKWISE; // 反時計回り
    if(sign(cross(b, c)) == -1) return CLOCKWISE;         // 時計回り
    if(sign(dot(b, c)) == -1) return ONLINE_BACK;         // c - a - b
    if(norm(b) < norm(c)) return ONLINE_FRONT;            // a - b - c
    return ON_SEGMENT;                                    // a - c - b
}

// 2直線の直交判定
bool is_orthogonal(const Line &a, const Line &b) {
    return equals(dot(a.b - a.a, b.b - b.a), 0);
}

// 2直線の平行判定
bool is_parallel(const Line &a, const Line &b) {
    return equals(cross(a.b - a.a, b.b - b.a), 0);
}

// 線分の交差判定
bool is_intersect_ss(const Segment &s, const Segment &t) {
    return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 &&
           ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

// 直線の交差判定
bool is_intersect_ll(const Line &l, const Line &m) {
    Real A = cross(l.b - l.a, m.b - m.a);
    Real B = cross(l.b - l.a, l.b - m.a);
    if(equals(abs(A), 0) && equals(abs(B), 0)) return true;
    return !is_parallel(l, m);
}

// 線分に点が乗っているか
bool is_intersect_sp(const Segment &s, const Point &p) {
    return ccw(s.a, s.b, p) == ON_SEGMENT;
}

// 点と点の距離
Real distance_pp(const Point &p1, const Point &p2) {
    return sqrt(pow(real(p1)-real(p2), 2) + pow(imag(p1)-imag(p2), 2));
}

// 点と直線の距離
Real distance_lp(const Line &l, const Point &p) {
    return abs(p - projection(l, p));
}

// 直線と直線の距離
Real distance_ll(const Line &l, const Line &m) {
    return is_intersect_ll(l, m) ? 0 : distance_lp(l, m.a);
}

// 点と線分の距離
Real distance_sp(const Segment &s, const Point &p) {
    Point r = projection(s, p);
    if(is_intersect_sp(s, r)) return abs(r - p);
    return min(abs(s.a - p), abs(s.b - p));
}

// 線分と線分の距離
Real distance_ss(const Segment &a, const Segment &b) {
    if(is_intersect_ss(a, b)) return 0;
    return min({distance_sp(a, b.a), distance_sp(a, b.b), distance_sp(b, a.a), distance_sp(b, a.b)});
}

// 交点
Point cross_point_ll(const Line &l, const Line &m) {
    Real A = cross(l.b - l.a, m.b - m.a);
    Real B = cross(l.b - l.a, l.b - m.a);
    if(equals(abs(A), 0) && equals(abs(B), 0)) return m.a;
    return m.a + (m.b - m.a) * B / A;
}

// 円と円の位置関係
int intersect(Circle c1, Circle c2) {
    if(c1.r < c2.r) swap(c1, c2);
    Real d = abs(c1.p - c2.p);
    if(c1.r + c2.r < d) return 4;
    if(equals(c1.r + c2.r, d)) return 3;
    if(c1.r - c2.r < d) return 2;
    if(equals(c1.r - c2.r, d)) return 1;
    return 0;
}

Real area(const Polygon &p){
    Real A = 0;
    for(int i = 0; i < p.size(); i++){
        A += cross(p[i], p[(i + 1) % p.size()]);
    }
    return A * 0.5;
}

bool is_convex(const Polygon &p){
    for(int i = 0; i < p.size(); i++){
        if(ccw(p[(i + p.size() - 1) % p.size()], p[i], p[(i + 1) % p.size()]) == -1) return false;
    }
    return true;
}

enum { OUT, ON, IN };
int contains(const Polygon &Q, const Point &p){
    bool in = false;
    for(int i = 0; i < Q.size(); i++){
        Point a = Q[i] - p, b = Q[(i + 1) % Q.size()] - p;
        if(a.imag() > b.imag()) swap(a, b);
        if(a.imag() <= 0 && 0 < b.imag() && cross(a, b) < 0) in = !in;
        if(cross(a, b) == 0 && dot(a, b) <= 0) return ON;
    }
    return in ? IN : OUT;
}

Polygon convex_hull(Polygon &p, bool strict = true){
    int n = (int)p.size(), k = 0;
    if(n <= 2) return p;
    sort(p.begin(), p.end());
    Polygon ch(2 * n);
    for(int i = 0; i < n; ch[k++] = p[i++]){
        while(k >= 2 && cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < 0) --k;
    }
    for(int i = n - 2, t = k + 1; i >= 0; ch[k++] = p[i--]){
        while(k >= t && cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < 0) --k;
    }
    ch.resize(k - 1);
    return ch;
}

Real convex_diameter(const Polygon &p){
    int n = (int)p.size();
    int is = 0, js = 0;
    for(int i = 1; i < n; i++){
        if(p[i].imag() > p[is].imag()) is = i;
        if(p[i].imag() < p[js].imag()) js = i;
    }
    Real maxdis = norm(p[is] - p[js]);
    int maxi, maxj, i, j;
    i = maxi = is;
    j = maxj = js;
    do {
        if(cross(p[(i + 1) % n] - p[i], p[(j + 1) % n] - p[j]) >= 0){
            j = (j + 1) % n;
        }else{
            i = (i + 1) % n;
        }

        if(norm(p[i] - p[j]) > maxdis){
            maxdis = norm(p[i] - p[j]);
            maxi = i;
            maxj = j;
        }

    }while(i != is || j != js);
    return sqrt(maxdis);
}

Polygon convex_cut(const Polygon &U, Line l){
    Polygon ret;
    for(int i = 0; i < U.size(); i++){
        Point now = U[i], nxt = U[(i + 1) % U.size()];
        if(ccw(l.a, l.b, now) != -1) ret.push_back(now);
        if(ccw(l.a, l.b, now) * ccw(l.a, l.b, nxt) < 0){
            ret.push_back(cross_point_ll(Line(now, nxt), l));
        }
    }
    return ret;
}

Real ClosetPair(Polygon& ps){
    if(ps.size() <= 1) throw (0);
    sort(begin(ps), end(ps));

    auto compare_y = [&](const Point &a, const Point &b) {
        return a.imag() < b.imag();
    };
    Polygon beet(ps.size());
    const double INF = 1e18;

    function< double(int, int) > rec = [&](int left, int right) {
        if(right - left <= 1) return INF;
        int mid = (left + right) >> 1;
        auto x = ps[mid].real();
        auto ret = min(rec(left, mid), rec(mid, right));
        inplace_merge(begin(ps) + left, begin(ps) + mid, begin(ps) + right, compare_y);
        int ptr = 0;
        for(int i = left; i < right; i++) {
            if(fabs((ps[i].real()) - x) >= ret) continue;
            for(int j = 0; j < ptr; j++) {
                auto luz = ps[i] - beet[ptr - j - 1];
                if(luz.imag() >= ret) break;
                ret = min(ret, abs(luz));
            }
            beet[ptr++] = ps[i];
        }
        return ret;
    };
    return rec(0, (int) ps.size());
}

pair< Point, Point > cross_point_cc(const Circle &c1, const Circle &c2) {
    Real d = abs(c1.p - c2.p);
    Real a = acos((c1.r * c1.r + d * d - c2.r * c2.r) / (2 * c1.r * d));
    Real t = atan2(c2.p.imag() - c1.p.imag(), c2.p.real() - c1.p.real());
    Point p1 = c1.p + Point(cos(t + a) * c1.r, sin(t + a) * c1.r);
    Point p2 = c1.p + Point(cos(t - a) * c1.r, sin(t - a) * c1.r);
    return {p1, p2};
}

const int BOTTOM = 0;
const int LEFT   = 1;
const int RIGHT  = 2;
const int TOP    = 3;

class endPoint {
    public:
        Point p;
        int seg; // id of Point
        int st; // kind of Point
        endPoint(){}
        endPoint(Point inp, int inseg, int inst):p(inp),seg(inseg),st(inst){}
        bool operator<(const endPoint &ep)const {
            if(p.imag() == ep.p.imag()) return st < ep.st;
            else return p.imag() < ep.p.imag();
        }
};

endPoint EP[220000];
int Manhattan_Intersections(vector< Segment > s){
    int n = s.size();
    double hoge;

    for(int i = 0, k = 0; i < n; i++){
        if(s[i].a.imag() == s[i].b.imag()){
            if(s[i].a.real() > s[i].b.real()){
                hoge = s[i].a.real();
                s[i].a.real(s[i].b.real());
                s[i].b.real(hoge);
            }
        }else if(s[i].a.imag() > s[i].b.imag()){
            hoge = s[i].a.imag();
            s[i].a.imag(s[i].b.imag());
            s[i].b.imag(hoge);
        }

        if(s[i].a.imag() == s[i].b.imag()){
            EP[k++] = endPoint(s[i].a, i, LEFT);
            EP[k++] = endPoint(s[i].b, i, RIGHT);
        }else{
            EP[k++] = endPoint(s[i].a, i, BOTTOM);
            EP[k++] = endPoint(s[i].b, i, TOP);
        }
    }

    sort(EP, EP + 2 * n);
    set<int> BT;
    BT.insert(1000000001);
    int cnt = 0;
    for(int i = 0; i < 2 * n; i++){
        if(EP[i].st == TOP) BT.erase(EP[i].p.real());
        else if(EP[i].st == BOTTOM) BT.insert(EP[i].p.real());
        else if(EP[i].st == LEFT){
            set<int>::iterator b = lower_bound(BT.begin(), BT.end(), s[EP[i].seg].a.real());
            set<int>::iterator e = upper_bound(BT.begin(), BT.end(), s[EP[i].seg].b.real());
            cnt += distance(b, e);
        }
    }

    return cnt;
}

// 内接円
Circle Inscribed_Circle(const Point& a, const Point& b, const Point& c){
    double A = abs(b - c), B = abs(c - a), C = abs(a - b);
    Point x = Point((a * A + b * B + c * C) / (A + B + C));
    double r = distance_sp(Segment(a,b),x);
    return Circle(x, r);
}

// 外接円
Circle Circumscribed_Circle(const Point& a, const Point& b, const Point& c){
    Point m1((a+b)/2.0), m2((b+c)/2.0);
    Point v((b-a).imag(), (a-b).real()), w((b-c).imag(), (c-b).real());
    Line s(m1, Point(m1+v)), t(m2, Point(m2+w));
    const Point x = cross_point_ll(s, t);
    return Circle(x, abs(a-x));
}

pair< Point, Point > cross_point_cl(const Circle &c, const Line &l) {
    Point pr = projection(l, c.p);
    if(equals(abs(pr - c.p), c.r)) return {pr, pr};
    Point e = (l.b - l.a) / abs(l.b - l.a);
    auto k = sqrt(norm(c.r) - norm(pr - c.p));
    return {pr - e * k, pr + e * k};
}

// 点pを通る円の接線
pair<Point,Point> tangent_cp(const Circle &c, const Point &p) {
    return cross_point_cc(c, Circle(p, sqrt(norm(c.p - p) - c.r * c.r)));
}

// 二つの円の共通接線
vector< Line > tangent_cc(Circle c1, Circle c2){
    vector< Line > ret;
    if(c1.r < c2.r) swap(c1,c2);
    double g = norm(c1.p-c2.p);
    if(equals(g,0.0)) return ret;
    Point u = (c2.p-c1.p)/sqrt(g);
    Point v = rotate(u, PI * 0.5);
    for(int s:{-1,1}){
        double h = (c1.r+ s*c2.r)/sqrt(g);
        if(equals(1- h*h, 0)){
            ret.emplace_back(c1.p+u*c1.r, c1.p+(u+v)*c1.r);
        }else if(1-h*h > 0){
            Point uu = u*h, vv = v*sqrt(1-h*h);
            ret.emplace_back(c1.p+(uu+vv)*c1.r, c2.p-(uu+vv)*c2.r*s);
            ret.emplace_back(c1.p+(uu-vv)*c1.r, c2.p-(uu-vv)*c2.r*s);
        }
    }
    return ret;
}

Real area_poly_c(const Polygon &p, const Circle &c) {
    if(p.size() < 3) return 0.0;
    function< Real(Circle, Point, Point) > cross_area = [&](const Circle &c, const Point &a, const Point &b) {
        Point va = c.p - a, vb = c.p - b;
        Real f = cross(va, vb), ret = 0.0;
        if(equals(f, 0.0)) return ret;
        if(max(abs(va), abs(vb)) < c.r + EPS) return f;
        if(distance_sp(Segment(a, b), c.p) > c.r - EPS) return c.r * c.r * arg(vb * conj(va));
        auto u = cross_point_cl(c, Segment(a, b));
        vector< Point > tot{a, u.first, u.second, b};
        for(int i = 0; i + 1 < tot.size(); i++) {
            ret += cross_area(c, tot[i], tot[i + 1]);
        }
        return ret;
    };
    Real A = 0;
    for(int i = 0; i < p.size(); i++) {
        A += cross_area(c, p[i], p[(i + 1) % p.size()]);
    }
    return A;
}

Real area_cc(const Circle &c1, const Circle &c2) {
    Real d = abs(c1.p - c2.p);
    if(c1.r + c2.r <= d + EPS) return 0.0;
    if(d <= fabs(c1.r - c2.r) + EPS) {
        Real r = min(c1.r, c2.r);
        return r * r * PI;
    }
    Real rc = (d * d + c1.r * c1.r - c2.r * c2.r) / (2 * d);
    Real theta = acos(rc / c1.r);
    Real phi = acos((d - rc) / c2.r);
    return (c1.r * c1.r*theta + c2.r*c2.r*phi - d*c1.r*sin(theta));
}

// g <- pair < v , cost > 
template < class T >
vector<T> Dijkstra(vector<vector<pair<int,T>>> &g, int s) {
    vector<T> dist(g.size(), -1);
    priority_queue<pair<T,int>> Q;
    Q.emplace(0, s);
    while(!Q.empty()){
        T cost = Q.top().first;
        int v = Q.top().second;
        Q.pop();
        cost = - cost;
        if(dist[v] == -1){
            dist[v] = cost;
            for(auto e : g[v]){
                if(dist[e.first] == -1){
                    Q.emplace(-(cost + e.second), e.first);
                }
            }
        }
    }
    for(auto &d : dist) if(d == -1) d = 1e9;
    return dist;
}

int main(){
    cin.tie(0);
    ios::sync_with_stdio(0);
    
    int N,M; cin >> N >> M;
    vector<Point> A(N),B(M);
    rep(i,N) cin >> A[i];
    rep(i,M) cin >> B[i];

    Segment l = Segment(B[0], B[1]);
    vector<vector<pair<int,Real>>> G(N);
    rep(i,N)rep(j,N)if(i < j){
        Segment m = Segment(A[i], A[j]);
        if(!is_intersect_ss(l, m)){
            Real d = abs(A[i] - A[j]);
            G[i].push_back({j, d});
            G[j].push_back({i, d});
        }
    }

    l = Segment(A[0], A[1]);
    vector<vector<pair<int,Real>>> H(M);
    rep(i,M)rep(j,M)if(i < j){
        Segment m = Segment(B[i], B[j]);
        if(!is_intersect_ss(l, m)) {
            Real d = abs(B[i] - B[j]);
            H[i].push_back({j, d});
            H[j].push_back({i, d});
        }
    }

    Real ans = min(Dijkstra(G, 0)[1] + abs(B[0] - B[1]), Dijkstra(H, 0)[1] + abs(A[0] - A[1]));
    cout.precision(17);
    cout << (ans < 1e9 ? ans : -1) << endl;
}
accuracy: 1
time_ms: 130
memory_kb: 58176
final_rank: 19

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define all(v) (v).begin(),(v).end()
#define pb(a) push_back(a)
#define rep(i, n) for(int i=0;i<n;i++)
#define foa(e, v) for(auto&& e : v)
using ll = long long;
const ll MOD7 = 1000000007, MOD998 = 998244353, INF = (1LL << 60);
#define dout(a) cout<<fixed<<setprecision(10)<<a<<endl;

using ld = long double;
ll cross(ll x1, ll y1, ll x2, ll y2) {
    return x1 * y2 - x2 * y1;
}
int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    int n, m;
    cin >> n >> m;
    vector<ll> xa(n), ya(n), xb(m), yb(m);
    rep(i, n) {
        cin >> xa[i] >> ya[i];
    }
    rep(i, m) {
        cin >> xb[i] >> yb[i];
    }
    ld inf = 1e15;
    ld ans = inf;
    auto is_ins = [&](int i1, int i2, int j1, int j2) -> bool {
        if(i1 == i2) return false;
        ll x1 = xa[i2] - xa[i1];
        ll y1 = ya[i2] - ya[i1];
        ll x2 = xb[j1] - xa[i1];
        ll y2 = yb[j1] - ya[i1];
        ll x3 = xb[j2] - xa[i1];
        ll y3 = yb[j2] - ya[i1];
        if(cross(x2, y2, x3, y3) < 0) {
            swap(x2, x3);
            swap(y2, y3);
        }
        return (cross(x2, y2, x1, y1) > 0 and cross(x1, y1, x3, y3) > 0 and cross(x3 - x1, y3 - y1, x2 - x1, y2 - y1) > 0);
    };
    auto dist = [&](ll x1, ll y1, ll x2, ll y2) -> ld {
        return sqrtl(ld((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)));
    };
    rep(i, n) rep(j, n) {
        if(!is_ins(0, i, 0, 1) and !is_ins(i, j, 0, 1) and !is_ins(j, 1, 0, 1)) {
            ld val = dist(xb[0], yb[0], xb[1], yb[1]);
            val += dist(xa[0], ya[0], xa[i], ya[i]);
            val += dist(xa[i], ya[i], xa[j], ya[j]);
            val += dist(xa[j], ya[j], xa[1], ya[1]);
            ans = min(ans, val);
        }
    }
    swap(xa, xb);
    swap(ya, yb);
    swap(n, m);
    rep(i, n) rep(j, n) {
        if(!is_ins(0, i, 0, 1) and !is_ins(i, j, 0, 1) and !is_ins(j, 1, 0, 1)) {
            ld val = dist(xb[0], yb[0], xb[1], yb[1]);
            val += dist(xa[0], ya[0], xa[i], ya[i]);
            val += dist(xa[i], ya[i], xa[j], ya[j]);
            val += dist(xa[j], ya[j], xa[1], ya[1]);
            ans = min(ans, val);
        }
    }
    if(ans > inf / ld(10)) {
        cout << -1 << endl;
        return 0;
    }
    dout(ans);
    return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 3584
final_rank: 3

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b) for (int i = (int)(a); i < (int)(b); i++)
#define rrep(i, a, b) for (int i = (int)(b)-1; i >= (int)(a); i--)
#define ALL(v) (v).begin(), (v).end()
#define UNIQUE(v) sort(ALL(v)), (v).erase(unique(ALL(v)), (v).end())
#define SZ(v) (int)v.size()
#define MIN(v) *min_element(ALL(v))
#define MAX(v) *max_element(ALL(v))
#define LB(v, x) int(lower_bound(ALL(v), (x)) - (v).begin())
#define UB(v, x) int(upper_bound(ALL(v), (x)) - (v).begin())

using uint = unsigned int;
using ll = long long int;
using ull = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;
const int inf = 0x3fffffff;
const ll INF = 0x1fffffffffffffff;

template <typename T> inline bool chmax(T &a, T b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T> inline bool chmin(T &a, T b) {
    if (a > b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T, typename U> T ceil(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? (x + y - 1) / y : x / y);
}
template <typename T, typename U> T floor(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? x / y : (x - y + 1) / y);
}
template <typename T> int popcnt(T x) {
    return __builtin_popcountll(x);
}
template <typename T> int topbit(T x) {
    return (x == 0 ? -1 : 63 - __builtin_clzll(x));
}
template <typename T> int lowbit(T x) {
    return (x == 0 ? -1 : __builtin_ctzll(x));
}

template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << "P(" << p.first << ", " << p.second << ")";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) {
    os << "{";
    for (int i = 0; i < vec.size(); i++) {
        os << vec[i] << (i + 1 == vec.size() ? "" : ", ");
    }
    os << "}";
    return os;
}
template <typename T, typename U>
ostream &operator<<(ostream &os, const map<T, U> &map_var) {
    os << "{";
    for (auto itr = map_var.begin(); itr != map_var.end(); itr++) {
        os << "(" << itr->first << ", " << itr->second << ")";
        itr++;
        if (itr != map_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const set<T> &set_var) {
    os << "{";
    for (auto itr = set_var.begin(); itr != set_var.end(); itr++) {
        os << *itr;
        ++itr;
        if (itr != set_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
#ifdef LOCAL
#define show(...) _show(0, #__VA_ARGS__, __VA_ARGS__)
#else
#define show(...) true
#endif
template <typename T> void _show(int i, T name) {
    cerr << '\n';
}
template <typename T1, typename T2, typename... T3>
void _show(int i, const T1 &a, const T2 &b, const T3 &...c) {
    for (; a[i] != ',' && a[i] != '\0'; i++)
        cerr << a[i];
    cerr << ":" << b << " ";
    _show(i + 1, a, c...);
}

/**
 * @brief template
 */

using T = double;
const T eps = 1e-12;
using Point = complex<T>;
using Poly = vector<Point>;
#define X real()
#define Y imag()
template <typename T> inline bool eq(const T &a, const T &b) {
    return fabs(a - b) < eps;
}
bool cmp(const Point &a, const Point &b) {
    auto sub = [&](Point a) {
        return (a.Y < 0 ? -1 : (a.Y == 0 && a.X >= 0 ? 0 : 1));
    };
    if (sub(a) != sub(b))
        return sub(a) < sub(b);
    return a.Y * b.X < a.X * b.Y;
}
struct Line {
    Point a, b, dir;
    Line() {}
    Line(Point _a, Point _b) : a(_a), b(_b), dir(b - a) {}
    Line(T A, T B, T C) {
        if (eq(A, .0)) {
            a = Point(0, C / B), b = Point(1 / C / B);
        } else if (eq(B, .0)) {
            a = Point(C / A, 0), b = Point(C / A, 1);
        } else {
            a = Point(0, C / B), b = Point(C / A, 0);
        }
    }
};
struct Segment : Line {
    Segment() {}
    Segment(Point _a, Point _b) : Line(_a, _b) {}
};
struct Circle {
    Point p;
    T r;
    Circle() {}
    Circle(Point _p, T _r) : p(_p), r(_r) {}
};

istream &operator>>(istream &is, Point &p) {
    T x, y;
    is >> x >> y;
    p = Point(x, y);
    return is;
}
ostream &operator<<(ostream &os, Point &p) {
    os << fixed << setprecision(12) << p.X << ' ' << p.Y;
    return os;
}
Point unit(const Point &a) {
    return a / abs(a);
}
T dot(const Point &a, const Point &b) {
    return a.X * b.X + a.Y * b.Y;
}
T cross(const Point &a, const Point &b) {
    return a.X * b.Y - a.Y * b.X;
}
Point rot(const Point &a, const T &theta) {
    return Point(cos(theta) * a.X - sin(theta) * a.Y,
                 sin(theta) * a.X + cos(theta) * a.Y);
}
Point rot90(const Point &a) {
    return Point(-a.Y, a.X);
}
T arg(const Point &a, const Point &b, const Point &c) {
    double ret = acos(dot(a - b, c - b) / abs(a - b) / abs(c - b));
    if (cross(a - b, c - b) < 0)
        ret = -ret;
    return ret;
}

Point Projection(const Line &l, const Point &p) {
    T t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
    return l.a + (l.a - l.b) * t;
}
Point Projection(const Segment &l, const Point &p) {
    T t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
    return l.a + (l.a - l.b) * t;
}
Point Reflection(const Line &l, const Point &p) {
    return p + (Projection(l, p) - p) * 2.;
}
int ccw(const Point &a, Point b, Point c) {
    b -= a;
    c -= a;
    if (cross(b, c) > eps)
        return 1; // ccw

    if (cross(b, c) < -eps)
        return -1; // cw

    if (dot(b, c) < 0)
        return 2; // c,a,b

    if (norm(b) < norm(c))
        return -2; // a,b,c

    return 0;      // a,c,b

}
bool isOrthogonal(const Line &a, const Line &b) {
    return eq(dot(a.b - a.a, b.b - b.a), .0);
}
bool isParallel(const Line &a, const Line &b) {
    return eq(cross(a.b - a.a, b.b - b.a), .0);
}
bool isIntersect(const Segment &a, const Segment &b) {
    return ccw(a.a, a.b, b.a) * ccw(a.a, a.b, b.b) <= 0 and
           ccw(b.a, b.b, a.a) * ccw(b.a, b.b, a.b) <= 0;
}
int isIntersect(const Circle &a, const Circle &b) {
    T d = abs(a.p - b.p);
    if (d > a.r + b.r + eps)
        return 4;
    if (eq(d, a.r + b.r))
        return 3;
    if (eq(d, abs(a.r - b.r)))
        return 1;
    if (d < abs(a.r - b.r) - eps)
        return 0;
    return 2;
}
T Dist(const Line &a, const Point &b) {
    Point c = Projection(a, b);
    return abs(c - b);
}
T Dist(const Segment &a, const Point &b) {
    if (dot(a.b - a.a, b - a.a) < eps)
        return abs(b - a.a);
    if (dot(a.a - a.b, b - a.b) < eps)
        return abs(b - a.b);
    return abs(cross(a.b - a.a, b - a.a)) / abs(a.b - a.a);
}
T Dist(const Segment &a, const Segment &b) {
    if (isIntersect(a, b))
        return .0;
    T res = min({Dist(a, b.a), Dist(a, b.b), Dist(b, a.a), Dist(b, a.b)});
    return res;
}
Point Intersection(const Line &a, const Line &b) {
    T d1 = cross(a.b - a.a, b.b - b.a);
    T d2 = cross(a.b - a.a, a.b - b.a);
    if (eq(d1, 0.) and eq(d2, 0.))
        return b.a;
    return b.a + (b.b - b.a) * (d2 / d1);
}
Poly Intersection(const Circle &a, const Line &b) {
    Poly res;
    T d = Dist(b, a.p);
    if (d > a.r + eps)
        return res;
    Point h = Projection(b, a.p);
    if (eq(d, a.r)) {
        res.push_back(h);
        return res;
    }
    Point e = unit(b.b - b.a);
    T ph = sqrt(a.r * a.r - d * d);
    res.push_back(h - e * ph);
    res.push_back(h + e * ph);
    return res;
}
Poly Intersection(const Circle &a, const Segment &b) {
    Line c(b.a, b.b);
    Poly sub = Intersection(a, c);
    double xmi = min(b.a.X, b.b.X), xma = max(b.a.X, b.b.X);
    double ymi = min(b.a.Y, b.b.Y), yma = max(b.a.Y, b.b.Y);
    Poly res;
    rep(i, 0, sub.size()) {
        if (xmi <= sub[i].X + eps and sub[i].X - eps <= xma and
            ymi <= sub[i].Y + eps and sub[i].Y - eps <= yma) {
            res.push_back(sub[i]);
        }
    }
    return res;
}
Poly Intersection(const Circle &a, const Circle &b) {
    Poly res;
    int mode = isIntersect(a, b);
    T d = abs(a.p - b.p);
    if (mode == 4 or mode == 0)
        return res;
    if (mode == 3) {
        T t = a.r / (a.r + b.r);
        res.push_back(a.p + (b.p - a.p) * t);
        return res;
    }
    if (mode == 1) {
        if (b.r < a.r - eps) {
            res.push_back(a.p + (b.p - a.p) * (a.r / d));
        } else {
            res.push_back(b.p + (a.p - b.p) * (b.r / d));
        }
        return res;
    }
    T rc = (a.r * a.r + d * d - b.r * b.r) / d / 2.;
    T rs = sqrt(a.r * a.r - rc * rc);
    if (a.r - abs(rc) < eps)
        rs = 0;
    Point e = unit(b.p - a.p);
    res.push_back(a.p + rc * e + rs * e * Point(0, 1));
    res.push_back(a.p + rc * e + rs * e * Point(0, -1));
    return res;
}
Poly HalfplaneIntersection(vector<Line> &H) {
    sort(ALL(H), [&](Line &l1, Line &l2) { return cmp(l1.dir, l2.dir); });
    auto outside = [&](Line &L, Point p) -> bool {
        return cross(L.dir, p - L.a) < -eps;
    };
    deque<Line> deq;
    int sz = 0;
    rep(i, 0, SZ(H)) {
        while (sz > 1 and
               outside(H[i], Intersection(deq[sz - 1], deq[sz - 2]))) {
            deq.pop_back();
            sz--;
        }
        while (sz > 1 and outside(H[i], Intersection(deq[0], deq[1]))) {
            deq.pop_front();
            sz--;
        }
        if (sz > 0 and fabs(cross(H[i].dir, deq[sz - 1].dir)) < eps) {
            if (dot(H[i].dir, deq[sz - 1].dir) < 0) {
                return {};
            }
            if (outside(H[i], deq[sz - 1].a)) {
                deq.pop_back();
                sz--;
            } else
                continue;
        }
        deq.push_back(H[i]);
        sz++;
    }

    while (sz > 2 and outside(deq[0], Intersection(deq[sz - 1], deq[sz - 2]))) {
        deq.pop_back();
        sz--;
    }
    while (sz > 2 and outside(deq[sz - 1], Intersection(deq[0], deq[1]))) {
        deq.pop_front();
        sz--;
    }
    if (sz < 3)
        return {};
    deq.push_back(deq.front());
    Poly ret;
    rep(i, 0, sz) ret.push_back(Intersection(deq[i], deq[i + 1]));
    return ret;
}

T Area(const Poly &a) {
    T res = 0;
    int n = a.size();
    rep(i, 0, n) res += cross(a[i], a[(i + 1) % n]);
    return fabs(res / 2.);
}
T Area(const Poly &a, const Circle &b) {
    int n = a.size();
    if (n < 3)
        return .0;
    auto rec = [&](auto self, const Circle &c, const Point &p1,
                   const Point &p2) {
        Point va = c.p - p1, vb = c.p - p2;
        T f = cross(va, vb), res = .0;
        if (eq(f, .0))
            return res;
        if (max(abs(va), abs(vb)) < c.r + eps)
            return f;
        if (Dist(Segment(p1, p2), c.p) > c.r - eps)
            return c.r * c.r * arg(vb * conj(va));
        auto u = Intersection(c, Segment(p1, p2));
        Poly sub;
        sub.push_back(p1);
        for (auto &x : u)
            sub.push_back(x);
        sub.push_back(p2);
        rep(i, 0, sub.size() - 1) res += self(self, c, sub[i], sub[i + 1]);
        return res;
    };
    T res = .0;
    rep(i, 0, n) res += rec(rec, b, a[i], a[(i + 1) % n]);
    return fabs(res / 2.);
}
T Area(const Circle &a, const Circle &b) {
    T d = abs(a.p - b.p);
    if (d >= a.r + b.r - eps)
        return .0;
    if (d <= abs(a.r - b.r) + eps) {
        T r = min(a.r, b.r);
        return M_PI * r * r;
    }
    T ath = acos((a.r * a.r + d * d - b.r * b.r) / d / a.r / 2.);
    T res = a.r * a.r * (ath - sin(ath * 2) / 2.);
    T bth = acos((b.r * b.r + d * d - a.r * a.r) / d / b.r / 2.);
    res += b.r * b.r * (bth - sin(bth * 2) / 2.);
    return fabs(res);
}
bool isConvex(const Poly &a) {
    int n = a.size();
    int cur, pre, nxt;
    rep(i, 0, n) {
        pre = (i - 1 + n) % n;
        nxt = (i + 1) % n;
        cur = i;
        if (ccw(a[pre], a[cur], a[nxt]) == -1)
            return 0;
    }
    return 1;
}
int isContained(const Poly &a,
                const Point &b) { // 0:not contain,1:on edge,2:contain

    bool res = 0;
    int n = a.size();
    rep(i, 0, n) {
        Point p = a[i] - b, q = a[(i + 1) % n] - b;
        if (p.Y > q.Y)
            swap(p, q);
        if (p.Y < eps and eps < q.Y and cross(p, q) > eps)
            res ^= 1;
        if (eq(cross(p, q), .0) and dot(p, q) < eps)
            return 1;
    }
    return (res ? 2 : 0);
}
Poly ConvexHull(Poly &a) {
    sort(ALL(a), [](const Point &p, const Point &q) {
        return (eq(p.Y, q.Y) ? p.X < q.X : p.Y < q.Y);
    });
    a.erase(unique(ALL(a)), a.end());
    int n = a.size(), k = 0;
    Poly res(n * 2);
    for (int i = 0; i < n; res[k++] = a[i++]) {
        while (k >= 2 and
               cross(res[k - 1] - res[k - 2], a[i] - res[k - 1]) < eps)
            k--;
    }
    for (int i = n - 2, t = k + 1; i >= 0; res[k++] = a[i--]) {
        while (k >= t and
               cross(res[k - 1] - res[k - 2], a[i] - res[k - 1]) < eps)
            k--;
    }
    res.resize(k - 1);
    return res;
}
T Diam(const Poly &a) {
    int n = a.size();
    int x = 0, y = 0;
    rep(i, 1, n) {
        if (a[i].Y > a[x].Y)
            x = i;
        if (a[i].Y < a[y].Y)
            y = i;
    }
    T res = abs(a[x] - a[y]);
    int i = x, j = y;
    do {
        if (cross(a[(i + 1) % n] - a[i], a[(j + 1) % n] - a[j]) < 0)
            i = (i + 1) % n;
        else
            j = (j + 1) % n;
        chmax(res, abs(a[i] - a[j]));
    } while (i != x or j != y);
    return res;
}
Poly Cut(const Poly &a, const Line &l) {
    int n = a.size();
    Poly res;
    rep(i, 0, n) {
        Point p = a[i], q = a[(i + 1) % n];
        if (ccw(l.a, l.b, p) != -1)
            res.push_back(p);
        if (ccw(l.a, l.b, p) * ccw(l.a, l.b, q) < 0)
            res.push_back(Intersection(Line(p, q), l));
    }
    return res;
}

T Closest(Poly &a) {
    int n = a.size();
    if (n <= 1)
        return 0;
    sort(ALL(a), [&](Point a, Point b) {
        return (eq(a.X, b.X) ? a.Y < b.Y : a.X < b.X);
    });
    Poly buf(n);
    auto rec = [&](auto self, int lb, int rb) -> T {
        if (rb - lb <= 1)
            return (T)INF;
        int mid = (lb + rb) >> 1;
        auto x = a[mid].X;
        T res = min(self(self, lb, mid), self(self, mid, rb));
        inplace_merge(a.begin() + lb, a.begin() + mid, a.begin() + rb,
                      [&](auto p, auto q) { return p.Y < q.Y; });
        int ptr = 0;
        rep(i, lb, rb) {
            if (abs(a[i].X - x) >= res)
                continue;
            rep(j, 0, ptr) {
                auto sub = a[i] - buf[ptr - 1 - j];
                if (sub.Y >= res)
                    break;
                chmin(res, abs(sub));
            }
            buf[ptr++] = a[i];
        }
        return res;
    };
    return rec(rec, 0, n);
}

Circle Incircle(const Point &a, const Point &b, const Point &c) {
    T A = abs(b - c), B = abs(c - a), C = abs(a - b);
    Point p(A * a.X + B * b.X + C * c.X, A * a.Y + B * b.Y + C * c.Y);
    p /= (A + B + C);
    T r = Dist(Line(a, b), p);
    return Circle(p, r);
}
Circle Circumcircle(const Point &a, const Point &b, const Point &c) {
    Line l1((a + b) / 2., (a + b) / 2. + (b - a) * Point(0, 1));
    Line l2((b + c) / 2., (b + c) / 2. + (c - b) * Point(0, 1));
    Point p = Intersection(l1, l2);
    return Circle(p, abs(p - a));
}
Poly tangent(const Point &a, const Circle &b) {
    return Intersection(b, Circle(a, sqrt(norm(b.p - a) - b.r * b.r)));
}
vector<Line> tangent(const Circle &a, const Circle &b) {
    vector<Line> res;
    T d = abs(a.p - b.p);
    if (eq(d, 0.))
        return res;
    Point u = unit(b.p - a.p);
    Point v = u * Point(0, 1);
    for (int t : {-1, 1}) {
        T h = (a.r + b.r * t) / d;
        if (eq(h * h, 1.)) {
            res.push_back(Line(a.p + (h > 0 ? u : -u) * a.r,
                               a.p + (h > 0 ? u : -u) * a.r + v));
        } else if (1 > h * h) {
            Point U = u * h, V = v * sqrt(1 - h * h);
            res.push_back(Line(a.p + (U + V) * a.r, b.p - (U + V) * (b.r * t)));
            res.push_back(Line(a.p + (U - V) * a.r, b.p - (U - V) * (b.r * t)));
        }
    }
    return res;
}

/**
 * @brief Geometry
 */

int main() {
    int N, M;
    cin >> N >> M;
    vector<Point> A(N), B(M);
    rep(i,0,N) {
        double x, y;
        cin >> x >> y;
        A[i] = Point(x,y);
    }
    rep(i,0,M) {
        double x, y;
        cin >> x >> y;
        B[i] = Point(x,y);
    }
    double ANS = INF;
    rep(i,0,N) {
        rep(j,0,N) {
            if (!isIntersect(Segment(A[0],A[i]),Segment(B[0],B[1])) && 
                !isIntersect(Segment(A[i],A[j]),Segment(B[0],B[1])) && 
                !isIntersect(Segment(A[j],A[1]),Segment(B[0],B[1]))) chmin(ANS, abs(A[i]-A[0])+abs(A[j]-A[i])+abs(A[1]-A[j])+abs(B[1]-B[0]));
        }
    }
    rep(i,0,M) {
        rep(j,0,M) {
            if (!isIntersect(Segment(A[0],A[1]),Segment(B[0],B[i])) && 
                !isIntersect(Segment(A[0],A[1]),Segment(B[i],B[j])) && 
                !isIntersect(Segment(A[0],A[1]),Segment(B[j],B[1]))) chmin(ANS, abs(A[1]-A[0])+abs(B[i]-B[0])+abs(B[j]-B[i])+abs(B[1]-B[j]));
        }
    }
    if (ANS == INF) cout << -1 << endl;
    else printf("%.12f\n",ANS);
}
accuracy: 1
time_ms: 110
memory_kb: 3652
final_rank: 10

code_snippet: #line 1 "2334.test.cpp"
#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/problems/2334"
#define ERROR 0.000000001

#line 2 "/home/zawatin/compro/cp-documentation/Src/Template/IOSetting.hpp"

#line 2 "/home/zawatin/compro/cp-documentation/Src/Template/TypeAlias.hpp"

#include <cstdint>
#include <cstddef>

namespace zawa {

using i16 = std::int16_t;
using i32 = std::int32_t;
using i64 = std::int64_t;
using i128 = __int128_t;

using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;

using usize = std::size_t;

} // namespace zawa
#line 4 "/home/zawatin/compro/cp-documentation/Src/Template/IOSetting.hpp"

#include <iostream>
#include <iomanip>

namespace zawa {

void SetFastIO() {
    std::cin.tie(nullptr)->sync_with_stdio(false);
}

void SetPrecision(u32 dig) {
    std::cout << std::fixed << std::setprecision(dig);
}

} // namespace zawa
#line 2 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Point.hpp"

#line 2 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Real.hpp"

#line 4 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Real.hpp"

#include <cmath>
#include <cassert>

namespace zawa {

namespace geometryR2 {

using Real = long double;

namespace internal {

Real EPS{1e-12};
constexpr i32 negative{-1};
constexpr i32 zero{};
constexpr i32 positive{1};

} // namespace internal

Real& Eps() {
    return internal::EPS;
}

i32 Sign(Real value) {
    if (value < -Eps()) return internal::negative;
    if (value > Eps()) return internal::positive;
    return internal::zero;
}

bool Zero(Real value) {
    return Sign(value) == internal::zero;
}

bool Positive(Real value) {
    return Sign(value) == internal::positive;
}

bool Negative(Real value) {
    return Sign(value) == internal::negative;
}

bool Equal(Real a, Real b) {
    return Zero(a - b);
}

bool Smaller(Real a, Real b) {
    return Negative(a - b);
}

bool Bigger(Real a, Real b) {
    return Positive(a - b);
}

Real Square(Real value) {
    return (Zero(value) ? value : value * value);
}

Real Sqrt(Real value) {
    assert(!Negative(value));
    return (Zero(value) ? value : sqrtl(value));
}

Real Abs(Real value) {
    return (Negative(value) ? -value : value);
}

} // namespace geometryR2
 
} // namespace zawa
#line 2 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Angle.hpp"

#line 4 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Angle.hpp"

#line 6 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Angle.hpp"

namespace zawa {

namespace geometryR2 {

constexpr Real PI{acosl(-1)};
constexpr Real TAU{static_cast<Real>(2) * PI};

constexpr Real ArcToRadian(Real arc) {
    return (arc * PI) / static_cast<Real>(180);
}

constexpr Real RadianToArc(Real radian) {
    return (radian * static_cast<Real>(180)) / PI;
}

} // namespace geometryR2

} // namespace zawa
#line 5 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Point.hpp"

#line 9 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Point.hpp"

namespace zawa {

namespace geometryR2 {

class Point {
private:
    Real x_{}, y_{};
public:
    /* constructor */
    Point() = default;
    Point(Real x, Real y) : x_{x}, y_{y} {}

    /* getter, setter */
    Real x() const {
        return x_;
    }
    Real& x() {
        return x_;
    }
    Real y() const {
        return y_;
    }
    Real& y() {
        return y_;
    }

    /* operator */
    Point& operator+=(const Point& rhs) {
        x_ += rhs.x();
        y_ += rhs.y();
        return *this;
    }
    friend Point operator+(const Point& lhs, const Point& rhs) {
        return Point{lhs} += rhs;
    }
    Point operator+() const {
        return *this;
    }
    Point& operator-=(const Point& rhs) {
        x_ -= rhs.x();
        y_ -= rhs.y();
        return *this;
    }
    friend Point operator-(const Point& lhs, const Point& rhs) {
        return Point{lhs} -= rhs;
    }
    Point operator-() const {
        return Point{} - *this;
    }
    Point& operator*=(Real k) {
        x_ *= k;
        y_ *= k;
        return *this;
    }
    friend Point operator*(Real k, const Point& p) {
        return Point{p} *= k;
    }
    friend Point operator*(const Point& p, Real k) {
        return Point{p} *= k;
    }
    Point& operator/=(Real k) {
        assert(!Zero(k));
        x_ /= k;
        y_ /= k;
        return *this;
    }
    friend Point operator/(Real k, const Point& p) {
        return Point{p} /= k;
    }
    friend Point operator/(const Point& p, Real k) {
        return Point{p} /= k;
    }
    friend bool operator==(const Point& lhs, const Point& rhs) {
        return Equal(lhs.x(), rhs.x()) and Equal(lhs.y(), rhs.y());
    }
    friend bool operator!=(const Point& lhs, const Point& rhs) {
        return !Equal(lhs.x(), rhs.x()) or !Equal(lhs.y(), rhs.y());
    }
    friend bool operator<(const Point& lhs, const Point& rhs) {
        return Smaller(lhs.x(), rhs.x()) or 
            (Equal(lhs.x(), rhs.x()) and Smaller(lhs.y(), rhs.y()));
    }
    friend bool operator<=(const Point& lhs, const Point& rhs) {
        return Smaller(lhs.x(), rhs.x()) or 
            (Equal(lhs.x(), rhs.x()) and (Smaller(lhs.y(), rhs.y()) or Equal(lhs.y(), rhs.y())));
    }
    friend bool operator>(const Point& lhs, const Point& rhs) {
        return Bigger(lhs.x(), rhs.x()) or
            (Equal(lhs.x(), rhs.x()) and Bigger(lhs.y(), rhs.y()));
    }
    friend bool operator>=(const Point& lhs, const Point& rhs) {
        return Bigger(lhs.x(), rhs.x()) or
            (Equal(lhs.x(), rhs.x()) and (Bigger(lhs.y(), rhs.y()) or Equal(lhs.y(), rhs.y())));
    }
    friend std::istream& operator>>(std::istream& is, Point& p) {
        is >> p.x_ >> p.y_;
        return is;
    }
    friend std::ostream& operator<<(std::ostream& os, const Point& p) {
        os << '(' << p.x_ << ',' << p.y_ << ')';
        return os;
    }
    
    /* member function */
    Real normSquare() const {
        return Square(x_) + Square(y_);
    }
    Real norm() const {
        return Sqrt(normSquare());
    }
    void normalize() {
        assert((*this) != Point{});
        (*this) /= norm(); 
    }
    Point normalized() const {
        Point res{*this};
        res.normalize();
        return res;
    }
    Point rotated(Real radian) const {
        return Point{
            x_ * cosl(radian) - y_ * sinl(radian),
            x_ * sinl(radian) + y_ * cosl(radian)
        };
    }
    void rotate(Real radian) {
        *this = rotated(radian); 
    }
    Point rotatedByArc(Real arc) const {
        return rotated(ArcToRadian(arc));
    }
    void rotateByArc(Real arc) {
        *this = rotatedByArc(arc);
    }
    Real argument() const {
        return (Negative(y_) ? TAU : static_cast<Real>(0)) + atan2l(y_, x_);
    }
    Real argumentByArc() const {
        return RadianToArc(argument());
    }

    /* friend function */
    friend Real Dot(const Point& lhs, const Point& rhs) {
        return lhs.x() * rhs.x() + lhs.y() * rhs.y();
    }
    friend Real Cross(const Point& lhs, const Point& rhs) {
        return lhs.x() * rhs.y() - lhs.y() * rhs.x();
    }
    friend Real Argument(const Point& lhs, const Point& rhs) {
        return rhs.argument() - lhs.argument();
    }
    friend bool ArgComp(const Point& lhs, const Point& rhs) {
        return Smaller(lhs.argument(), rhs.argument());
    }
};

using Vector = Point;

} // namespace geometryR2

} // namespace zawa
#line 2 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Segment.hpp"

#line 2 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Relation.hpp"

#line 5 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Relation.hpp"

namespace zawa {

namespace geometryR2 {

enum RELATION {
    // p0 -> p1 -> p2の順で直線上に並んでいる
    ONLINE_FRONT = -2,
    // (p1 - p0) -> (p2 - p0)が時計回りになっている
    CLOCKWISE,
    // p0 -> p2 -> p1の順で直線上に並んでいる
    ON_SEGMENT,
    // (p1 - p0) -> (p2 - p0)が反時計回りになっている
    COUNTER_CLOCKWISE,
    // p2 -> p0 -> p1、またはp1 -> p0 -> p2の順で直線上に並んでいる
    ONLINE_BACK
};

RELATION Relation(const Point& p0, const Point& p1, const Point& p2) {
    Point a{p1 - p0}, b{p2 - p0};
    if (Positive(Cross(a, b))) return COUNTER_CLOCKWISE;
    if (Negative(Cross(a, b))) return CLOCKWISE;
    if (Negative(Dot(a, b))) return ONLINE_BACK;
    if (Smaller(a.normSquare(), b.normSquare())) return ONLINE_FRONT;
    return ON_SEGMENT;
};

} // namespace geometryR2

} // namespace zawa
#line 2 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Distance/PointAndPoint.hpp"

#line 4 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Distance/PointAndPoint.hpp"

namespace zawa {

namespace geometryR2 {

Real Distance(const Point& p0, const Point& p1) {
    return Point{p1 - p0}.norm();
}

Real DistanceSquare(const Point& p0, const Point& p1) {
    return Point{p1 - p0}.normSquare();
}

} // namespace geometryR2

} // namespace zawa
#line 6 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Segment.hpp"

#include <algorithm>
#line 9 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Segment.hpp"

namespace zawa {

namespace geometryR2 {

class Segment {
private:
    Point p0_{}, p1_{};
public:
    /* constructor */
    Segment() = default;
    Segment(const Point& p0, const Point& p1) : p0_{p0}, p1_{p1} {}
    Segment(Real x0, Real y0, Real x1, Real y1) : p0_{x0, y0}, p1_{x1, y1} {}

    /* getter setter */
    const Point& p0() const {
        return p0_;
    }
    Point& p0() {
        return p0_;
    }
    const Point& p1() const {
        return p1_;
    }
    Point& p1() {
        return p1_;
    }

    /* member function */
    bool valid() const {
        return p0_ != p1_;
    }
    bool straddle(const Segment& s) const {
        return Relation(p0_, p1_, s.p0()) * Relation(p0_, p1_, s.p1()) <= 0;
    }
    Real length() const {
        assert(valid());
        return Distance(p0_, p1_);
    }
    Point midpoint() const {
        assert(valid());
        return p0_ + Vector{p1_ - p0_} / static_cast<Real>(2);
    }
};

} // namespace geometryR2

} // namespace zawa
#line 2 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Intersect/SegmentAndSegment.hpp"

#line 4 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Intersect/SegmentAndSegment.hpp"

#line 6 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Intersect/SegmentAndSegment.hpp"

namespace zawa {

namespace geometryR2 {

bool Intersect(const Segment& s0, const Segment& s1) {
    assert(s0.valid());
    assert(s1.valid());
    return s0.straddle(s1) and s1.straddle(s0);
}

} // namespace geometryR2

} // namespace zawa
#line 8 "2334.test.cpp"

#line 10 "2334.test.cpp"
#include <queue>

using namespace zawa;
using namespace geometryR2;

const Real INF{9e18};

Real solve(int N, const std::vector<Point>& P, const Segment& S) {
    std::vector<std::vector<std::pair<int, Real>>> g(N);
    for (int i{} ; i < N ; i++) {
        for (int j{} ; j < N ; j++) {
            if (i == j) continue;
            Segment cur{P[i], P[j]};
            if (Intersect(cur, S)) continue;
            g[i].emplace_back(j, cur.length());
        }
    }
    std::vector<Real> dist(N, INF);
    using qt = std::pair<Real, int>;
    std::priority_queue<qt, std::vector<qt>, std::greater<qt>> que;
    dist[0] = 0;
    que.emplace(dist[0], 0);
    while (que.size()) {
        auto [d, v]{que.top()};
        que.pop();
        if (Smaller(dist[v], d)) continue;
        for (auto [x, w] : g[v]) {
            if (Smaller(dist[v] + w, dist[x])) {
                dist[x] = dist[v] + w;
                que.emplace(dist[x], x);
            }
        }
    }
    return dist[1] + S.length();
}

int main() {
    SetFastIO();
    int NA, NB;
    std::cin >> NA >> NB;
    std::vector<Point> A(NA), B(NB);
    for (auto& a : A) std::cin >> a;
    for (auto& b : B) std::cin >> b;
    Real ans{std::min(
            solve(NA, A, Segment{B[0], B[1]}),
            solve(NB, B, Segment{A[0], A[1]})
            )};
    SetPrecision(10);
    if (Smaller(ans, INF)) {
        std::cout << ans << '\n';
    }
    else {
        std::cout << -1 << '\n';
    }
}
accuracy: 1
time_ms: 80
memory_kb: 34548
final_rank: 15

code_snippet: #line 1 "2334.test.cpp"
#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/problems/2334"

#line 2 "/home/zawatin/compro/cp-documentation/Src/Template/IOSetting.hpp"

#line 2 "/home/zawatin/compro/cp-documentation/Src/Template/TypeAlias.hpp"

#include <cstdint>
#include <cstddef>

namespace zawa {

using i16 = std::int16_t;
using i32 = std::int32_t;
using i64 = std::int64_t;
using i128 = __int128_t;

using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;

using usize = std::size_t;

} // namespace zawa
#line 4 "/home/zawatin/compro/cp-documentation/Src/Template/IOSetting.hpp"

#include <iostream>
#include <iomanip>

namespace zawa {

void SetFastIO() {
    std::cin.tie(nullptr)->sync_with_stdio(false);
}

void SetPrecision(u32 dig) {
    std::cout << std::fixed << std::setprecision(dig);
}

} // namespace zawa
#line 2 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Point.hpp"

#line 2 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Real.hpp"

#line 4 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Real.hpp"

#include <cmath>
#include <cassert>

namespace zawa {

namespace geometryR2 {

using Real = long double;

namespace internal {

Real EPS{1e-12};
constexpr i32 negative{-1};
constexpr i32 zero{};
constexpr i32 positive{1};

} // namespace internal

Real& Eps() {
    return internal::EPS;
}

i32 Sign(Real value) {
    if (value < -Eps()) return internal::negative;
    if (value > Eps()) return internal::positive;
    return internal::zero;
}

bool Zero(Real value) {
    return Sign(value) == internal::zero;
}

bool Positive(Real value) {
    return Sign(value) == internal::positive;
}

bool Negative(Real value) {
    return Sign(value) == internal::negative;
}

bool Equal(Real a, Real b) {
    return Zero(a - b);
}

bool Smaller(Real a, Real b) {
    return Negative(a - b);
}

bool Bigger(Real a, Real b) {
    return Positive(a - b);
}

Real Square(Real value) {
    return (Zero(value) ? value : value * value);
}

Real Sqrt(Real value) {
    assert(!Negative(value));
    return (Zero(value) ? value : sqrtl(value));
}

Real Abs(Real value) {
    return (Negative(value) ? -value : value);
}

} // namespace geometryR2
 
} // namespace zawa
#line 2 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Angle.hpp"

#line 4 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Angle.hpp"

#line 6 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Angle.hpp"

namespace zawa {

namespace geometryR2 {

constexpr Real PI{acosl(-1)};
constexpr Real TAU{static_cast<Real>(2) * PI};

constexpr Real ArcToRadian(Real arc) {
    return (arc * PI) / static_cast<Real>(180);
}

constexpr Real RadianToArc(Real radian) {
    return (radian * static_cast<Real>(180)) / PI;
}

} // namespace geometryR2

} // namespace zawa
#line 5 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Point.hpp"

#line 9 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Point.hpp"

namespace zawa {

namespace geometryR2 {

class Point {
private:
    Real x_{}, y_{};
public:
    /* constructor */
    Point() = default;
    Point(Real x, Real y) : x_{x}, y_{y} {}

    /* getter, setter */
    Real x() const {
        return x_;
    }
    Real& x() {
        return x_;
    }
    Real y() const {
        return y_;
    }
    Real& y() {
        return y_;
    }

    /* operator */
    Point& operator+=(const Point& rhs) {
        x_ += rhs.x();
        y_ += rhs.y();
        return *this;
    }
    friend Point operator+(const Point& lhs, const Point& rhs) {
        return Point{lhs} += rhs;
    }
    Point operator+() const {
        return *this;
    }
    Point& operator-=(const Point& rhs) {
        x_ -= rhs.x();
        y_ -= rhs.y();
        return *this;
    }
    friend Point operator-(const Point& lhs, const Point& rhs) {
        return Point{lhs} -= rhs;
    }
    Point operator-() const {
        return Point{} - *this;
    }
    Point& operator*=(Real k) {
        x_ *= k;
        y_ *= k;
        return *this;
    }
    friend Point operator*(Real k, const Point& p) {
        return Point{p} *= k;
    }
    friend Point operator*(const Point& p, Real k) {
        return Point{p} *= k;
    }
    Point& operator/=(Real k) {
        assert(!Zero(k));
        x_ /= k;
        y_ /= k;
        return *this;
    }
    friend Point operator/(Real k, const Point& p) {
        return Point{p} /= k;
    }
    friend Point operator/(const Point& p, Real k) {
        return Point{p} /= k;
    }
    friend bool operator==(const Point& lhs, const Point& rhs) {
        return Equal(lhs.x(), rhs.x()) and Equal(lhs.y(), rhs.y());
    }
    friend bool operator!=(const Point& lhs, const Point& rhs) {
        return !Equal(lhs.x(), rhs.x()) or !Equal(lhs.y(), rhs.y());
    }
    friend bool operator<(const Point& lhs, const Point& rhs) {
        return Smaller(lhs.x(), rhs.x()) or 
            (Equal(lhs.x(), rhs.x()) and Smaller(lhs.y(), rhs.y()));
    }
    friend bool operator<=(const Point& lhs, const Point& rhs) {
        return Smaller(lhs.x(), rhs.x()) or 
            (Equal(lhs.x(), rhs.x()) and (Smaller(lhs.y(), rhs.y()) or Equal(lhs.y(), rhs.y())));
    }
    friend bool operator>(const Point& lhs, const Point& rhs) {
        return Bigger(lhs.x(), rhs.x()) or
            (Equal(lhs.x(), rhs.x()) and Bigger(lhs.y(), rhs.y()));
    }
    friend bool operator>=(const Point& lhs, const Point& rhs) {
        return Bigger(lhs.x(), rhs.x()) or
            (Equal(lhs.x(), rhs.x()) and (Bigger(lhs.y(), rhs.y()) or Equal(lhs.y(), rhs.y())));
    }
    friend std::istream& operator>>(std::istream& is, Point& p) {
        is >> p.x_ >> p.y_;
        return is;
    }
    friend std::ostream& operator<<(std::ostream& os, const Point& p) {
        os << '(' << p.x_ << ',' << p.y_ << ')';
        return os;
    }
    
    /* member function */
    Real normSquare() const {
        return Square(x_) + Square(y_);
    }
    Real norm() const {
        return Sqrt(normSquare());
    }
    void normalize() {
        assert((*this) != Point{});
        (*this) /= norm(); 
    }
    Point normalized() const {
        Point res{*this};
        res.normalize();
        return res;
    }
    Point rotated(Real radian) const {
        return Point{
            x_ * cosl(radian) - y_ * sinl(radian),
            x_ * sinl(radian) + y_ * cosl(radian)
        };
    }
    void rotate(Real radian) {
        *this = rotated(radian); 
    }
    Point rotatedByArc(Real arc) const {
        return rotated(ArcToRadian(arc));
    }
    void rotateByArc(Real arc) {
        *this = rotatedByArc(arc);
    }
    Real argument() const {
        return (Negative(y_) ? TAU : static_cast<Real>(0)) + atan2l(y_, x_);
    }
    Real argumentByArc() const {
        return RadianToArc(argument());
    }

    /* friend function */
    friend Real Dot(const Point& lhs, const Point& rhs) {
        return lhs.x() * rhs.x() + lhs.y() * rhs.y();
    }
    friend Real Cross(const Point& lhs, const Point& rhs) {
        return lhs.x() * rhs.y() - lhs.y() * rhs.x();
    }
    friend Real Argument(const Point& lhs, const Point& rhs) {
        return rhs.argument() - lhs.argument();
    }
    friend bool ArgComp(const Point& lhs, const Point& rhs) {
        return Smaller(lhs.argument(), rhs.argument());
    }
};

using Vector = Point;

} // namespace geometryR2

} // namespace zawa
#line 2 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Segment.hpp"

#line 2 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Relation.hpp"

#line 5 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Relation.hpp"

namespace zawa {

namespace geometryR2 {

enum RELATION {
    // p0 -> p1 -> p2の順で直線上に並んでいる
    ONLINE_FRONT = -2,
    // (p1 - p0) -> (p2 - p0)が時計回りになっている
    CLOCKWISE,
    // p0 -> p2 -> p1の順で直線上に並んでいる
    ON_SEGMENT,
    // (p1 - p0) -> (p2 - p0)が反時計回りになっている
    COUNTER_CLOCKWISE,
    // p2 -> p0 -> p1、またはp1 -> p0 -> p2の順で直線上に並んでいる
    ONLINE_BACK
};

RELATION Relation(const Point& p0, const Point& p1, const Point& p2) {
    Point a{p1 - p0}, b{p2 - p0};
    if (Positive(Cross(a, b))) return COUNTER_CLOCKWISE;
    if (Negative(Cross(a, b))) return CLOCKWISE;
    if (Negative(Dot(a, b))) return ONLINE_BACK;
    if (Smaller(a.normSquare(), b.normSquare())) return ONLINE_FRONT;
    return ON_SEGMENT;
};

} // namespace geometryR2

} // namespace zawa
#line 2 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Distance/PointAndPoint.hpp"

#line 4 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Distance/PointAndPoint.hpp"

namespace zawa {

namespace geometryR2 {

Real Distance(const Point& p0, const Point& p1) {
    return Point{p1 - p0}.norm();
}

Real DistanceSquare(const Point& p0, const Point& p1) {
    return Point{p1 - p0}.normSquare();
}

} // namespace geometryR2

} // namespace zawa
#line 6 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Segment.hpp"

#include <algorithm>
#line 9 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Segment.hpp"

namespace zawa {

namespace geometryR2 {

class Segment {
private:
    Point p0_{}, p1_{};
public:
    /* constructor */
    Segment() = default;
    Segment(const Point& p0, const Point& p1) : p0_{p0}, p1_{p1} {}
    Segment(Real x0, Real y0, Real x1, Real y1) : p0_{x0, y0}, p1_{x1, y1} {}

    /* getter setter */
    const Point& p0() const {
        return p0_;
    }
    Point& p0() {
        return p0_;
    }
    const Point& p1() const {
        return p1_;
    }
    Point& p1() {
        return p1_;
    }

    /* member function */
    bool valid() const {
        return p0_ != p1_;
    }
    bool straddle(const Segment& s) const {
        return Relation(p0_, p1_, s.p0()) * Relation(p0_, p1_, s.p1()) <= 0;
    }
    Real length() const {
        assert(valid());
        return Distance(p0_, p1_);
    }
    Point midpoint() const {
        assert(valid());
        return p0_ + Vector{p1_ - p0_} / static_cast<Real>(2);
    }
};

} // namespace geometryR2

} // namespace zawa
#line 2 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Intersect/SegmentAndSegment.hpp"

#line 4 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Intersect/SegmentAndSegment.hpp"

#line 6 "/home/zawatin/compro/cp-documentation/Src/GeometryR2/Intersect/SegmentAndSegment.hpp"

namespace zawa {

namespace geometryR2 {

bool Intersect(const Segment& s0, const Segment& s1) {
    assert(s0.valid());
    assert(s1.valid());
    return s0.straddle(s1) and s1.straddle(s0);
}

} // namespace geometryR2

} // namespace zawa
#line 7 "2334.test.cpp"

#line 9 "2334.test.cpp"
#include <queue>

using namespace zawa;
using namespace geometryR2;

const Real INF{9e18};

Real solve(int N, const std::vector<Point>& P, const Segment& S) {
    std::vector<std::vector<std::pair<int, Real>>> g(N);
    for (int i{} ; i < N ; i++) {
        for (int j{} ; j < N ; j++) {
            if (i == j) continue;
            Segment cur{P[i], P[j]};
            if (Intersect(cur, S)) continue;
            g[i].emplace_back(j, cur.length());
        }
    }
    std::vector<Real> dist(N, INF);
    using qt = std::pair<Real, int>;
    std::priority_queue<qt, std::vector<qt>, std::greater<qt>> que;
    dist[0] = 0;
    que.emplace(dist[0], 0);
    while (que.size()) {
        auto [d, v]{que.top()};
        que.pop();
        if (Smaller(dist[v], d)) continue;
        for (auto [x, w] : g[v]) {
            if (Smaller(dist[v] + w, dist[x])) {
                dist[x] = dist[v] + w;
                que.emplace(dist[x], x);
            }
        }
    }
    return dist[1] + S.length();
}

int main() {
    SetFastIO();
    int NA, NB;
    std::cin >> NA >> NB;
    std::vector<Point> A(NA), B(NB);
    for (auto& a : A) std::cin >> a;
    for (auto& b : B) std::cin >> b;
    Real ans{std::min(
            solve(NA, A, Segment{B[0], B[1]}),
            solve(NB, B, Segment{A[0], A[1]})
            )};
    SetPrecision(10);
    if (Smaller(ans, INF)) {
        std::cout << ans << '\n';
    }
    else {
        std::cout << -1 << '\n';
    }
}
accuracy: 1
time_ms: 80
memory_kb: 34544
final_rank: 14

code_snippet: #include <bits/stdc++.h>




namespace zawa {

using i16 = std::int16_t;
using i32 = std::int32_t;
using i64 = std::int64_t;
using i128 = __int128_t;

using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;

using usize = std::size_t;

} // namespace zawa


namespace zawa {

void SetFastIO() {
    std::cin.tie(nullptr)->sync_with_stdio(false);
}

void SetPrecision(u32 dig) {
    std::cout << std::fixed << std::setprecision(dig);
}

} // namespace zawa




namespace zawa {

namespace geometryR2 {

using Real = long double;

namespace internal {

Real EPS{1e-12};
constexpr i32 negative{-1};
constexpr i32 zero{};
constexpr i32 positive{1};

} // namespace internal

Real& Eps() {
    return internal::EPS;
}

i32 Sign(Real value) {
    if (value < -Eps()) return internal::negative;
    if (value > Eps()) return internal::positive;
    return internal::zero;
}

bool Zero(Real value) {
    return Sign(value) == internal::zero;
}

bool Positive(Real value) {
    return Sign(value) == internal::positive;
}

bool Negative(Real value) {
    return Sign(value) == internal::negative;
}

bool Equal(Real a, Real b) {
    return Zero(a - b);
}

bool Smaller(Real a, Real b) {
    return Negative(a - b);
}

bool Bigger(Real a, Real b) {
    return Positive(a - b);
}

Real Square(Real value) {
    return (Zero(value) ? value : value * value);
}

Real Sqrt(Real value) {
    assert(!Negative(value));
    return (Zero(value) ? value : sqrtl(value));
}

Real Abs(Real value) {
    return (Negative(value) ? -value : value);
}

} // namespace geometryR2
 
} // namespace zawa



namespace zawa {

namespace geometryR2 {

constexpr Real PI{acosl(-1)};
constexpr Real TAU{static_cast<Real>(2) * PI};

constexpr Real ArcToRadian(Real arc) {
    return (arc * PI) / static_cast<Real>(180);
}

constexpr Real RadianToArc(Real radian) {
    return (radian * static_cast<Real>(180)) / PI;
}

} // namespace geometryR2

} // namespace zawa


namespace zawa {

namespace geometryR2 {

class Point {
private:
    Real x_{}, y_{};
public:
    /* constructor */
    Point() = default;
    Point(Real x, Real y) : x_{x}, y_{y} {}

    /* getter, setter */
    Real x() const {
        return x_;
    }
    Real& x() {
        return x_;
    }
    Real y() const {
        return y_;
    }
    Real& y() {
        return y_;
    }

    /* operator */
    Point& operator+=(const Point& rhs) {
        x_ += rhs.x();
        y_ += rhs.y();
        return *this;
    }
    friend Point operator+(const Point& lhs, const Point& rhs) {
        return Point{lhs} += rhs;
    }
    Point operator+() const {
        return *this;
    }
    Point& operator-=(const Point& rhs) {
        x_ -= rhs.x();
        y_ -= rhs.y();
        return *this;
    }
    friend Point operator-(const Point& lhs, const Point& rhs) {
        return Point{lhs} -= rhs;
    }
    Point operator-() const {
        return Point{} - *this;
    }
    Point& operator*=(Real k) {
        x_ *= k;
        y_ *= k;
        return *this;
    }
    friend Point operator*(Real k, const Point& p) {
        return Point{p} *= k;
    }
    friend Point operator*(const Point& p, Real k) {
        return Point{p} *= k;
    }
    Point& operator/=(Real k) {
        assert(!Zero(k));
        x_ /= k;
        y_ /= k;
        return *this;
    }
    friend Point operator/(Real k, const Point& p) {
        return Point{p} /= k;
    }
    friend Point operator/(const Point& p, Real k) {
        return Point{p} /= k;
    }
    friend bool operator==(const Point& lhs, const Point& rhs) {
        return Equal(lhs.x(), rhs.x()) and Equal(lhs.y(), rhs.y());
    }
    friend bool operator!=(const Point& lhs, const Point& rhs) {
        return !Equal(lhs.x(), rhs.x()) or !Equal(lhs.y(), rhs.y());
    }
    friend bool operator<(const Point& lhs, const Point& rhs) {
        return Smaller(lhs.x(), rhs.x()) or 
            (Equal(lhs.x(), rhs.x()) and Smaller(lhs.y(), rhs.y()));
    }
    friend bool operator<=(const Point& lhs, const Point& rhs) {
        return Smaller(lhs.x(), rhs.x()) or 
            (Equal(lhs.x(), rhs.x()) and (Smaller(lhs.y(), rhs.y()) or Equal(lhs.y(), rhs.y())));
    }
    friend bool operator>(const Point& lhs, const Point& rhs) {
        return Bigger(lhs.x(), rhs.x()) or
            (Equal(lhs.x(), rhs.x()) and Bigger(lhs.y(), rhs.y()));
    }
    friend bool operator>=(const Point& lhs, const Point& rhs) {
        return Bigger(lhs.x(), rhs.x()) or
            (Equal(lhs.x(), rhs.x()) and (Bigger(lhs.y(), rhs.y()) or Equal(lhs.y(), rhs.y())));
    }
    friend std::istream& operator>>(std::istream& is, Point& p) {
        is >> p.x_ >> p.y_;
        return is;
    }
    friend std::ostream& operator<<(std::ostream& os, const Point& p) {
        os << '(' << p.x_ << ',' << p.y_ << ')';
        return os;
    }
    
    /* member function */
    Real normSquare() const {
        return Square(x_) + Square(y_);
    }
    Real norm() const {
        return Sqrt(normSquare());
    }
    void normalize() {
        assert((*this) != Point{});
        (*this) /= norm(); 
    }
    Point normalized() const {
        Point res{*this};
        res.normalize();
        return res;
    }
    Point rotated(Real radian) const {
        return Point{
            x_ * cosl(radian) - y_ * sinl(radian),
            x_ * sinl(radian) + y_ * cosl(radian)
        };
    }
    void rotate(Real radian) {
        *this = rotated(radian); 
    }
    Point rotatedByArc(Real arc) const {
        return rotated(ArcToRadian(arc));
    }
    void rotateByArc(Real arc) {
        *this = rotatedByArc(arc);
    }
    Real argument() const {
        return (Negative(y_) ? TAU : static_cast<Real>(0)) + atan2l(y_, x_);
    }
    Real argumentByArc() const {
        return RadianToArc(argument());
    }

    /* friend function */
    friend Real Dot(const Point& lhs, const Point& rhs) {
        return lhs.x() * rhs.x() + lhs.y() * rhs.y();
    }
    friend Real Cross(const Point& lhs, const Point& rhs) {
        return lhs.x() * rhs.y() - lhs.y() * rhs.x();
    }
    friend Real Argument(const Point& lhs, const Point& rhs) {
        return rhs.argument() - lhs.argument();
    }
    friend bool ArgComp(const Point& lhs, const Point& rhs) {
        return Smaller(lhs.argument(), rhs.argument());
    }
};

using Vector = Point;

} // namespace geometryR2

} // namespace zawa



namespace zawa {

namespace geometryR2 {

enum RELATION {
    // p0 -> p1 -> p2の順で直線上に並んでいる
    ONLINE_FRONT = -2,
    // (p1 - p0) -> (p2 - p0)が時計回りになっている
    CLOCKWISE,
    // p0 -> p2 -> p1の順で直線上に並んでいる
    ON_SEGMENT,
    // (p1 - p0) -> (p2 - p0)が反時計回りになっている
    COUNTER_CLOCKWISE,
    // p2 -> p0 -> p1、またはp1 -> p0 -> p2の順で直線上に並んでいる
    ONLINE_BACK
};

RELATION Relation(const Point& p0, const Point& p1, const Point& p2) {
    Point a{p1 - p0}, b{p2 - p0};
    if (Positive(Cross(a, b))) return COUNTER_CLOCKWISE;
    if (Negative(Cross(a, b))) return CLOCKWISE;
    if (Negative(Dot(a, b))) return ONLINE_BACK;
    if (Smaller(a.normSquare(), b.normSquare())) return ONLINE_FRONT;
    return ON_SEGMENT;
};

} // namespace geometryR2

} // namespace zawa


namespace zawa {

namespace geometryR2 {

Real Distance(const Point& p0, const Point& p1) {
    return Point{p1 - p0}.norm();
}

Real DistanceSquare(const Point& p0, const Point& p1) {
    return Point{p1 - p0}.normSquare();
}

} // namespace geometryR2

} // namespace zawa


namespace zawa {

namespace geometryR2 {

class Segment {
private:
    Point p0_{}, p1_{};
public:
    /* constructor */
    Segment() = default;
    Segment(const Point& p0, const Point& p1) : p0_{p0}, p1_{p1} {}
    Segment(Real x0, Real y0, Real x1, Real y1) : p0_{x0, y0}, p1_{x1, y1} {}

    /* getter setter */
    const Point& p0() const {
        return p0_;
    }
    Point& p0() {
        return p0_;
    }
    const Point& p1() const {
        return p1_;
    }
    Point& p1() {
        return p1_;
    }

    /* member function */
    bool valid() const {
        return p0_ != p1_;
    }
    bool straddle(const Segment& s) const {
        return Relation(p0_, p1_, s.p0()) * Relation(p0_, p1_, s.p1()) <= 0;
    }
    Real length() const {
        assert(valid());
        return Distance(p0_, p1_);
    }
    Point midpoint() const {
        assert(valid());
        return p0_ + Vector{p1_ - p0_} / static_cast<Real>(2);
    }
};

} // namespace geometryR2

} // namespace zawa



namespace zawa {

namespace geometryR2 {

bool Intersect(const Segment& s0, const Segment& s1) {
    assert(s0.valid());
    assert(s1.valid());
    return s0.straddle(s1) and s1.straddle(s0);
}

} // namespace geometryR2

} // namespace zawa

using namespace zawa;
using namespace geometryR2;

const Real INF{9e18};

Real solve(int n, const std::vector<Point>& P, const Segment& S) {
    std::vector<std::vector<std::pair<int, Real>>> g(n);
    for (int i{} ; i < n ; i++) {
        for (int j{} ; j < n ; j++) {
            if (i == j) continue;
            Segment cur{P[i], P[j]};
            if (Intersect(cur, S)) continue;
            g[i].emplace_back(j, cur.length()); 
        }
    }
    std::vector dist(n, INF);
    dist[0] = 0;
    using qt = std::pair<Real, int>;
    std::priority_queue<qt, std::vector<qt>, std::greater<qt>> que;
    que.emplace(Real{0}, 0);
    while (que.size()) {
        auto [d, v]{que.top()};
        que.pop();
        if (Smaller(dist[v], d)) continue;
        for (auto [x, w] : g[v]) {
            if (Smaller(dist[v] + w, dist[x])) {
                dist[x] = dist[v] + w;
                que.emplace(dist[x], x);
            }
        }
    }
    //std::cout << dist[1] << ' ' << S.length() << std::endl;
    return S.length() + dist[1];
}

int main() {
    std::cin.tie(nullptr)->sync_with_stdio(false);

    int NA, NB;
    std::cin >> NA >> NB;
    std::vector<Point> PA(NA), PB(NB);
    for (int i{} ; i < NA ; i++) {
        std::cin >> PA[i];
    }
    for (int i{} ; i < NB ; i++) {
        std::cin >> PB[i];
    }
    Real ans{std::min(
            solve(NA, PA, Segment{PB[0], PB[1]}),
            solve(NB, PB, Segment{PA[0], PA[1]})
            )};
    SetPrecision(12);
    if (Smaller(ans, INF)) {
        std::cout << ans << '\n';
    }
    else {
        std::cout << -1 << '\n';
    }
}
accuracy: 1
time_ms: 80
memory_kb: 34620
final_rank: 16

code_snippet: #include <bits/stdc++.h>
using namespace std;

template<class T>
bool chmin(T &a, const T &b) {if (a > b) {a = b; return 1;} return 0;}

using ll = long long;
using ld = long double;

bool is_end = false;
mt19937 engine(42);

using pld = pair<ld, ld>;

ld distance(pair<ld, ld> &P, pair<ld, ld> &Q)
{
	ld dx = P.first - Q.first;
	ld dy = P.second - Q.second;
	return sqrt(dx * dx + dy * dy);
}

bool has_collision(pld p0, pld p1, pld q0, pld q1)
{
	auto [x0, y0] = p0;
	auto [x1, y1] = p1;
	
	auto [x2, y2] = q0;
	auto [x3, y3] = q1;
	
	bool ret = true;
	
	{
		// ax + by + c = 0
		ld dx = x1 - x0, dy = y1 - y0;
		ld a = -dy, b = dx, c = - (a * x0 + b * y0);
		ld mul = (a * x2 + b * y2 + c) * (a * x3 + b * y3 + c);
		ret &= (mul < 0);
	}
	{
		// ax + by + c = 0
		ld dx = x3 - x2, dy = y3 - y2;
		ld a = -dy, b = dx, c = - (a * x2 + b * y2);
		ld mul = (a * x0 + b * y0 + c) * (a * x1 + b * y1 + c);
		ret &= (mul < 0);
	}
	
	return ret;
}

void calc()
{
	ll N, M; cin >> N >> M;
	vector<pair<ld, ld>> towna(N), townb(M);
	for (int i = 0; i < N; ++i)
	{
		ld x, y; cin >> x >> y;
		towna[i] = make_pair(x, y);
	}
	for (int i = 0; i < M; ++i)
	{
		ld x, y; cin >> x >> y;
		townb[i] = make_pair(x, y);
	}
	
	const ld INF = 1e18;
	ld res = INF;
	
	// fix A
	{
		ld lena = distance(towna[0], towna[1]);
		
		priority_queue<pair<ld, int>, vector<pair<ld, int>>, greater<pair<ld, int>>> pq;
		vector<ld> dist(M, INF);
		dist[0] = 0.0;
		pq.emplace(dist[0], 0);
		
		while (!pq.empty())
		{
			auto [d, v] = pq.top();
			pq.pop();
			
			if (dist[v] < d) {continue;}
			
			for (int i = 0; i < M; ++i)
			{
				if (i == v) {continue;}
				
				if (!has_collision(towna[0], towna[1], townb[v], townb[i]))
				{
					if (chmin(dist[i], dist[v] + distance(townb[v], townb[i])))
					{
						pq.emplace(dist[i], i);
					}
				}
			}
		}
		
		if (dist[1] < INF)
		{
			chmin(res, lena + dist[1]);
		}
	}
	
	// fix B
	{
		ld lenb = distance(townb[0], townb[1]);
		
		priority_queue<pair<ld, int>, vector<pair<ld, int>>, greater<pair<ld, int>>> pq;
		vector<ld> dist(N, INF);
		dist[0] = 0.0;
		pq.emplace(dist[0], 0);
		
		while (!pq.empty())
		{
			auto [d, v] = pq.top();
			pq.pop();
			
			if (dist[v] < d) {continue;}
			
			for (int i = 0; i < N; ++i)
			{
				if (i == v) {continue;}
				
				if (!has_collision(townb[0], townb[1], towna[v], towna[i]))
				{
					if (chmin(dist[i], dist[v] + distance(towna[v], towna[i])))
					{
						pq.emplace(dist[i], i);
					}
				}
			}
		}
		
		if (dist[1] < INF)
		{
			chmin(res, lenb + dist[1]);
		}
	}
	
	cout << fixed << setprecision(20) << (res < INF ? res : -1) << endl;
	
	return;
}

int main()
{
	calc();
	
	return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 3764
final_rank: 4

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define rep(i, n) for (int i = 0; i < (n); ++i)
#define rrep(i, n) for (int i = (n) - 1; i >= 0; --i)

#define all(c) std::begin(c), std::end(c)

#ifdef LOCAL
#define debug(...) debug_impl(#__VA_ARGS__, __VA_ARGS__)
template <class T, class ...Args> void debug_impl(string s, T&& f, Args &&...args) {
    cerr << "(" << s << "): " << "(" << forward<T>(f);
    ((cerr << ", " << forward<Args>(args)), ..., (cerr << ")\n"));
}
#else
#define debug(...) void(0)
#endif

template <class T> bool chmax(T& a, const T& b) { return b > a ? (a = b, true) : false; }
template <class T> bool chmin(T& a, const T& b) { return b < a ? (a = b, true) : false; }


template <class T> istream& operator>>(istream& in, vector<T>& v) {
    for (auto& e : v) in >> e;
    return in;
}
template <class ...Args> void read(Args&... args) {
    (cin >> ... >> args);
}

template <class T> ostream& operator<<(ostream& out, const vector<T>& v) {
    int n = v.size();
    rep(i, n) {
        out << v[i];
        if (i + 1 != n) out << ' ';
    }
    return out;
}

template <class T, class ...Tails> void print(T&& h, Tails &&... tails) {
    cout << h, ((cout << ' ' << forward<Tails>(tails)), ..., (cout << '\n'));
}

using ld = long double;
using point = complex<ld>;

constexpr ld eps = 1e-10;

ld dot(point const&a, point const &b) {
    return real(conj(a) * b);
}

ld cross(point const&a, point const&b) {
    return imag(conj(a) * b);
}

int ccw(point a, point b, point c) {
    b -= a; c -= a;
    if(cross(b, c) > eps) return 1;
    if(cross(b, c) < -eps) return -1;
    if(dot(b, c) < 0) return 2;
    if(norm(b) < norm(c)) return -2;
    return 0;
}

struct segment {
    segment(point a, point b) : a(a), b(b) {}
    point a, b;
};

bool isis_ss(segment s, segment t) {
    return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b ) <= 0 
    && ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

template <class T> using vc = vector<T>;
template <class T> using vvc = vector<vc<T>>;
#define si(c) (int)(c).size()
#define eb emplace_back
#define mkp make_pair

typedef pair<ld, int> P;

const ld inf = 1e9 + 7;

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

    cout << fixed << setprecision(20);

    int na, nb; read(na, nb);
    vc<point> a(na), b(nb);
    rep(i, na) {
        ld x, y; read(x, y);
        a[i] = point{x, y};
    }
    rep(i, nb) {
        ld x, y; read(x, y);
        b[i] = point(x, y);
    }

    ld ans = inf;

    rep(_, 2) {
        ld now = abs(a[0] - a[1]);
        segment sg(a[0], a[1]);
        vvc<pair<int, ld>> g(nb);
        vc<ld> di(nb, inf);
        di[0] = 0.0;
        rep(i, nb) {
            for(int j = i + 1; j < nb; ++ j) {
                if(!isis_ss(segment(b[i], b[j]), sg)) {
                    debug(i, j);
                    ld dist = abs(b[i] - b[j]);
                    g[i].eb(j, dist); g[j].eb(i, dist);
                }
            }
        }
        priority_queue<pair<ld, int>, vector<pair<ld, int>>, greater<pair<ld, int>>> pque;
        pque.push(P{0.0, 0});
        while(si(pque)) {
            auto [d, v] = pque.top(); pque.pop();
            if(d > di[v]) continue;
            for(auto [nv, cost]: g[v]) {
                if(chmin(di[nv], d + cost)) {
                    pque.push(P{di[nv], nv});
                }
            }
        }
        debug(di[1]);
        if(di[1] != inf) {
            now += di[1];
            chmin(ans, now);
        }
        swap(a, b); swap(na, nb);
    }

    if(ans == inf) print(-1);
    else print(ans);
}
accuracy: 1
time_ms: 110
memory_kb: 37824
final_rank: 17

code_snippet: #pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
// #include<atcoder/scc>
using namespace std;
// using namespace atcoder;

struct Point{
	long double x;
	long double y;
};

long double cross3(Point a, Point b, Point c){
	return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
}

bool iscross(Point a1, Point a2, Point b1, Point b2){
	bool flg1 = cross3(a1, a2, b1) * cross3(a1, a2, b2) < 0;
	bool flg2 = cross3(b1, b2, a1) * cross3(b1, b2, a2) < 0;
	return (flg1 && flg2);
}

long double D(Point a, Point b){
	return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}

void solve(){
	cout << fixed << setprecision(12);
	int na, nb;
	cin >> na >> nb;
	long double x, y;
	vector<Point> A(na);
	for(int i = 0; i < na; i++){
		cin >> x >> y;
		A[i] = {x, y};
	}

	vector<Point> B(nb);
	for(int i = 0; i < nb; i++){
		cin >> x >> y;
		B[i] = {x, y};
	}

	long double inf = 1e60;
	long double ans = inf;

	for(int i = 0; i < 2; i++){
		Point a1 = A[0];
		Point a2 = A[1];
		vector<long double> dist(nb, inf);
		dist[0] = 0;
		priority_queue<pair<long double, int>, vector<pair<long double, int>>, greater<pair<long double, int>>> pq;
		pq.push({0, 0});		
		while(!pq.empty()){
			long double d = pq.top().first;
			int pos = pq.top().second;
			pq.pop();
			if(dist[pos] < d) continue;
			for(int npos = 0; npos < nb; npos++){
				if(npos == pos) continue;
				if(iscross(a1, a2, B[pos], B[npos])) continue;
				long double nd = d + D(B[pos], B[npos]);				
				if(dist[npos] > nd){
					dist[npos] = nd;
					pq.push({nd, npos});
				}
			}
		}
		ans = min(ans, dist[1] + D(a1, a2));

		swap(na, nb);
		swap(A, B);
	}

	if(ans == inf) cout << "-1\n";
	else cout << ans << "\n";
}

int main(){
	cin.tie(0)->sync_with_stdio(0);
	int t;
	t = 1;
	// cin >> t;
	while(t--) solve();
}
accuracy: 1
time_ms: 30
memory_kb: 3808
final_rank: 5

code_snippet: #include <bits/stdc++.h>
//#include <atcoder/all>
//using namespace atcoder;
#pragma GCC target ("avx2")
#pragma GCC optimization ("O3")
#pragma GCC optimization ("unroll-loops")
using namespace std;
 
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<string> VS;
typedef pair<int, int> PII;
typedef pair<int, int> pii;
typedef pair<long long, long long> PLL;
typedef pair<int, PII> TIII;
 
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
 
 
#define FOR(i, s, n) for (int i = s; i < (int)n; ++i)
#define REP(i, n) FOR(i, 0, n)
#define rep(i, a, b) for (int i = a; i < (b); ++i)
#define trav(a, x) for (auto &a : x)
#define all(x) x.begin(), x.end()
 
#define MOD 1000000007
 
template<class T1, class T2> inline bool chmax(T1 &a, T2 b) {if (a < b) {a = b; return true;} return false;}
template<class T1, class T2> inline bool chmin(T1 &a, T2 b) {if (a > b) {a = b; return true;} return false;}
const double EPS = 1e-8, PI = acos(-1);
const double pi = 3.141592653589793238462643383279;
//ここから編集    
typedef string::const_iterator State;
ll GCD(ll a, ll b){
  return (b==0)?a:GCD(b, a%b);
}
ll LCM(ll a, ll b){
  return a/GCD(a, b) * b;
}
template< int mod >
struct ModInt {
  int x;
 
  ModInt() : x(0) {}
 
  ModInt(int64_t y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {}
 
  ModInt &operator+=(const ModInt &p) {
    if((x += p.x) >= mod) x -= mod;
    return *this;
  }
 
  ModInt &operator-=(const ModInt &p) {
    if((x += mod - p.x) >= mod) x -= mod;
    return *this;
  }
 
  ModInt &operator*=(const ModInt &p) {
    x = (int) (1LL * x * p.x % mod);
    return *this;
  }
 
  ModInt &operator/=(const ModInt &p) {
    *this *= p.inverse();
    return *this;
  }
 
  ModInt operator-() const { return ModInt(-x); }
 
  ModInt operator+(const ModInt &p) const { return ModInt(*this) += p; }
 
  ModInt operator-(const ModInt &p) const { return ModInt(*this) -= p; }
 
  ModInt operator*(const ModInt &p) const { return ModInt(*this) *= p; }
 
  ModInt operator/(const ModInt &p) const { return ModInt(*this) /= p; }
 
  bool operator==(const ModInt &p) const { return x == p.x; }
 
  bool operator!=(const ModInt &p) const { return x != p.x; }
 
  ModInt inverse() const {
    int a = x, b = mod, u = 1, v = 0, t;
    while(b > 0) {
      t = a / b;
      swap(a -= t * b, b);
      swap(u -= t * v, v);
    }
    return ModInt(u);
  }
 
  ModInt pow(int64_t n) const {
    ModInt ret(1), mul(x);
    while(n > 0) {
      if(n & 1) ret *= mul;
      mul *= mul;
      n >>= 1;
    }
    return ret;
  }
 
  friend ostream &operator<<(ostream &os, const ModInt &p) {
    return os << p.x;
  }
 
  friend istream &operator>>(istream &is, ModInt &a) {
    int64_t t;
    is >> t;
    a = ModInt< mod >(t);
    return (is);
  }
 
  static int get_mod() { return mod; }
};
 
using modint = ModInt< 1000000007 >;
template< typename T >
struct Combination {
  vector< T > _fact, _rfact, _inv;
 
  Combination(int sz) : _fact(sz + 1), _rfact(sz + 1), _inv(sz + 1) {
    _fact[0] = _rfact[sz] = _inv[0] = 1;
    for(int i = 1; i <= sz; i++) _fact[i] = _fact[i - 1] * i;
    _rfact[sz] /= _fact[sz];
    for(int i = sz - 1; i >= 0; i--) _rfact[i] = _rfact[i + 1] * (i + 1);
    for(int i = 1; i <= sz; i++) _inv[i] = _rfact[i] * _fact[i - 1];
  }
 
  inline T fact(int k) const { return _fact[k]; }
 
  inline T rfact(int k) const { return _rfact[k]; }
 
  inline T inv(int k) const { return _inv[k]; }
 
  T P(int n, int r) const {
    if(r < 0 || n < r) return 0;
    return fact(n) * rfact(n - r);
  }
 
  T C(int p, int q) const {
    if(q < 0 || p < q) return 0;
    return fact(p) * rfact(q) * rfact(p - q);
  }
 
  T H(int n, int r) const {
    if(n < 0 || r < 0) return (0);
    return r == 0 ? 1 : C(n + r - 1, r);
  }
};
 
ll modpow(ll x, ll n, ll mod) {
  ll res = 1;
  x %= mod;
  if(x == 0) return 0;
  while(n) {
    if(n&1) res = (res * x) % mod;
    x = (x * x) % mod;
    n >>= 1;
  }
  return res;
} 
inline long long mod(long long a, long long m) {
    return (a % m + m) % m;
}
template<typename T> 
struct BIT{
  int N;
  std::vector<T> node;
  BIT(){}
  BIT(int n){
    N = n;
    node.resize(N+10);
  }
  void build(int n) {
    N = n;
    node.resize(N+10);
  }
  /* a: 1-indexed */
  void add(int a, T x){
    for(int i=a; i<(int)node.size(); i += i & -i) node[i] += x;
  }

  /* [1, a] */
  T sum(int a){
    T res = 0;
    for(int x=a; x>0; x -= x & -x) res += node[x];
    return res;
  }

  /* [l, r] */
  T rangesum(int l, int r){
    return sum(r) - sum(l-1);
  }

  /* 
    a1+a2+...+aw >= valとなるような最小のwを返す
    @verify https://codeforces.com/contest/992/problem/E
  */
  int lower_bound(T val) {
    if(val < 0) return 0;

    int res = 0;
    int n = 1; 
    while (n < N) n *= 2;

    T tv=0;
    for (int k = n; k > 0; k /= 2) {
      if(res + k < N && node[res + k] < val){
        val -= node[res+k];
        res += k;
      }
    }
    return res+1; 
  }
};

struct UnionFind{
  std::vector<int> par;
  std::vector<int> siz;

  UnionFind(int sz_): par(sz_), siz(sz_) {
    for(int i=0; i<sz_; ++i) par[i] = i, siz[i] = 1;
  }

  void init(int sz_){
    par.resize(sz_);
    siz.resize(sz_);
    for(int i=0; i<sz_; ++i) par[i] = i, siz[i] = 1;
  }

  int root(int x){
    if(x == par[x]) return x;
    return par[x] = root(par[x]);
  }

  bool merge(int x, int y){
    x = root(x), y = root(y);
    if(x == y) return false;
    if(siz[x] < siz[y]) std::swap(x, y);
    siz[x] += siz[y];
    par[y] = x;
    return true;
  }

  bool issame(int x, int y){
    return root(x) == root(y);
  }

  int size(int x){
    return siz[root(x)];
  }
};
struct RollingHash{

    using ull = unsigned long long;
    const ull mod = (1ULL << 61) - 1;
    const ull MASK30 = (1ULL << 30) - 1;
    const ull MASK31 = (1ULL << 31) - 1;

    const ull MASK61 = mod;

    ull base;
    int n;
    vector<ull> hash, pow;

    RollingHash(const string &s)
    {
        random_device rnd;
        mt19937_64 mt(rnd());
        base = 1001;
        
        n = (int)s.size();
        hash.assign(n+1, 0);
        pow.assign(n+1, 1);
        
        for(int i=0; i<n; i++){
            hash[i+1] = calc_mod(mul(hash[i], base) + s[i]);
            pow[i+1] = calc_mod(mul(pow[i], base));
        }
    }

    ull calc_mod(ull x){
        ull xu = x >> 61;
        ull xd = x & MASK61;
        ull res = xu + xd;
        if(res >= mod) res -= mod;
        return res;
    }

    ull mul(ull a, ull b){
        ull au = a >> 31;
        ull ad = a & MASK31;
        ull bu = b >> 31;
        ull bd = b & MASK31;
        ull mid = ad * bu + au * bd;
        ull midu = mid >> 30;
        ull midd = mid & MASK30;
        return calc_mod(au * bu * 2 + midu + (midd << 31) + ad * bd);
    }

    //[l,r)のハッシュ値
    inline ull get(int l, int r){
        ull res = calc_mod(hash[r] + mod*3-mul(hash[l], pow[r-l]));
        return res;
    }
    //string tのハッシュ値
    inline ull get(string t){
        ull res = 0;
        for(int i=0; i<t.size(); i++){
            res = calc_mod(mul(res, base)+t[i]);
        }
        return res;
    }
    //string s中のtの数をカウント
    inline int count(string t) {
        if(t.size() > n) return 0;
        auto hs = get(t);
        int res = 0;
        for(int i=0; i<n-t.size()+1; i++){
            if(get(i, i+t.size()) == hs) res++; 
        }
        return res;
    }

    /* 
        concat 
        @verify https://codeforces.com/problemset/problem/514/C
    */
    inline ull concat(ull h1, ull h2, int h2len){
      return calc_mod(h2 + mul(h1, pow[h2len]));
    }

    // LCPを求める S[a:] T[b:]
    inline int LCP(int a, int b){
        int len = min((int)hash.size()-a, (int)hash.size()-b);
        
        int lb = -1, ub = len;
        while(ub-lb>1){
            int mid = (lb+ub)/2;

            if(get(a, a+mid) == get(b, b+mid)) lb = mid;
            else ub = mid;
        }
        return lb;
    }
};
using Point = complex< double >;
bool eq(double a, double b){ return fabs(a-b) < EPS; }
namespace std {
  bool operator<(const Point a, const Point b) {
    if(eq(a.real(),b.real())) return a.imag() < b.imag();
    return a.real() < b.real();
  }
}

istream &operator>> (istream &is, Point &p) {
  double a, b;
  is >> a >> b;
  p = Point(a, b);
  return is;
}

ostream &operator<< (ostream &os, Point &p) {
  return os << fixed << setprecision(10) << p.real() << " " << p.imag();
}

bool operator<(const Point &a, const Point &b) {
  return a.real() != b.real() ? a.real() < b.real() : a.imag() < b.imag();
}

// rotate Φ(rad)
// x = r * cos(θ + Φ)
//   = r * cos(θ) * cos(Φ) - r * sin(θ) * sin(Φ)
//   = x * cos(Φ) - y * sin(Φ) (∵ cos(θ) = x/r, sin(θ) = y/r)  
Point rotate(double phi, const Point &p) {
  double x = p.real(), y = p.imag();
  return Point(x * cos(phi) - y * sin(phi), x * sin(phi) + y * cos(phi));
}

double radian_to_degree(double r) {
  return (r * 180.0 / PI);
}

double degree_to_radian(double d) {
  return (d * PI / 180.0);
}

struct Line{
  Point a, b;

  Line() = default;

  Line(Point a, Point b) : a(a), b(b){}

  Line(double A, double B, double C){
    //ax + by = c
    if(eq(A, 0)){
      a = Point(0, C/B), b = Point(1, C/B);
    }else if(eq(B, 0)){
      a = Point(C/A, 0), b = Point(C/A, 1);
    }else{
      a = Point(0, C/B), b = Point(C/A, 0);
    }
  }

  friend istream &operator>>(istream &is, Line &a) {
    return is >> a.a >> a.b;
  }
  friend ostream &operator<<(ostream &os, Line &a) {
    return os << a.a << " to " << a.b;
  }
};

struct Segment: Line {
  Segment() = default;

  Segment(Point a, Point b) : Line(a, b) {}
};

struct Circle {
  Point p;
  double r;

  Circle() = default;

  Circle(Point p, double r): p(p), r(r){}
};

using Points = vector<Point>;
using Polygon = vector<Point>;
using Segments = vector<Segment>;
using Lines = vector<Line>;
using Circles = vector<Circle>;

double cross(const Point &a, const Point &b) {
  return a.real() * b.imag() - a.imag() * b.real();
}

double dot(const Point& a, const Point &b) {
  return a.real() * b.real() + a.imag() * b.imag();
}

//https://mathtrain.jp/projection
Point projection(const Line &l, const Point &p){
  double t = dot(p - l.a, l.a-l.b) / norm(l.a - l.b);
  return l.a + (l.a - l.b) * t;
}

Point projection(const Segment &l, const Point &p){
  double t = dot(p - l.a, l.b-l.a) / norm(l.a - l.b);
  return l.a + (l.b - l.a) * t;
}

Point reflection(const Line &l, const Point &p){
  return p + (projection(l, p) - p) * 2.0;
}

int ccw(const Point &a, const Point &b, const Point &c) {
  if(cross(b-a, c-a) > EPS) return 1;   // "COUNTER_CLOCKWISE"
  if(cross(b-a, c-a) < -EPS) return -1; // "CLOCKWISE"
  if(dot(b-a, c-a) < -EPS) return 2;    // "ONLINE_BACK" c-a-b
  if(norm(b-a) < norm(c-a) - EPS) return -2;  // "ONLINE_FRONT" a-b-c
  return 0;                         // "ON_SEGMENT" a-c-b
}

bool parallel(const Line &a, const Line &b){
  return eq(cross(a.a-a.b, b.a-b.b), 0.0);
}
bool orthogonal(const Line &a, const Line &b){
  return eq(dot(a.a-a.b, b.a-b.b), 0.0);
}
enum { OUT, ON, IN };

int contains(const Polygon& Q, const Point& p){
  bool in = false;
  for(int i=0; i<Q.size(); i++){
    Point a = Q[i] - p, b = Q[(i+1)%Q.size()]-p;
    if(a.imag() > b.imag()) swap(a, b);
    if(a.imag() <= 0 && 0 < b.imag() && cross(a, b) < 0) in = !in;
    if(cross(a, b) == 0 && dot(a, b) <= 0) return ON;
  }
  return in ? IN : OUT;
}
bool intersect(const Segment &s, const Point &p){
  return ccw(s.a, s.b, p) == 0;
}

//直線の交差判定
bool intersect(const Line &a, const Line &b) {
  if(parallel(a, b)) return 0;
  return 1;
}

//線分が重なる/端点で交わるときtrue
bool intersect(const Segment &a, const Segment &b) {
  return ccw(a.a, a.b, b.a) * ccw(a.a, a.b, b.b) <= 0 && ccw(b.a, b.b, a.a) * ccw(b.a, b.b, a.b) <= 0;
}


Point crosspoint(const Line &a, const Line &b){
  double d = cross(b.b-b.a, a.b-a.a);
  if(eq(d, 0.0)) return Point(1e9, 1e9); 
  
  return a.a + (a.b - a.a) * cross(b.b-b.a, b.b-a.a) / d;
}

Point crosspoint(const Segment &a, const Segment &b){
  return crosspoint(Line(a.a, a.b), Line(b.a, b.b));
}
double distance(const Point &a, const Point &b){
  return abs(a - b);
}
double distance(const Line &l, const Point &p){
  return abs( cross(p - l.a, l.b-l.a) / abs(l.b-l.a) );
}
double distance(const Segment &s, const Point &p){
  Point r = projection(s, p);
  if(intersect(s, r)) return abs(r-p);
  return min(abs(s.a - p), abs(s.b - p));
}
// double distance(const Line &a, const Line &b){

// }
// double distance(const Line &a, const Segment &b){

// }
double distance(const Segment &a, const Segment &b) {
  return intersect(a, b) ? 0 : min({distance(a, b.a), distance(a, b.b), distance(b, a.a), distance(b, a.b)});
}

/* 2円の交点 */
vector<Point> crosspointCC(Circle C1, Circle C2){
  vector<Point> ps;
  Point ab = C2.p - C1.p;
  double d = abs(ab);
  double rc = (C1.r * C1.r + d * d - C2.r * C2.r) / (2 * d);
  if(eq(d, 0) || C1.r < abs(rc)) return ps;

  double rs = sqrt(C1.r * C1.r - rc*rc);

  Point abN = ab * Point(0, rs/d);
  Point cp = C1.p + rc / d * ab;
  ps.push_back(cp + abN);
  if(!eq(norm(abN), 0))ps.push_back(cp-abN);
  return ps;
}

vector<Point> crosspointCL(Circle C, Line l){
  Point p = projection(l, C.p);

  Point e = (l.b-l.a)/abs(l.b-l.a);
  if(eq(distance(l, C.p), C.r)) {
    return vector<Point>{p, p};
  }
  double base = sqrt(C.r*C.r-norm(p-C.p));
  
  return vector<Point>{p+e*base, p-e*base};
}

/* 円同士の共通部分の面積を求める */
// verify: http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_I date: 2020/10/11
long double AreaofCC(Circle& C1, Circle& C2){
  if(C1.r > C2.r) swap(C1, C2);
  long double nor = norm(C1.p - C2.p);
  long double dist = sqrtl(nor);
  
  if(C1.r + C2.r < dist+EPS) return 0;

  if(dist + C1.r < C2.r + EPS) return C1.r * C1.r * PI;

  long double theta1 = acosl((nor + C1.r*C1.r - C2.r * C2.r)/(2*C1.r*dist));

  long double theta2 = acosl((nor + C2.r*C2.r - C1.r * C1.r)/(2*C2.r*dist));
  
  return (theta1 - sinl(theta1+ theta1) *0.5) * C1.r * C1.r + (theta2 - sinl(theta2+theta2) *0.5) * C2.r * C2.r;
}


Polygon convex_hull(Polygon &p)
{
    int n = (int)p.size(), k = 0;
    if (n <= 2)
        return p;
    sort(p.begin(), p.end());
    vector<Point> ch(n * 2);

    for (int i = 0; i < n; ch[k++] = p[i++])
    {
        while (k >= 2 && cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < 0)
            --k;
    }

    for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = p[i--])
    {
        while (k >= t && cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < 0)
            --k;
    }
    ch.resize(k - 1);
    return ch;
}
double convex_diameter(const Polygon &p)
{
    int n = (int)p.size();
    if (n == 2)
        return abs(p[0] - p[1]);

    int is = 0, js = 0;
    for (int i = 1; i < n; ++i)
    {
        if (imag(p[i]) > imag(p[is]))
            is = i;
        if (imag(p[i]) < imag(p[js]))
            js = i;
    }

    double res = abs(p[is] - p[js]);
    int i, maxi, j, maxj;
    i = maxi = is;
    j = maxj = js;
    do
    {
        if (cross(p[(i + 1) % n] - p[i], p[(j + 1) % n] - p[j]) >= 0)
            j = (j + 1) % n;
        else
            i = (i + 1) % n;
        res = max(res, abs(p[i] - p[j]));
    } while (i != is || j != js);
    return res;
}

Polygon convex_cut(const Polygon &p, const Line l)
{
    Polygon ret;
    for (int i = 0; i < p.size(); ++i)
    {
        Point now = p[i], nxt = p[(i + 1) % p.size()];
        if (ccw(l.a, l.b, now) != -1) //交点が線分l上にあるとき
            ret.push_back(now);
        if (ccw(l.a, l.b, now) * ccw(l.a, l.b, nxt) < 0)
        {
            ret.push_back(crosspoint(Line(now, nxt), l));
        }
    }
    return (ret);
}
double closestpair(Points &a, int l, int r){
  if(r-l<=1) return 1e20;
  int mid = (l+r)/2;

  double X = a[mid].real();
  double d = min(closestpair(a, l, mid), closestpair(a, mid, r));
  inplace_merge(a.begin()+l, a.begin()+mid, a.begin()+r, [](const Point& pa, const Point& pb){
    return pa.imag() < pb.imag();
  });

  Points b;
  for(int i=l; i<r; i++){
    if(abs(a[i].real()-X) >= d) continue;
    for(int j=b.size()-1; j>=0; j--){
      if(abs((a[i]-b[j]).imag()) >= d) break;
      d = min(d, abs(a[i]-b[j]));
    }
    b.push_back(a[i]);
  }
  return d;
}

/* 円の交差判定 */
/* verify: http://judge.u-aizu.ac.jp/onlinejudge/finder.jsp?course=CGL date:2020/10/11 */
int intersectionCC(Circle c1, Circle c2){
  if(c1.r > c2.r) swap(c1, c2);
  double d1 = abs(c1.p-c2.p); 
  double d2 = c1.r + c2.r;
  if(d1 > d2) return 4; /* 互いに交点を持たない */
  else if(d1 == d2) return 3; /* 外接する場合 */
  else{
    if(c2.r == c1.r + d1) return 1; /* 内接する場合 */
    else if(c2.r > c1.r + d1) return 0; /* 包含 */
    else return 2; /* 交点を2つ持つ */
  }
}

/* 点集合が反時計回りに与えられる場合のみ */
double Area(Points &g){
  double res = 0;
  int n = g.size();
  REP(i,n){
    res += cross(g[i], g[(i+1)%n]);
  }
  return res/2.0;
}

/* 内接円 */
/* verify: http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_B&lang=ja date: 2020/10/11 */
pair<Point, double> incircle_of_a_Triangle(Points &p){

  double a = abs(p[1]-p[2]), b = abs(p[2]-p[0]), c = abs(p[0]-p[1]);
  double s = (a+b+c) / 2.0;
  double S = sqrtl(s*(s-a)*(s-b)*(s-c));
  double r = S/s; 
  
  Point pp = (a*p[0]+b*p[1]+c*p[2])/(a+b+c);
  return make_pair(pp, r);
} 

/* 外接円 */
pair<Point, double> circumscribed_circle_of_a_triangle(Points &p){

  Point m1((p[0]+p[1])/2.0), m2((p[1]+p[2])/2.0);
  Point v((p[1]-p[0]).imag(), (p[0]-p[1]).real()), w((p[1]-p[2]).imag(), (p[2]-p[1]).real());

  Line l1(m1, Point(v+m1)), l2(m2, Point(w+m2));

  Point x = crosspoint(l1, l2);
  double r = abs(x-p[0]);
  return make_pair(x, r);
}

/* ある点pを通る円cの接線 */
Points tangent_to_a_circle(Point p, Circle C){
  Points ps;
  double d = abs(C.p-p);
  if(eq(d,0)){
    ps.push_back(p);
  }else if(d>EPS){
    
    double d2 = sqrt(d*d-C.r*C.r);
    
    long double theta = acosl(d2/d);
    //cout << theta << endl;
    Point pp = C.p - p;
    Point p2 = rotate(-theta, pp);

    Point e = p2/abs(p2);
    Point ppp = e*d2;
    ps.push_back(p + ppp);
    p2 = rotate(theta, pp);
    e = p2/abs(p2);
    ppp = e*d2;
    ps.push_back(p + ppp);
    
  }
  return ps;
}

Lines tangent(Circle C1, Circle C2){
  Lines ls;
  if(C1.r < C2.r) swap(C1, C2);
  double d = norm(C1.p - C2.p);
  if(eq(d, 0)) return ls;
  Point u = (C2.p - C1.p) / sqrt(d);
  Point v = rotate(pi/2, u);

  for(double s: {-1, 1}) {
    double h = (C1.r + s * C2.r) / sqrt(d);
    if(eq(1-h*h, 0)) {
      ls.emplace_back(C1.p + u * C1.r, C1.p + (u+v) * C1.r);
    }else if(1-h*h>0){
      Point uu = u*h, vv = v*sqrt(1-h*h);
      ls.emplace_back(C1.p + (uu+vv) * C1.r, C2.p - (uu+vv) * C2.r * s);
      ls.emplace_back(C1.p + (uu-vv) * C1.r, C2.p - (uu-vv) * C2.r * s);
    }
  }
  return ls;
}
Line bisector(Point a, Point b){
    Point A = (a+b)*Point(0.5, 0); 
    return Line(A, A+(b-a)*Point(0, PI/2));
}

Polygon voronoi_cell(Polygon Q, Points P, int s){
    REP(i,P.size()){
        if(i!=s){
            Q = convex_cut(Q, bisector(P[s], P[i]));
        }
    }
    return Q;
}
int main() {  
  cin.tie(0);
  ios::sync_with_stdio(false);
  cout << fixed << setprecision(12);
  
  int n1, n2; cin >> n1 >> n2;
  vector<vector<pair<int, double>>> g1(n1), g2(n2);
  Points p1(n1), p2(n2);
  REP(i,n1) cin >> p1[i];
  REP(i,n2) cin >> p2[i];

  REP(i,n1) {
    for(int j=i+1; j<n1; j++) {
      g1[i].push_back({j, abs(p1[i]-p1[j])});
      g1[j].push_back({i, abs(p1[i]-p1[j])});
    }
  }
  REP(i,n2) {
    for(int j=i+1; j<n2; j++) {
      g2[i].push_back({j, abs(p2[i]-p2[j])});
      g2[j].push_back({i, abs(p2[i]-p2[j])});
    }
  }
  vector<double> d1(n1, 1e9), d2(n2, 1e9);
  {
    priority_queue<pair<double, int>, vector<pair<double, int>>, greater<pair<double, int>>> pq;
    pq.push({0, 0});
    d2[0] = 0;
    while(pq.size()) {
      auto[c, v] = pq.top(); pq.pop();
      if(d2[v] < c) continue;
      for(auto [u, cost]: g2[v]) {
        if(intersect(Segment(p2[u], p2[v]), Segment(p1[0], p1[1]))) continue;
        if(d2[u] > d2[v] + cost) {
          d2[u] = d2[v] + cost;
          pq.push({d2[u], u});
        }
      }
    }
  }
  {
    priority_queue<pair<double, int>, vector<pair<double, int>>, greater<pair<double, int>>> pq;
    pq.push({0, 0});
    d1[0] = 0;
    while(pq.size()) {
      auto[c, v] = pq.top(); pq.pop();
      if(d1[v] < c) continue;
      for(auto [u, cost]: g1[v]) {
        if(intersect(Segment(p1[u], p1[v]), Segment(p2[0], p2[1]))) continue;
        if(d1[u] > d1[v] + cost) {
          d1[u] = d1[v] + cost;
          pq.push({d1[u], u});
        }
      }
    }
  }
  double ans = min(d1[1] + abs(p2[0]-p2[1]), d2[1] + abs(p1[0]-p1[1]));
  if(ans >= 1e9) cout << -1 << endl;
  else cout << ans << endl;
  return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 35852
final_rank: 13

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define all(A) A.begin(),A.end()
using vll = vector<ll>;
#define rep(i, n) for (long long i = 0; i < (long long)(n); i++)

vector<vll> Q = { {1,2,5,6},{2,3,6,7},{3,4,7,8},{5,6,9,10},{6,7,10,11},{7,8,11,12},{9,10,13,14},{10,11,14,15},{11,12,15,16} };
vector<vll> T = { {0,1,2,3,6},{0,1,2,4,7},{0,1,2,5,8},{3,4,5,0,6},{3,4,5,1,7},{3,4,5,2,8},{6,7,8,0,3},{6,7,8,1,4},{6,7,8,2,5} };

double di(pair<double, double> P1, pair<double, double> P2) {
	double dx = P1.first - P2.first;
	double dy = P1.second - P2.second;
	return sqrt(dx * dx + dy * dy);
}

/*bool kousa(pair<double, double> P1, pair<double, double> P2, pair<double, double> Q1, pair<double, double> Q2) {
	double xa = P1.first;
	double xb = P2.first;
	double ya = P1.second;
	double yb = P2.second;
	double xc = Q1.first;
	double xd = Q2.first;
	double yc = Q1.second;
	double yd = Q2.second;
	double s = (xa - xb) * (yc - ya) - (ya - yb) * (xc - xa);
	double t = (xa - xb) * (yd - ya) - (ya - yb) * (xd - xa);
	return (s*t>=0);

}*/


bool kousa(pair<double, double> P1, pair<double, double> P2, pair<double, double> Q1, pair<double, double> Q2) {
	double xa = P1.first;
	double xb = P2.first;
	double ya = P1.second;
	double yb = P2.second;
	double xc = Q1.first;
	double xd = Q2.first;
	double yc = Q1.second;
	double yd = Q2.second;
    //cout<<yd<<endl;
	double s = (xb-xa) * (yc - ya) - (yb-ya) * (xc - xa);
	double t = (xb-xa) * (yd - ya) - (yb-ya) * (xd - xa);

    double s2 = (xd-xc) * (ya - yc) - (yd-yc) * (xa - xc);
	double t2 = (xd-xc) * (yb - yc) - (yd-yc) * (xb - xc);

	//cout<<s2<<" "<<t2<<endl;
    return ((s*t<0)&&(s2*t2<0));

}



int main() {
	ll NA, NB;
	cin >> NA >> NB;
	vector<pair<double, double>> A(NA);
	rep(i, NA) {
		double X,Y;
		cin >> X >> Y;
		A[i] = make_pair(X, Y);
	}

	vector<pair<double, double>> B(NB);
	rep(i, NB) {
		double X, Y;
		cin >> X >> Y;
		B[i] = make_pair(X, Y);
	}
	double an = 1e18;

	double a = di(A[0], A[1]);
	vector<double> dist(NB, 1e18);
	priority_queue<pair<double, ll>, vector<pair<double, ll>>, greater<pair<double, ll>>> Q;
	dist[0] = 0.0;
	Q.push(make_pair(0.0, 0));
	vector<bool> seen(NB, false);
	while (!Q.empty()) {
		auto p = Q.top();
		Q.pop();
		if (seen[p.second])continue;
		seen[p.second] = true;
		rep(i, NB) {
			if (i == p.second)continue;
			if (seen[i])continue;

			double d = di(B[p.second],B[i]);

			if (kousa(A[0], A[1], B[p.second], B[i]))continue;
			if (dist[p.second] + d >= dist[i])continue;

			dist[i] = dist[p.second] + d;
			Q.push(make_pair(dist[i], i));

		}

	}
	an = min(an, a+dist[1]);

	double b = di(B[0], B[1]);
	dist.assign(NA, 1e18);
	dist[0] = 0.0;
	Q.push(make_pair(0.0, 0));
	seen.assign(NA, false);
	while (!Q.empty()) {
		auto p = Q.top();
		Q.pop();
		if (seen[p.second])continue;
		seen[p.second] = true;
		rep(i, NA) {
			if (i == p.second)continue;
			if (seen[i])continue;

			double d = di(A[p.second],A[i]);

			if (kousa(B[0], B[1], A[p.second], A[i]))continue;
			if (dist[p.second] + d >= dist[i])continue;

			dist[i] = dist[p.second] + d;
			Q.push(make_pair(dist[i], i));

		}

	}
	an = min(an, b+dist[1]);
	if(an<1e17){
		cout<<fixed<<setprecision(16)<<an<<endl;
	}
	else cout<<-1<<endl;
	//cout << (an < 1e17 ? an : -1) << endl;
}
accuracy: 1
time_ms: 10
memory_kb: 3628
final_rank: 1

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i, s, t) for (int i = (int)(s); i < (int)(t); ++i)

using T = double;
using Vec = std::complex<T>;

constexpr T eps = 1e-12;
inline bool eq(T a, T b) { return std::abs(a - b) < eps; }
inline bool lt(T a, T b) { return a < b - eps; }
inline bool leq(T a, T b) { return a < b + eps; }

std::istream& operator>>(std::istream& is, Vec& p) {
    T x, y;
    is >> x >> y;
    p = {x, y};
    return is;
}

T dot(const Vec& a, const Vec& b) {
    return (std::conj(a) * b).real();
}

T cross(const Vec& a, const Vec& b) {
    return (std::conj(a) * b).imag();
}

Vec rot(const Vec& a, T ang) {
    return a * Vec(std::cos(ang), std::sin(ang));
}

bool are_colinear(const Vec& a, const Vec& b, const Vec& c) {
    return eq(cross(b - a, c - a), 0);
}

bool ccw(const Vec& a, const Vec& b, const Vec& c) {
    return lt(-cross(b - a, c - a), 0);
}

bool intersect(const Vec& a, const Vec& b, const Vec& c, const Vec& d) {
    return ccw(a, c, d) != ccw(b, c, d) && ccw(a, b, c) != ccw(a, b, d);
}

bool on_segment(const Vec& a, const Vec& b, const Vec& p) {
    Vec u = a - p, v = b - p;
    return eq(cross(u, v), 0) && lt(dot(u, v), 0);
}

T line_point_dist(const Vec& a, const Vec& b, const Vec& p) {
    const T l2 = std::norm(b - a);
    const T t = dot(p - a, b - a) / l2;
    const Vec q = a + t * (b - a);
    return std::abs(p - q);
}

T segment_point_distance(const Vec& a, const Vec& b, const Vec& p) {
    const T l2 = std::norm(b - a);
    const T t = std::max(T(0), std::min(T(1), dot(p - a, b - a) / l2));
    const Vec q = a + t * (b - a);
    return std::abs(p - q);
}

Vec intersection(const Vec& a, const Vec& b, const Vec& c, const Vec& d) {
    Vec p = b - a;
    Vec q = d - c;
    Vec r = c - a;
    assert(!eq(cross(q, p), 0)); // not parallel
    return a + cross(q, r) / cross(q, p) * p;
}

std::vector<Vec> intersection_circles(const Vec& c1, T r1, const Vec& c2, T r2) {
    T d = std::abs(c1 - c2);
    // if the circles are outside of each other
    if (lt(r1 + r2, d)) return {};
    // if one contains the other entirely
    if (lt(d, std::abs(r2 - r1))) return {};
    T x = (r1*r1 - r2*r2 + d*d) / (2*d);
    T y = std::sqrt(r1*r1 - x*x);
    Vec e1 = (c2 - c1) / std::abs(c2 - c1);
    Vec e2 = Vec(-e1.imag(), e1.real());
    return {c1 + x*e1 + y*e2, c1 + x*e1 - y*e2};
}

std::vector<Vec> intersection_circle_line(const Vec& c, T r, const Vec& p1, const Vec& p2) {
    T d = line_point_dist(p1, p2, c);
    // no intersection
    if (lt(r, d)) return {};
    Vec e1 = (p2 - p1) / std::abs(p2 - p1);
    Vec e2 = Vec(-e1.imag(), e1.real());
    T t = std::sqrt(r*r - d*d);
    if (eq(d, 0)) return {c + t*e1, c - t*e1};
    if (ccw(c, p1, p2)) e2 *= -1;
    if (eq(r, d)) return {c + d*e2};
    return {c + d*e2 + t*e1, c + d*e2 - t*e1};
}

T area(const Vec& A, const Vec& B, const Vec& C) {
    return std::abs(cross(B - A, C - A)) / T(2);
}

Vec centroid(const Vec& A, const Vec& B, const Vec& C) {
    assert(!are_colinear(A, B, C));
    return (A + B + C) / T(3);
}

Vec circumcenter(const Vec& A, const Vec& B, const Vec& C) {
    assert(!are_colinear(A, B, C));
    T a = std::abs(B - C);
    T b = std::abs(C - A);
    T c = std::abs(A - B);
    T cosA = (b*b + c*c - a*a) / (2*b*c);
    T cosB = (c*c + a*a - b*b) / (2*c*a);
    T cosC = (a*a + b*b - c*c) / (2*a*b);
    return (a*cosA*A + b*cosB*B + c*cosC*C) / (a*cosA + b*cosB + c*cosC);
}

Vec incenter(const Vec& A, const Vec& B, const Vec& C) {
    assert(!are_colinear(A, B, C));
    T a = std::abs(B - C);
    T b = std::abs(C - A);
    T c = std::abs(A - B);
    return (a*A + b*B + c*C) / (a + b + c);
}

std::vector<Vec> convex_hull(std::vector<Vec>& points) {
    int n = points.size();
    std::sort(points.begin(), points.end(), [](const Vec& v1, const Vec& v2) {
        return (v1.imag() != v2.imag()) ? (v1.imag() < v2.imag()) : (v1.real() < v2.real());
    });
    int k = 0; // the number of vertices in the convex hull
    std::vector<Vec> ch(2 * n);
    // right
    for (int i = 0; i < n; ++i) {
        while (k > 1 && lt(cross(ch[k-1] - ch[k-2], points[i] - ch[k-1]), 0)) --k;
        ch[k++] = points[i];
    }
    int t = k;
    // left
    for (int i = n - 2; i >= 0; --i) {
        while (k > t && lt(cross(ch[k-1] - ch[k-2], points[i] - ch[k-1]), 0)) --k;
        ch[k++] = points[i];
    }
    ch.resize(k - 1);
    return ch;
}

template <typename T>
struct Edge {
    int from, to;
    T weight;
    Edge() = default;
    Edge(int to, T weight) : from(-1), to(to), weight(weight) {}
    Edge(int from, int to, T weight) : from(from), to(to), weight(weight) {}
};

template <typename T>
std::vector<T> dijkstra(const std::vector<std::vector<Edge<T>>>& G, int s) {
    std::vector<T> dist(G.size(), std::numeric_limits<T>::max());
    dist[s] = 0;
    using P = std::pair<T, int>;
    std::priority_queue<P, std::vector<P>, std::greater<P>> pq;
    pq.emplace(0, s);

    while (!pq.empty()) {
        T d;
        int v;
        std::tie(d, v) = pq.top();
        pq.pop();
        if (dist[v] < d) continue;
        for (auto& e : G[v]) {
            if (dist[e.to] > d + e.weight) {
                dist[e.to] = d + e.weight;
                pq.emplace(dist[e.to], e.to);
            }
        }
    }

    return dist;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed << setprecision(15);

    int NA, NB;
    cin >> NA >> NB;
    vector<Vec> A(NA), B(NB);
    for (auto& v : A) cin>> v;
    for (auto& v : B) cin>> v;
    // A
    double ans = 1e9;
    {
        vector<vector<Edge<double>>> G(NB);
        rep(i,0,NB) rep(j,i+1, NB) {
            if (!intersect(A[0], A[1], B[i], B[j])) {
                G[i].push_back({j, abs(B[i] - B[j])});
                G[j].push_back({i, abs(B[i] - B[j])});
            }
        }
        auto dist = dijkstra(G, 0);
        ans = min(ans, abs(A[0] - A[1]) + dist[1]);
    }
    {
        vector<vector<Edge<double>>> G(NA);
        rep(i,0,NA) rep(j,i+1, NA) {
            if (!intersect(A[i], A[j], B[0], B[1])) {
                G[i].push_back({j, abs(A[i] - A[j])});
                G[j].push_back({i, abs(A[i] - A[j])});
            }
        }
        auto dist = dijkstra(G, 0);
        ans = min(ans, abs(B[0] - B[1]) + dist[1]);
    }
    cout << (ans < 1e9 ? ans : -1) << endl;
}
accuracy: 1
time_ms: 40
memory_kb: 20868
final_rank: 12

code_snippet: /**
 *    author:  otera
 *    created: 27.10.2021 02:29:21 
**/
#include<bits/stdc++.h>
using namespace std;

using ll = long long;
using ld = long double;
using ull = unsigned long long;
using uint = unsigned;
#define repa(i, n) for(int i = 0; i < n; ++ i)
#define repb(i, a, b) for(int i = a; i < b; ++ i)
#define repc(i, a, b, c) for(int i = a; i < b; i += c)
#define overload4(a, b, c, d, e, ...) e
#define rep(...) overload4(__VA_ARGS__, repc, repb, repa)(__VA_ARGS__)
#define rep1a(i, n) for(int i = 0; i <= n; ++ i)
#define rep1b(i, a, b) for(int i = a; i <= b; ++ i)
#define rep1c(i, a, b, c) for(int i = a; i <= b; i += c)
#define rep1(...) overload4(__VA_ARGS__, rep1c, rep1b, rep1a)(__VA_ARGS__)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define per1(i,n) for(int i=n;i>=1;i--)
typedef pair<int, int> P;
typedef pair<ll, ll> LP;
// #define pb push_back
#define eb emplace_back
#define fr first
#define sc second
#define all(c) c.begin(),c.end()
#define lb(c, x) distance((c).begin(), lower_bound(all(c), (x)))
#define ub(c, x) distance((c).begin(), upper_bound(all(c), (x)))
#define Sort(a) sort(all(a))
#define Rev(a) reverse(all(a))
#define Uniq(a) sort(all(a));a.erase(unique(all(a)),end(a))
#define si(c) (int)(c).size()
inline ll popcnt(ull a){ return __builtin_popcountll(a); }
#define tpow(n) (1LL<<(n))
#define unless(A) if(!(A))
ll intpow(ll a, ll b){ ll ans = 1; while(b){ if(b & 1) ans *= a; a *= a; b /= 2; } return ans; }
ll intpow(ll a, ll b, ll m) {ll ans = 1; while(b){ if(b & 1) (ans *= a) %= m; (a *= a) %= m; b /= 2; } return ans; }
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }
#define INT(...) int __VA_ARGS__;in(__VA_ARGS__)
#define LL(...) ll __VA_ARGS__;in(__VA_ARGS__)
#define ULL(...) ull __VA_ARGS__;in(__VA_ARGS__)
#define STR(...) string __VA_ARGS__;in(__VA_ARGS__)
#define CHR(...) char __VA_ARGS__;in(__VA_ARGS__)
#define DBL(...) double __VA_ARGS__;in(__VA_ARGS__)
#define LD(...) ld __VA_ARGS__;in(__VA_ARGS__)
#define vec(type,name,...) vector<type>name(__VA_ARGS__)
#define VEC(type,name,size) vector<type>name(size);in(name)
#define vv(type,name,h,...) vector<vector<type>>name(h,vector<type>(__VA_ARGS__))
#define VV(type,name,h,w) vector<vector<type>>name(h,vector<type>(w));in(name)
#define vvv(type,name,h,w,...) vector<vector<vector<type>>>name(h,vector<vector<type>>(w,vector<type>(__VA_ARGS__)))
template <class T> using vc = vector<T>;
template <class T> using vvc = vector<vc<T>>;
template <class T> using vvvc = vector<vvc<T>>;
template <class T> using vvvvc = vector<vvvc<T>>;
template <class T> using pq = priority_queue<T>;
template <class T> using pqg = priority_queue<T, vector<T>, greater<T>>;
template<class T> void scan(T& a){ cin >> a; }
template<class T> void scan(vector<T>& a){ for(auto&& i : a) scan(i); }
void in(){}
template <class Head, class... Tail> void in(Head& head, Tail&... tail){ scan(head); in(tail...); }
void print(){ cout << ' '; }
template<class T> void print(const T& a){ cout << a; }
template<class T> void print(const vector<T>& a){ if(a.empty()) return; print(a[0]); for(auto i = a.begin(); ++i != a.end(); ){ cout << ' '; print(*i); } }
int out(){ cout << '\n'; return 0; }
template<class T> int out(const T& t){ print(t); cout << '\n'; return 0; }
template<class Head, class... Tail> int out(const Head& head, const Tail&... tail){ print(head); cout << ' '; out(tail...); return 0; }
#define CHOOSE(a) CHOOSE2 a
#define CHOOSE2(a0,a1,a2,a3,a4,x,...) x
#define debug_1(x1) cout<<#x1<<": "<<x1<<endl
#define debug_2(x1,x2) cout<<#x1<<": "<<x1<<", "#x2<<": "<<x2<<endl
#define debug_3(x1,x2,x3) cout<<#x1<<": "<<x1<<", "#x2<<": "<<x2<<", "#x3<<": "<<x3<<endl
#define debug_4(x1,x2,x3,x4) cout<<#x1<<": "<<x1<<", "#x2<<": "<<x2<<", "#x3<<": "<<x3<<", "#x4<<": "<<x4<<endl
#define debug_5(x1,x2,x3,x4,x5) cout<<#x1<<": "<<x1<<", "#x2<<": "<<x2<<", "#x3<<": "<<x3<<", "#x4<<": "<<x4<<", "#x5<<": "<<x5<<endl
#ifdef DEBUG
#define debug(...) CHOOSE((__VA_ARGS__,debug_5,debug_4,debug_3,debug_2,debug_1,~))(__VA_ARGS__)
#define dump(...) { print(#__VA_ARGS__); print(":"); out(__VA_ARGS__); }
#else
#define debug(...)
#define dump(...)
#endif

#ifndef SUISEN_GEOMETRY
#define SUISEN_GEOMETRY

#include <algorithm>
#include <cassert>
#include <complex>
#include <iostream>
#include <optional>
#include <tuple>
#include <variant>
#include <vector>

namespace suisen {
namespace geometry {

    using coordinate_t = long double;
    using Point = std::complex<coordinate_t>;

    // operator

    Point operator+(const Point &p, coordinate_t real) { return Point(p) + Point(real, 0); }
    Point operator-(const Point &p, coordinate_t real) { return Point(p) - Point(real, 0); }
    Point operator*(const Point &p, coordinate_t real) { return Point(p) * Point(real, 0); }
    Point operator/(const Point &p, coordinate_t real) { return Point(p) / Point(real, 0); }
    Point operator+(coordinate_t real, const Point &p) { return Point(real, 0) + Point(p); }
    Point operator-(coordinate_t real, const Point &p) { return Point(real, 0) - Point(p); }
    Point operator*(coordinate_t real, const Point &p) { return Point(real, 0) * Point(p); }
    Point operator/(coordinate_t real, const Point &p) { return Point(real, 0) / Point(p); }

    std::istream& operator>>(std::istream &in, Point &p) {
        coordinate_t x, y;
        in >> x >> y;
        p = Point(x, y);
        return in;
    }
    std::ostream& operator<<(std::ostream &out, const Point &p) {
        return out << p.real() << ' ' << p.imag();
    }

    // relations between three points X, Y, Z.

    struct ISP {
        static constexpr int L_CURVE = +1; // +---------------+ Z is in 'a' => ISP = +1
        static constexpr int R_CURVE = -1; // |aaaaaaaaaaaaaaa| Z is in 'b' => ISP = -1
        static constexpr int FRONT   = +2; // |ddd X eee Y ccc| Z is in 'c' => ISP = +2
        static constexpr int BACK    = -2; // |bbbbbbbbbbbbbbb| Z is in 'd' => ISP = -2
        static constexpr int MIDDLE  =  0; // +---------------+ Z is in 'e' => ISP =  0
    };

    struct Sign {
        static constexpr int NEGATIVE = -1;
        static constexpr int ZERO = 0;
        static constexpr int POSITIVE = +1;
    };

    enum class Containment {
        OUT, ON, IN
    };

    constexpr Point ZERO = Point(0, 0);
    constexpr Point ONE  = Point(1, 0);
    constexpr Point I    = Point(0, 1);
    constexpr coordinate_t EPS = 1e-9;
    constexpr coordinate_t PI  = 3.14159265358979323846264338327950288419716939937510L;
    constexpr coordinate_t E   = 2.71828182845904523536028747135266249775724709369995L;

    constexpr auto XY_COMPARATOR = [](const Point &p, const Point &q) {
        return p.real() == q.real() ? p.imag() < q.imag() : p.real() < q.real();
    };
    constexpr auto XY_COMPARATOR_GREATER = [](const Point &p, const Point &q) {
        return p.real() == q.real() ? p.imag() > q.imag() : p.real() > q.real();
    };
    constexpr auto YX_COMPARATOR = [](const Point &p, const Point &q) {
        return p.imag() == q.imag() ? p.real() < q.real() : p.imag() < q.imag();
    };
    constexpr auto YX_COMPARATOR_GREATER = [](const Point &p, const Point &q) {
        return p.imag() == q.imag() ? p.real() > q.real() : p.imag() > q.imag();
    };

    int sgn(coordinate_t x) {
        return x > EPS ? Sign::POSITIVE : x < -EPS ? Sign::NEGATIVE : Sign::ZERO;
    }
    int compare(coordinate_t x, coordinate_t y) {
        return sgn(x - y);
    }

    auto cartesian(const coordinate_t real, const coordinate_t imag) {
        return Point(real, imag);
    }
    auto polar(const coordinate_t rho, const coordinate_t theta) {
        return Point(rho * std::cos(theta), rho * std::sin(theta));
    }
    auto cis(const coordinate_t theta) {
        return Point(std::cos(theta), std::sin(theta));
    }
    auto conj(const Point &z) {
        return Point(z.real(), -z.imag());
    }
    auto arg(const Point &z) {
        return std::atan2(z.imag(), z.real());
    }
    auto square_abs(const Point &z) {
        return z.real() * z.real() + z.imag() * z.imag();
    }
    auto abs(const Point &z) {
        return std::sqrt(square_abs(z));
    }
    auto rot(const Point &z, const coordinate_t theta) {
        return cis(theta) * z;
    }
    auto dot(const Point &a, const Point &b) {
        return a.real() * b.real() + a.imag() * b.imag();
    }
    auto det(const Point &a, const Point &b) {
        return a.real() * b.imag() - a.imag() * b.real();
    }
    bool equals(const Point &a, const Point &b) {
        return sgn(a.real() - b.real()) == Sign::ZERO and sgn(a.imag() - b.imag()) == Sign::ZERO;
    }
    bool equals(coordinate_t a, coordinate_t b) {
        return compare(a, b) == 0;
    }
    
    // https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_1_C
    int isp(const Point &a, const Point &b, const Point &c) {
        Point ab = b - a, ac = c - a;
        int s = sgn(det(ab, ac));
        if (s == Sign::POSITIVE) return ISP::L_CURVE;
        if (s == Sign::NEGATIVE) return ISP::R_CURVE;
        if (sgn(dot(ab, ac)) == Sign::NEGATIVE) return ISP::BACK;
        Point ba = a - b, bc = c - b;
        if (sgn(dot(ba, bc)) == Sign::NEGATIVE) return ISP::FRONT;
        return ISP::MIDDLE;
    }

    struct Line {
        Point a, b;
        Line() : Line(ZERO, ZERO) {}
        Line(const Point &from, const Point &to) : a(from), b(to) {}
    };
    struct Ray {
        Point a, b;
        Ray() : Ray(ZERO, ZERO) {}
        Ray(const Point &from, const Point &to) : a(from), b(to) {}
    };
    struct Segment {
        Point a, b;
        Segment() : Segment(ZERO, ZERO) {}
        Segment(const Point &from, const Point &to) : a(from), b(to) {}
    };
    struct Circle {
        Point center;
        coordinate_t radius;
        Circle() : Circle(ZERO, 0) {}
        Circle(const Point &c, const coordinate_t &r) : center(c), radius(r) {}
    };

    // Triangle
    
    coordinate_t signed_area(const Point &a, const Point &b, const Point &c) {
        return det(b - a, c - a) / 2;
    }
    coordinate_t area(const Point &a, const Point &b, const Point &c) {
        return std::abs(signed_area(a, b, c));
    }
    Point pG(const Point &a, const Point &b, const Point &c) {
        return (a + b + c) / 3;
    }
    // https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_B
    Circle pI(const Point &a, const Point &b, const Point &c) {
        auto la = std::abs(b - c), lb = std::abs(c - a), lc = std::abs(a - b);
        auto l = la + lb + lc;
        la /= l, lb /= l, lc /= l;
        Point center = la * a + lb * b + lc * c;
        auto radius = 2. * area(a, b, c) / l;
        return Circle(center, radius);
    }
    // https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_C
    Circle pO(const Point &a, const Point &b, const Point &c) {
        Point ab = b - a, bc = c - b, ca = a - c;
        auto la = square_abs(bc), lb = square_abs(ca), lc = square_abs(ab);
        auto s = la * (lb + lc - la), t = lb * (lc + la - lb), u = lc * (la + lb - lc);
        auto l = s + t + u;
        s /= l, t /= l, u /= l;
        Point center = a * s + b * t + c * u;
        return Circle(center, std::abs(center - a));
    }
    Point pH(const Point &a, const Point &b, const Point &c) {
        return a + b + c - 2 * pO(a, b, c).center;
    }
    auto pIabc(const Point &a, const Point &b, const Point &c) {
        return std::make_tuple(pI(-a, b, c), pI(a, -b, c), pI(a, b, -c));
    }

    // Line

    // https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_A
    template <typename line_t_1, typename line_t_2>
    auto is_parallel(const line_t_1 &l1, const line_t_2 &l2) -> decltype(l1.a, l1.b, l2.a, l2.b, bool()) {
        return sgn(det(l1.b - l1.a, l2.b - l2.a)) == Sign::ZERO;
    }
    // https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_A
    template <typename line_t_1, typename line_t_2>
    auto is_orthogonal(const line_t_1 &l1, const line_t_2 &l2) -> decltype(l1.a, l1.b, l2.a, l2.b, bool())  {
        return sgn(dot(l1.b - l1.a, l2.b - l2.a)) == Sign::ZERO;
    }
    template <typename line_t_1, typename line_t_2>
    auto on_the_same_line(const line_t_1 &l1, const line_t_2 &l2) -> decltype(l1.a, l1.b, l2.a, l2.b, bool())  {
        return is_parallel(l1, l2) and sgn(det(l1.b - l1.a, l2.a - l1.a)) == Sign::ZERO;
    }

    // https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_1_A
    template <typename line_t>
    Point projection(const Point &p, const line_t &line) {
        Point a = p - line.a;
        Point b = line.b - line.a;
        return line.a + dot(a, b) / square_abs(b) * b;
    }

    // https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_1_B
    template <typename line_t>
    Point reflection(const Point &p, const line_t &line) {
        Point h = projection(p, line);
        return p + (h - p) * 2;
    }

    // https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_D
    coordinate_t square_distance(const Point &p, const Segment &l) {
        Point h = projection(p, l);
        if (isp(l.a, l.b, h) == ISP::MIDDLE) {
            return square_abs(h - p);
        } else {
            return std::min(square_abs(p - l.a), square_abs(p - l.b));
        }
    }
    coordinate_t square_distance(const Segment &l, const Point &p) {
        return square_distance(p, l);
    }
    coordinate_t square_distance(const Point &p, const Ray &l) {
        Point h = projection(p, l);
        int dir = isp(l.a, l.b, h);
        return dir == ISP::MIDDLE or dir == ISP::FRONT ? square_abs(h - p) : std::min(square_abs(p - l.a), square_abs(p - l.b));
    }
    coordinate_t square_distance(const Ray &l, const Point &p) {
        return square_distance(p, l);
    }
    coordinate_t square_distance(const Point &p, const Line &l) {
        return square_abs(projection(p, l) - p);
    }
    coordinate_t square_distance(const Line &l, const Point &p) {
        return square_distance(p, l);
    }
    // https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_D
    coordinate_t distance(const Point &p, const Segment &l) {
        return std::sqrt(square_distance(p, l));
    }
    // https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_D
    coordinate_t distance(const Segment &l, const Point &p) {
        return distance(p, l);
    }
    coordinate_t distance(const Point &p, const Ray &l) {
        return std::sqrt(square_distance(p, l));
    }
    coordinate_t distance(const Ray &l, const Point &p) {
        return distance(p, l);
    }
    coordinate_t distance(const Point &p, const Line &l) {
        return std::sqrt(square_distance(p, l));
    }
    coordinate_t distance(const Line &l, const Point &p) {
        return distance(p, l);
    }

    Containment contains(const Segment &l, const Point &p) {
        return sgn(distance(l, p)) == 0 ? Containment::ON : Containment::OUT;
    }
    Containment contains(const Ray &l, const Point &p) {
        return sgn(distance(l, p)) == 0 ? Containment::ON : Containment::OUT;
    }
    Containment contains(const Line &l, const Point &p) {
        return sgn(distance(l, p)) == 0 ? Containment::ON : Containment::OUT;
    }

    bool equals(const Line &l, const Line &m) {
        return on_the_same_line(l, m);
    }
    bool equals(const Ray &l, const Ray &m) {
        return on_the_same_line(l, m) and equals(l.a, m.a);
    }
    bool equals(const Segment &l, const Segment &m) {
        return (equals(l.a, m.a) and equals(l.b, m.b)) or (equals(l.a, m.b) and equals(l.b, m.a));
    }

    // "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_B"
    bool has_common_point(const Segment &l1, const Segment &l2) {
        int isp_1a = isp(l1.a, l1.b, l2.a), isp_1b = isp(l1.a, l1.b, l2.b);
        if (isp_1a * isp_1b > 0) return false;
        int isp_2a = isp(l2.a, l2.b, l1.a), isp_2b = isp(l2.a, l2.b, l1.b);
        if (isp_2a * isp_2b > 0) return false;
        return true;
    }

    namespace internal {
        template <typename line_t_1, typename line_t_2>
        Point cross_point(const line_t_1 &l1, const line_t_2 &l2) {
            assert(not is_parallel(l1, l2));
            Point u = l1.b - l1.a, v = l2.a - l2.b, c = l2.a - l1.a;
            return l2.a - det(u, c) / det(u, v) * v;
        }
    }

    // "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_C"
    std::variant<std::nullptr_t, Point, Segment> common_point(const Segment &l1, const Segment &l2) {
        if (not has_common_point(l1, l2)) return nullptr;
        if (not is_parallel(l1, l2)) return internal::cross_point(l1, l2);
        std::vector<Point> ps { l1.a, l1.b, l2.a, l2.b };
        for (int i = 0; i <= 2; ++i) for (int j = 2; j >= i; --j) {
            if (XY_COMPARATOR(ps[j + 1], ps[j])) std::swap(ps[j], ps[j + 1]);
        }
        if (equals(ps[1], ps[2])) return ps[1];
        return Segment(ps[1], ps[2]);
    }

    // https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_D
    coordinate_t square_distance(const Segment &l1, const Segment &l2) {
        if (has_common_point(l1, l2)) return 0;
        return std::min({ square_distance(l1, l2.a), square_distance(l1, l2.b), square_distance(l1.a, l2), square_distance(l1.b, l2) });
    }
    // https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_D
    coordinate_t distance(const Segment &l1, const Segment &l2) {
        return std::sqrt(square_distance(l1, l2));
    }

    // Polygon

    using Polygon = std::vector<Point>;

    // https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_3_A
    coordinate_t signed_area(const Polygon &poly) {
        coordinate_t res = 0;
        int sz = poly.size();
        for (int i = 0; i < sz; ++i) {
            int j = i + 1;
            if (j == sz) j = 0;
            res += signed_area(ZERO, poly[i], poly[j]);
        }
        return res;
    }
    // https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_3_A
    auto area(const Polygon &poly) {
        return std::abs(signed_area(poly));
    }
    // https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_3_B
    template <bool accept_180_degree = true>
    bool is_convex(const Polygon &poly) {
        int sz = poly.size();
        for (int i = 0; i < sz; ++i) {
            int j = i + 1, k = i + 2;
            if (j >= sz) j -= sz;
            if (k >= sz) k -= sz;
            int dir = isp(poly[i], poly[j], poly[k]);
            if constexpr (accept_180_degree) {
                if (dir == ISP::R_CURVE) return false;
            } else {
                if (dir != ISP::L_CURVE) return false;
            }
        }
        return true;
    }
    // https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_3_C
    Containment contains(const Polygon &poly, const Point &p) {
        bool in = false;
        int sz = poly.size();
        for (int i = 0; i < sz; ++i) {
            int j = i + 1;
            if (j == sz) j -= sz;
            Point a = poly[i] - p, b = poly[j] - p;
            if (a.imag() > b.imag()) std::swap(a, b);
            if (sgn(a.imag()) <= 0 and sgn(b.imag()) > 0 and sgn(det(a, b)) < 0) in = not in;
            if (sgn(det(a, b)) == 0 and sgn(dot(a, b)) <= 0) return Containment::ON;
        }
        return in ? Containment::IN : Containment::OUT;
    }

    // https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_4_B
    auto convex_diameter(const Polygon &convex) {
        const int sz = convex.size();
        auto d2 = [&](int i, int j) { return square_abs(convex[j % sz] - convex[i]); };
        coordinate_t max_dist = -1;
        std::pair<int, int> argmax { -1, -1 };
        for (int i = 0, j = 0; i < sz; ++i) {
            while (d2(i, j + 1) >= d2(i, j)) ++j;
            coordinate_t cur_dist = d2(i, j);
            if (cur_dist > max_dist) {
                max_dist = cur_dist;
                argmax = { i, j };
            }
        }
        auto [i, j] = argmax;
        return std::make_tuple(i, j % sz, std::sqrt(max_dist));
    }

    // https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_4_C
    auto convex_cut(const Polygon &convex, const Line &l) {
        Polygon res;
        int sz = convex.size();
        for (int i = 0; i < sz; ++i) {
            int j = i + 1;
            if (j == sz) j -= sz;
            const Point &a = convex[i], &b = convex[j];
            int da = sgn(det(l.b - l.a, a - l.a));
            if (da >= 0) res.push_back(a);
            int db = sgn(det(l.b - l.a, b - l.a));
            if (da * db < 0) res.push_back(internal::cross_point(l, Segment(a, b)));
        }
        return res;
    }

    // Circle

    // https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_A
    int tangent_num(const Circle &c1, const Circle &c2) {
        coordinate_t r1 = c1.radius, r2 = c2.radius;
        if (r1 > r2) return tangent_num(c2, c1);
        coordinate_t d = abs(c1.center - c2.center);
        int cp = compare(d, r1 + r2);
        if (cp > 0) return 4;
        if (cp == 0) return 3;
        int cn = compare(d, r2 - r1);
        if (cn > 0) return 2;
        if (cn == 0) return 1;
        return 0;
    }

    // https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_D
    std::vector<Point> common_point(const Circle &c, const Line &l) {
        Point h = projection(c.center, l);
        coordinate_t d = abs(c.center - h);
        int cp = compare(d, c.radius);
        if (cp > 0) return {};
        if (cp == 0) return { h };
        auto v = (l.a - l.b) * (std::sqrt(c.radius * c.radius - d * d) / abs(l.a - l.b));
        return { h - v, h + v };
    }

    // https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_H
    std::vector<Point> common_point(const Circle &c, const Segment &l) {
        auto ps = common_point(c, Line(l.a, l.b));
        ps.erase(std::remove_if(ps.begin(), ps.end(), [&](const auto &p) { return contains(l, p) != Containment::ON; }), ps.end());
        return ps;
    }

    // https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_E
    std::vector<Point> common_point(const Circle &c1, const Circle &c2) {
        coordinate_t r1 = c1.radius, r2 = c2.radius;
        if (r1 > r2) return common_point(c2, c1);
        coordinate_t d = abs(c1.center - c2.center);
        int cp = compare(d, r1 + r2), cn = compare(d, r2 - r1);
        if (cp > 0 or cn < 0) return {};
        auto v = c1.center - c2.center;
        coordinate_t lv = abs(v);
        if (cp == 0 or cn == 0) {
            return { c2.center + v * (r2 / lv) };
        }
        coordinate_t lp = d, ln = (r2 * r2 - r1 * r1) / d;
        coordinate_t p = (lp + ln) / 2, x = sqrt(r2 * r2 - p * p);
        auto h = c2.center + v * (p / lv);
        auto t = v * I;
        return { h + t * (x / lv), h - t * (x / lv) };
    }

    // https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_F
    Containment contains(const Circle &c, const Point &p) {
        coordinate_t d = abs(c.center - p);
        int cp = compare(d, c.radius);
        if (cp > 0) return Containment::OUT;
        if (cp < 0) return Containment::IN;
        return Containment::ON;
    }

    // https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_F
    std::vector<Point> tangent_to_circle(const Circle &c, const Point &p) {
        Containment cnt = contains(c, p);
        if (cnt == Containment::IN) return {};
        if (cnt == Containment::ON) return { p };
        auto v = c.center - p;
        coordinate_t r = c.radius, d = abs(v), l = sqrt(d * d - r * r);
        coordinate_t t = std::asin(r / d);
        return { p + rot(v, t) * (l / d), p + rot(v, -t) * (l / d) };
    }

    // https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_G
    // returns { Line(p, q) | p is on c1, q is on c2, Line(p, q) is common tangent of c1 and c2 }
    std::vector<Line> common_tangent(const Circle &c1, const Circle &c2) {
        int num = tangent_num(c1, c2);
        std::vector<Line> res;
        if (num == 0) return res;
        Point a = c1.center, b = c2.center, v = b - a;
        coordinate_t r1 = c1.radius, r2 = c2.radius;
        coordinate_t rp = r1 + r2, rm = r1 - r2, rd = r2 / r1;
        coordinate_t sqxy = square_abs(v);
        coordinate_t rtp = std::sqrt(std::max(sqxy - rp * rp, coordinate_t(0)));
        coordinate_t rtm = std::sqrt(std::max(sqxy - rm * rm, coordinate_t(0)));
        Point r = v * r1, u = r * Point(0, 1);
        Point l12 = r * rp, r12 = u * rtp, l34 = r * rm, r34 = u * rtm;
        Point p14 = (l34 + r34) / sqxy;
        res.emplace_back(a + p14, b + p14 * rd);
        if (num == 1) return res;
        Point p13 = (l34 - r34) / sqxy;
        res.emplace_back(a + p13, b + p13 * rd);
        if (num == 2) return res;
        Point p12 = (l12 + r12) / sqxy;
        res.emplace_back(a + p12, b - p12 * rd);
        if (num == 3) return res;
        Point p11 = (l12 - r12) / sqxy;
        res.emplace_back(a + p11, b - p11 * rd);
        return res;
    }

    // https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_H
    coordinate_t intersection_area(const Polygon &poly, const Circle &circle) {
        int sz = poly.size();
        coordinate_t r2 = circle.radius * circle.radius;
        const Point &c = circle.center;
        coordinate_t area = 0;
        for (int i = 0; i < sz; i++) {
            int j = i + 1;
            if (j >= sz) j -= sz;
            Point a = poly[i], b = poly[j];
            bool in_a = contains(circle, a) == Containment::IN, in_b = contains(circle, b) == Containment::IN;
            Point ca = a - c, cb = b - c;
            if (in_a and in_b) {
                area += det(ca, cb);
                continue;
            }
            std::vector<Point> ps = common_point(circle, Segment(a, b));
            if (ps.empty()) {
                area += r2 * arg(cb / ca);
            } else {
                Point s = ps[0];
                Point t = ps.size() == 1 ? s : ps[1];
                if (compare(square_abs(t - a), square_abs(s - a)) < 0) std::swap(s, t);
                Point cs = s - c, ct = t - c;
                area += det(cs, ct);
                area += in_a ? det(ca, cs) : r2 * arg(cs / ca);
                area += in_b ? det(ct, cb) : r2 * arg(cb / ct);
            }
        }
        return area / 2;
    }

    // https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_I
    coordinate_t intersection_area(const Circle &c1, const Circle &c2) {
        coordinate_t r = c1.radius, s = c2.radius;
        if (r < s) return intersection_area(c2, c1);
        Point a = c1.center, b = c2.center;
        coordinate_t d = abs(a - b);
        if (compare(d, r + s) >= 0) return 0;
        if (compare(d, r - s) <= 0) return PI * s * s;
        coordinate_t x = (d * d + r * r - s * s) / (2 * d);
        coordinate_t h = std::sqrt(std::max(r * r - x * x, coordinate_t(0)));
        coordinate_t a1 = r * r * std::acos(x / r);
        coordinate_t a2 = s * s * std::acos((d - x) / s);
        coordinate_t a12 = d * h;
        return a1 + a2 - a12;
    }
}
} // namespace suisen

#endif // SUISEN_GEOMETRY

using namespace suisen::geometry ;

const int inf = 1'000'000'007;

void solve() {
    INT(na, nb);
    vc<int> xa(na), ya(na);
    vc<int> xb(nb), yb(nb);
    vc<Point> pa(na), pb(nb);
    rep(i, na) {
        in(xa[i], ya[i]);
        pa[i] = {(ld)xa[i], (ld)ya[i]};
    }
    rep(i, nb) {
        in(xb[i], yb[i]);
        pb[i] = {(ld)xb[i], (ld)yb[i]};
    }
    auto dist = [&](bool check, int i, int j) -> ld {
        unless(check) return sqrt(pow((ld)(xa[i] - xa[j]), 2.0) + pow((ld)(ya[i] - ya[j]), 2.0));
        else return sqrt(pow((ld)(xb[i] - xb[j]), 2.0) + pow((ld)(yb[i] - yb[j]), 2.0));
    };
    auto ok = [&](int i, int j) -> bool {
        Segment l(pa[0], pa[1]);
        Segment m(pb[i], pb[j]);
        return !(has_common_point(l, m));
    };
    ld ans = inf;
    rep(_, 2) {
        vc<ld> d(nb, inf);
        pqg<pair<ld, int>> pque;
        pque.push({0.0, 0});
        d[0] = 0;
        while(pque.size()) {
            auto [di, v] = pque.top(); pque.pop();
            if(di > d[v]) continue;
            rep(nv, nb) {
                if(ok(v, nv)) {
                    if(chmin(d[nv], d[v] + dist(1, v, nv))) {
                        pque.push({d[nv], nv});
                    }
                }
            }
        }
        chmin(ans, dist(0, 0, 1) + d[1]);
        swap(na, nb);
        swap(xa, xb);
        swap(ya, yb);
        swap(pa, pb);
    }
    if(ans == inf) out("-1");
    else out(ans);
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout << fixed << setprecision(20);
    // INT(t); rep(i, t)solve();
    solve();
    return 0;
}
accuracy: 1
time_ms: 80
memory_kb: 3876
final_rank: 8

code_snippet: #include<bits/stdc++.h> 
using namespace std;
using ll=long long int;
//using Int=__int128;
#define ALL(A) A.begin(),A.end()
template<typename T1,typename T2> bool chmin(T1 &a,T2 b){if(a<=b)return 0; a=b; return 1;}
template<typename T1,typename T2> bool chmax(T1 &a,T2 b){if(a>=b)return 0; a=b; return 1;}
template<typename T> constexpr int bitUP(T x,int a){return (x>>a)&1;}
//→　↓　←　↑ 
int dh[4]={0,1,0,-1}, dw[4]={1,0,-1,0};
//右上から時計回り
//int dh[8]={-1,0,1,1,1,0,-1,-1}, dw[8]={1,1,1,0,-1,-1,-1,0};
//long double EPS = 1e-6;
//long double PI = acos(-1);
//const ll INF=(1LL<<62);
const int MAX=(1<<30);
constexpr ll MOD=1000000000+7;
//constexpr ll MOD=998244353;


inline void bin101(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout << fixed << setprecision(20);
}

using pii=pair<int,int>;
using pil=pair<int,ll>;
using pli=pair<ll,int>;
using pll=pair<ll,ll>;
using psi=pair<string,int>;
using pis=pair<int,string>;
using psl=pair<string,ll>;
using pls=pair<ll,string>;
using pss=pair<string,string>;

using Graph=vector<vector<int>>;

template<typename T >
struct edge {
	int to;
	T cost;
	edge()=default;
	edge(int to, T cost) : to(to), cost(cost) {}

};
template<typename T>
using WeightGraph=vector<vector<edge<T>>>;

template<typename T>
void CinGraph(int M,WeightGraph<T> &g,bool directed=false,bool index1=true){
    while(M--){
        int s,t;
        T cost;
        cin>>s>>t>>cost;
        if(index1) s--,t--;
        g[s].emplace_back(t,cost);
        if(not directed) g[t].emplace_back(s,cost);
    }
}

void CinGraph(int M,Graph &g,bool directed=false,bool index1=true){
    while(M--){
        int s,t;
        cin>>s>>t;
        if(index1) s--,t--;
        g[s].push_back(t);
        if(not directed) g[t].push_back(s);
    }
}


//0-indexed vector cin
template<typename T>
inline istream &operator>>(istream &is,vector<T> &v) {
    for(size_t i=0;i<v.size();i++) is>>v[i];
	return is;
}
 
//0-indexed vector cin
template<typename T>
inline istream &operator>>(istream &is,vector<vector<T>> &v) {
    for(size_t i=0;i<v.size();i++){
        is>>v[i];
    }
    return is;
}
//vector cout
template<typename T>
inline ostream &operator<<(ostream &os,const vector<T> &v) {
    for(size_t i=0;i<v.size();i++){
        if(i) os<<" ";
        os<<v[i];
    }
    return os;
}
//vector<vector> cout
template<typename T>
inline ostream &operator<<(ostream &os,const vector<vector<T>> &v) {
    for(size_t i=0;i<v.size();i++){
        os<<v[i];
        if(i+1!=v.size()) os<<"\n";
    }
    return os;
}

//Graph out
template<typename T>
inline ostream &operator<<(ostream &os,const Graph &g) {
    for(size_t i=0;i<g.size();i++){
        for(int to:g[i]){
            os<<i<<"->"<<to<<" ";
        }
        os<<endl;
    }
    return os;
}

//WeightGraph out
template<typename T>
inline ostream &operator<<(ostream &os,const WeightGraph<T> &g) {
    for(size_t i=0;i<g.size();i++){
        for(auto e:g[i]){
            os<<i<<"->"<<e.to<<"("<<e.cost<<") ";
        }
        os<<endl;
    }
    return os;
}


//要素数n 初期値x
template<typename T>
inline vector<T> vmake(size_t n,T x){
	return vector<T>(n,x);
}

//a,b,c,x data[a][b][c] 初期値x
template<typename... Args>
auto vmake(size_t n,Args... args){
	auto v=vmake(args...);
	return vector<decltype(v)>(n,move(v));
}
template<typename V,typename T>
void fill(V &v,const T value){
    v=value;
}

template<typename V,typename T>
void fill(vector<V> &vec,const T value){
    for(auto &v:vec) fill(v,value);
}

//pair cout
template<typename T, typename U>
inline ostream &operator<<(ostream &os,const pair<T,U> &p) {
	os<<p.first<<" "<<p.second;
	return os;
}
 
//pair cin
template<typename T, typename U>
inline istream &operator>>(istream &is,pair<T,U> &p) {
	is>>p.first>>p.second;
	return is;
}
 
//ソート
template<typename T>
inline void vsort(vector<T> &v){
    sort(v.begin(),v.end());
}
 
//逆順ソート
template<typename T>
inline void rvsort(vector<T> &v){
	sort(v.rbegin(),v.rend());
}

//1ビットの数を返す
inline int popcount(int x){
	return __builtin_popcount(x);
}
//1ビットの数を返す
inline int popcount(ll x){
	return __builtin_popcountll(x);
}
template<typename T>
inline void Compress(vector<T> &C){
    sort(C.begin(),C.end());
    C.erase(unique(C.begin(),C.end()),C.end());
}
template<typename T>
inline int lower_idx(const vector<T> &C,T value){
    return lower_bound(C.begin(),C.end(),value)-C.begin();
}
template<typename T>
inline int upper_idx(const vector<T> &C,T value){
    return upper_bound(C.begin(),C.end(),value)-C.begin();
}
//時計回りに90度回転
template<typename T>
inline void rotate90(vector<vector<T>> &C){
    vector<vector<T>> D(C[0].size(),vector<T>(C.size()));
    for(int h=0;h<C.size();h++){
        for(int w=0;w<C[h].size();w++){
            D[w][C.size()-1-h]=C[h][w];
        }
    }
    C=D;
}
//補グラフを返す
//i→iのような辺は加えない
Graph ComplementGraph(const Graph &g){
    size_t sz=g.size();
    bool used[sz][sz];
    fill(used[0],used[sz],false);
    for(size_t i=0;i<sz;i++){
        for(int to:g[i]){
            used[i][to]=true;
        }
    }
    Graph ret(sz);
    for(size_t i=0;i<sz;i++){
        for(size_t j=0;j<sz;j++){
            if(used[i][j]) continue;
            if(i==j) continue;
            ret[i].push_back(j);
        }
    }
    return ret;
}
//グラフの分解 secondはある頂点がどこに対応するか id[i]={2,3}のとき,頂点iはret[2][3]に対応
//無効グラフのみに対応
pair<vector<Graph>,vector<pair<int,int>>> GraphDecomposition(const Graph &g){
    vector<pair<int,int>> id(g.size(),pair<int,int>(-1,-1));
    vector<Graph> ret;
    vector<int> now;
    for(size_t i=0;i<g.size();i++){
        if(id[i].first!=-1) continue;
        id[i].first=ret.size();
        id[i].second=0;
        now.push_back(i);
        for(size_t j=0;j<now.size();j++){
            for(int to:g[now[j]]){
                if(id[to].first==-1){
                    id[to].first=ret.size();
                    id[to].second=now.size();
                    now.push_back(to);
                }
            }
        }
        Graph r(now.size());
        for(size_t j=0;j<now.size();j++){
            r[j]=g[now[j]];
            for(int &to:r[j]){
                to=id[to].second;
            }
        }
        ret.push_back(r);
        now.clear();
    }
    return make_pair(ret,id);
}
//0indexを想定
bool OutGrid(ll h,ll w,ll H,ll W){
    return (h>=H or w>=W or h<0 or w<0);
}

void NO(){
    cout<<"NO"<<"\n";
}
void YES(){
    cout<<"YES"<<"\n";
}
void No(){
    cout<<"No"<<"\n";
}
void Yes(){
    cout<<"Yes"<<"\n";
}
namespace overflow{
    template<typename T>
    T max(){
        return numeric_limits<T>::max();
    }
    template<typename T>
    T ADD(T a,T b){
        T res;
        return __builtin_add_overflow(a,b,&res)?max<T>():res;
    }
    template<typename T>
    T MUL(T a,T b){
        T res;
        return __builtin_mul_overflow(a,b,&res)?max<T>():res;
    }
};
using namespace overflow;
struct ModInt{
    using u64=uint_fast64_t;
    u64 a;
    constexpr ModInt() :a(0){}
    constexpr ModInt(ll x) :a((x>=0)?(x%MOD):(x%MOD+MOD) ) {}

    inline constexpr ModInt operator+(const ModInt rhs)const noexcept{
        return ModInt(*this)+=rhs;
    }
    inline constexpr ModInt operator-(const ModInt rhs)const noexcept{
        return ModInt(*this)-=rhs;
    }
    inline constexpr ModInt operator*(const ModInt rhs)const noexcept{
        return ModInt(*this)*=rhs;
    }
    inline constexpr ModInt operator/(const ModInt rhs)const noexcept{
        return ModInt(*this)/=rhs;
    }
    inline constexpr ModInt operator+(const ll rhs) const noexcept{
        return ModInt(*this)+=ModInt(rhs);
    }
    inline constexpr ModInt operator-(const ll rhs)const noexcept{
        return ModInt(*this)-=ModInt(rhs);
    }
    inline constexpr ModInt operator*(const ll rhs)const noexcept{
        return ModInt(*this)*=ModInt(rhs);
    }
    inline constexpr ModInt operator/(const ll rhs)const noexcept{
        return ModInt(*this)/=ModInt(rhs);
    }

    inline constexpr ModInt &operator+=(const ModInt rhs)noexcept{
        a+=rhs.a;
        if(a>=MOD) a-=MOD;
        return *this;
    }
    inline constexpr ModInt &operator-=(const ModInt rhs)noexcept{
        if(rhs.a>a) a+=MOD;
        a-=rhs.a;
        return *this;
    }
    inline constexpr ModInt &operator*=(const ModInt rhs)noexcept{
        a=(a*rhs.a)%MOD;
        return *this;
    }
    inline constexpr ModInt &operator/=(ModInt rhs)noexcept{
        a=(a*rhs.inverse().a)%MOD;
        return *this;
    }
    inline constexpr ModInt &operator+=(const ll rhs)noexcept{
        return *this+=ModInt(rhs);
    }
    inline constexpr ModInt &operator-=(const ll rhs)noexcept{
        return *this-=ModInt(rhs);
    }
    inline constexpr ModInt &operator*=(const ll rhs)noexcept{
        return *this*=ModInt(rhs);
    }
    inline constexpr ModInt &operator/=(const ll rhs)noexcept{
        return *this/=ModInt(rhs);
    }

    inline constexpr ModInt operator=(const ll x)noexcept{
        a=(x>=0)?(x%MOD):(x%MOD+MOD);
        return *this;
    }

    inline constexpr bool operator==(const ModInt p)const noexcept{
        return a==p.a;
    }

    inline constexpr bool operator!=(const ModInt p)const noexcept{
        return a!=p.a;
    }

    inline constexpr ModInt pow(ll N) const noexcept{
        ModInt ans(1LL),p(a);
        while(N>0){
            if(bitUP(N,0)){
                ans*=p;
            }
            p*=p;
            N>>=1;
        }
        return ans;
    }
    inline constexpr ModInt inverse() const noexcept{
        return pow(MOD-2);
    }

};
inline constexpr ModInt operator+(const ll &a,const ModInt &b)noexcept{
    return ModInt(a)+=b;
}
inline constexpr ModInt operator-(const ll &a,const ModInt &b)noexcept{
    return ModInt(a)-=b;
}
inline constexpr ModInt operator*(const ll &a,const ModInt &b)noexcept{
    return ModInt(a)*=b;
}
inline constexpr ModInt operator/(const ll &a,const ModInt &b)noexcept{
    return ModInt(a)/=b;
}
//cout
inline ostream &operator<<(ostream &os,const ModInt &p) {
    return os<<p.a;
}

//cin
inline istream &operator>>(istream &is,ModInt &p) {
    ll t;
    is>>t;
    p=t;
    return is;
}

struct Binominal{
    vector<ModInt> fac,finv,inv; //fac[n]:n! finv:(n!)の逆元
    int sz;
    Binominal(int n=10) :sz(1){
        if(n<=0) n=10;
        init(n);
    }
    inline void init(int n){
        fac.resize(n+1,1);
        finv.resize(n+1,1);
        inv.resize(n+1,1);
        for(int i=sz+1;i<=n;i++){
            fac[i]=fac[i-1]*i;
            inv[i]=MOD-inv[MOD%i]*(MOD/i);
            finv[i]=finv[i-1]*inv[i];
        }
        sz=n;
    }
    //nCk(n,k<=N) をO(1)で求める
    inline ModInt com(int n,int k){
        if(n<k) return ModInt(0);
        if(n<0 || k<0) return ModInt(0);
        if(n>sz) init(n);
        return fac[n]*finv[k]*finv[n-k];
    }
    //nCk(k<=N) をO(k)　で求める 
    inline ModInt rcom(ll n,int k){
        if(n<0 || k<0 || n<k) return ModInt(0);
        if(k>sz) init(k);
        ModInt ret(1);
        for(int i=0;i<k;i++){
            ret*=n-i;
        }
        ret*=finv[k];
        return ret;
    }

    //重複組み合わせ n種類のものから重複を許してk個を選ぶ
    //〇がn個,|がk個
    inline ModInt h(int n,int k){
        return com(n+k-1,k);
    }
};
vector<int> Subset(int S,bool zero=false,bool full=false){
    vector<int> ret;
    int now=(S-1)&S;
    if(full and S){
        ret.push_back(S);
    }
    do{
        ret.push_back(now);
        now=(now-1)&S;
    }while(now!=0);
    if(zero){
        ret.push_back(0);
    }
    return ret;
}
template<typename T>
T SUM(const vector<T> &v,int s,int t){
    chmax(s,0);
    chmin(t,int(v.size())-1);
    if(s>t) return 0;
    if(s==0) return v[t];
    else return v[t]-v[s-1];
}
template<typename T>
void buildSUM(vector<T> &v){
    for(size_t i=1;i<v.size();i++){
        v[i]+=v[i-1];
    }
    return;
}
 
////////////////////////////
// マクロや型
////////////////////////////

using DD=long double;

const DD EPS=1e-9;
const DD INF=1e50;
const DD PI=acosl(-1.0);
#define EQ(a,b) (abs( (a) - (b) )<EPS) //a==b
#define LS(a,b) ( (a)+EPS<(b) ) //a<b
#define GR(a,b) ( (a)>(b)+EPS ) //a>b
#define LE(a,b) ( (a)<(b)+EPS ) //a<=b
#define GE(a,b) ( (a)>(b)-EPS ) //a>=b

#define X real()
#define Y imag()


//点
using Point=complex<DD>;
istream &operator>>(istream &is, Point &p) {
  DD x,y;
  is>>x>>y;
  p=Point(x,y);
  return is;
}

//点a→点bの線分
//aとbが等しい時、色々バグるから注意!
struct Segment{
    Point a,b;
    Segment()=default;
    Segment(Point a,Point b) :a(a),b(b){}
    Segment(DD ax,DD ay,DD bx,DD by):a(ax,ay),b(bx,by){}
    Segment(DD r,Point a) :a(a),b(a+polar((DD)1.0,r)){} 
};
using Line=Segment;

//円
struct Circle{
    Point p;
    DD r;
    Circle()=default;
    Circle(Point p,DD r):p(p),r(r){}
};

using Polygon=vector<Point>;

////////////////////////////
// 基本計算
////////////////////////////

//度→ラジアン
inline DD torad(const DD deg){return deg*PI/180;}
//ラジアン→度
inline DD todeg(const DD rad){return rad*180/PI;}
//内積 |a||b|cosθ
inline DD dot(const Point &a,const Point &b){return (conj(a)*b).X;}
//外積 |a||b|sinθ
inline DD cross(const Point &a,const Point &b){return (conj(a)*b).Y;}
//ベクトルpを反時計回りにtheta(ラジアン)回転
Point rotate(const Point &p,const DD theta){return p*Point(cos(theta),sin(theta));}

//余弦定理 cos(角度abc(ラジアン))を返す
//長さの対応に注意 ab:辺abの長さ
//verify:https://codeforces.com/gym/102056/problem/F
DD cosine_formula(const DD ab,const DD bc,const DD ca){
    return (ab*ab+bc*bc-ca*ca)/(2*ab*bc);
}

inline bool xy_sort(const Point &a,const Point &b){
    if(a.X+EPS<b.X) return true;
    if(EQ(a.X,b.X) && a.Y+EPS<b.Y) return true;
    return false;
}
inline bool yx_sort(const Point &a,const Point &b){
    if(a.Y+EPS<b.Y) return true;
    if(EQ(a.Y,b.Y) && a.X+EPS<b.X) return true;
    return false;
}
namespace std{
    inline bool operator<(const Point &a,const Point &b)noexcept{
        return xy_sort(a,b);
    }
}
//DDの比較関数
struct DDcom{
    bool operator()(const DD a, const DD b) const noexcept {
        return a+EPS<b;
    }
};


////////////////////////////
// 平行や直交
////////////////////////////

bool isOrthogonal(const Point &a,const Point &b){
    return EQ(dot(a,b),0.0);
}
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_A
bool isOrthogonal(const Segment &s,const Segment &t){
    return EQ(dot(s.a-s.b,t.a-t.b),0.0);
}
bool isParallel(const Point &a,const Point &b){
    return EQ(cross(a,b),0.0);
}
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_A
bool isParallel(const Segment &s,const Segment &t){
    return EQ(cross(s.a-s.b,t.a-t.b),0);
}
//線分a→bに対して点cがどの位置にあるか
//反時計回り:1　時計回り:-1 直線上(a,b,c:-2 a,c,b:0 c,a,b:2)
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_1_C
//線分a→bの端点にcがあるなら0と判定されるはず
int ccw(const Point &a,Point b,Point c){
    if(EQ(abs(b-c),0) or EQ(abs(a-c),0)) return 0;
    b-=a;c-=a;
    if(cross(b,c)>EPS) return 1;
    if(cross(b,c)<-EPS) return -1;
    if(dot(b,c)<-EPS) return 2;
    if(LS(norm(b),norm(c))) return -2;
    return 0;
}

////////////////////////////
// 射影と反射
////////////////////////////

//射影
//直線lに点pから垂線を引いたときの交点
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_1_A
Point project(const Point &p,const Line &l){
    Point base=l.b-l.a;
    DD r=dot(p-l.a,base)/norm(base);
    return l.a+base*r;
}
//反射
//直線lに対して点pと対称な点
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_1_B
Point reflect(const Point &p,const Line &l){
    return p+(project(p,l)-p)*(DD)2.0;
}

////////////////////////////
// 点との距離
////////////////////////////

//点と直線の距離
DD DistPL(const Point &p,const Line &l){
    return abs(cross(l.b-l.a,p-l.a))/abs(l.b-l.a);
}
//点と線分の距離
DD DistPS(const Point &p,const Segment &s){
    if( dot(s.b-s.a,p-s.a)<0.0 ) return abs(p-s.a);
    if( dot(s.a-s.b,p-s.b)<0.0 ) return abs(p-s.b);
    return DistPL(p,s);
}

////////////////////////////
// 線分と直線
////////////////////////////

//線分a-b,c-dは交差するか?
//接する場合も交差すると判定
//接する場合は交差しないとするなら<=を<に変換
bool intersect(const Point &a,const Point &b,const Point &c,const Point &d){
    return(ccw(a,b,c)*ccw(a,b,d)<=0 && ccw(c,d,a)*ccw(c,d,b)<=0);
}
//線分s,tは交差するか？
//接する場合も交差すると判定
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_B&lang=ja
//接する場合は交差しないとするならintersectの<=を<に変換
bool intersect(const Segment &s,const Segment &t){
    return intersect(s.a,s.b,t.a,t.b);
}
// 2直線の交点
// 線分の場合はintersectをしてから使う
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_C&lang=ja
Point crossPoint(const Line &s,const Line &t){
    Point base=t.b-t.a;
    DD d1=cross(base,t.a-s.a);
    DD d2=cross(base,s.b-s.a);
    if(EQ(d1,0) and EQ(d2,0)) return s.a; //同じ直線
    if(EQ(d2,0)) assert(false); //交点がない
    return s.a+d1/d2*(s.b-s.a);
}
//線分と線分の距離
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_D&lang=ja
DD Dist(const Segment &s,const Segment &t){
    if(intersect(s,t)) return 0.0;
    return min(min(DistPS(t.a,s),DistPS(t.b,s)),min(DistPS(s.a,t),DistPS(s.b,t)) );
}
bool issame(const Line &l,const Line &m){
    if (GR(abs(cross(m.a - l.a, l.b - l.a)),0) ) return false;
    if (GR(abs(cross(m.b - l.a, l.b - l.a)),0) ) return false;
    return true;
}

////////////////////////////
// 円
////////////////////////////
//直線lと円Cの交点
//l.aにより近い方がindexが小さい
//veirfy:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_D
vector<Point> crossPointLC(const Line &l,const Circle &c){
    vector<Point> ret;
    if(GR(DistPL(c.p,l),c.r)) return ret; //交点がないとき、空ベクトルを返す
    Point pr=project(c.p,l);
    Point e=(l.b-l.a)/(abs(l.b-l.a));
    DD base=sqrt(c.r*c.r-norm(pr-c.p));
    ret.push_back(pr-e*base);
    ret.push_back(pr+e*base);
    if(EQ(DistPL(c.p,l),c.r)) ret.pop_back(); //接するとき
    return ret;
}
//線分sと円cの交点
//交点がないときは空ベクトルを返す
//線分の端が交わる場合も交点とみなす
//s.aにより近い方がindexが小さい
vector<Point> crossPointSC(const Segment &s,const Circle &c){
    vector<Point> ret;
    if(DistPS(c.p,s)>c.r+EPS) return ret;
    auto koho=crossPointLC(s,c);
    for(auto p:koho){
        if(ccw(s.a,s.b,p)==0 or EQ(abs(p-s.a),0) or EQ(abs(p-s.b),0)) ret.push_back(p);
    }
    return ret;
}

//円aと円bの共通接線の数
//離れている:4 外接:3 交わる:2 内接:1 内包:0
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_A
int intersect(const Circle &a,const Circle &b){
    DD d=abs(a.p-b.p);
    if(GR(d,a.r+b.r)) return 4;
    if(EQ(d,a.r+b.r)) return 3;
    if(EQ(d,abs(a.r-b.r))) return 1;
    if(LS(d,abs(a.r-b.r))) return 0;
    return 2;
}

//円aと円bの交点
//交点がないときは空ベクトルを返す
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_E
vector<Point> crossPoint(const Circle &a,const Circle &b){
    vector<Point> ret;
    if(GR(abs(a.p-b.p),a.r+b.r)) return ret;
    DD d=abs(a.p-b.p);
    DD s=acosl((a.r*a.r+d*d-b.r*b.r)/(2*a.r*d)); //0~π
    DD t=arg(b.p-a.p);
    if(EQ(a.r+b.r,d)) ret.push_back(a.p+polar(a.r,t));
    else ret.push_back(a.p+polar(a.r,t+s)),ret.push_back(a.p+polar(a.r,t-s));
    return ret;
}

template<class T>
vector<T> dijkstra(const vector< vector<edge<T>> > &g,int s,const T inf,const T zero){
    vector<T> dist(g.size(),inf);
    using pti=pair<T,int>;
    priority_queue<pti,vector<pti>,greater<pti>> que;
    dist[s]=zero;
    que.emplace(dist[s],s);
    while(!que.empty()){
      T cost;
      int idx;
      tie(cost,idx)=que.top();
      que.pop();
      if(dist[idx]<cost) continue;
      for(auto &e:g[idx]){
        auto next_cost=cost+e.cost;
        if(dist[e.to]<=next_cost) continue;
        dist[e.to]=next_cost;
        que.emplace(dist[e.to],e.to);
      }
    }
    return dist;
}

DD f(Segment S,vector<Point> P){
    WeightGraph<DD> g(P.size());
    for(int i=0;i<P.size();i++){
        for(int j=i+1;j<P.size();j++){
            if(intersect(S.a,S.b,P[i],P[j])) continue;
            g[i].emplace_back(j,abs(P[i]-P[j]));
            g[j].emplace_back(i,abs(P[i]-P[j]));
        }
    }
    DD ans=dijkstra(g,0,INF,DD(0))[1];
    return ans+abs(S.a-S.b);
}


void solve(){
    int NA,NB;
    cin>>NA>>NB;
    vector<Point> A(NA),B(NB);
    cin>>A>>B;

    DD ans=f({A[0],A[1]},B);
    chmin(ans,f({B[0],B[1]},A));
    if(ans>MAX) cout<<-1<<endl;
    else cout<<ans<<endl;
}

int main(){
    bin101();
    int T=1;
    //cin>>T;
    while(T--) solve();
}
accuracy: 1
time_ms: 310
memory_kb: 37716
final_rank: 20

code_snippet: #include <bits/stdc++.h>
using namespace std;

namespace geometry {
using Real = double;
constexpr Real EPS = 1e-8;
constexpr Real PI = 3.14159265358979323846L;

inline int sgn(Real x) { return x < -EPS ? -1 : x > EPS ? 1 : 0; }

inline int compare(Real a, Real b) { return sgn(a - b); }

inline bool equals(Real a, Real b) { return compare(a, b) == 0; }

struct Point {
    Real x, y;

    Point() {}

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

    Point& operator+=(const Point& p) {
        x += p.x, y += p.y;
        return *this;
    }

    Point& operator-=(const Point& p) {
        x -= p.x, y -= p.y;
        return *this;
    }

    Point& operator*=(const Real& k) {
        x *= k, y *= k;
        return *this;
    }

    Point& operator/=(const Real& k) {
        x /= k, y /= k;
        return *this;
    }

    Point operator+(const Point& p) const { return Point(*this) += p; }

    Point operator-(const Point& p) const { return Point(*this) -= p; }

    Point operator*(const Real& k) const { return Point(*this) *= k; }

    Point operator/(const Real& k) const { return Point(*this) /= k; }

    Point operator-() const { return Point(-x, -y); }

    bool operator==(const Point& p) const { return (compare(x, p.x) == 0 && compare(y, p.y) == 0); }

    bool operator!=(const Point& p) const { return !(*this == p); }

    bool operator<(const Point& p) const {
        return compare(x, p.x) < 0 || (compare(x, p.x) == 0 && compare(y, p.y) < 0);
    }

    bool operator>(const Point& p) const {
        return compare(x, p.x) > 0 || (compare(x, p.x) == 0 && compare(y, p.y) > 0);
    }

    friend std::istream& operator>>(std::istream& is, Point& p) { return is >> p.x >> p.y; }

    friend std::ostream& operator<<(std::ostream& os, const Point& p) { return os << p.x << ' ' << p.y; }

    Real norm() const { return x * x + y * y; }

    Real abs() const { return std::hypot(x, y); }

    Real arg() const { return std::atan2(y, x); }

    Point normal() const { return Point(-y, x); }

    Point unit() const { return *this / abs(); }

    Point rotate(Real theta) const {
        return Point(x * std::cos(theta) - y * std::sin(theta), x * std::sin(theta) + y * std::cos(theta));
    }
};

Point polar(const Real& r, const Real& theta) { return Point(cos(theta), sin(theta)) * r; }

Real dot(const Point& p, const Point& q) { return p.x * q.x + p.y * q.y; }

Real cross(const Point& p, const Point& q) { return p.x * q.y - p.y * q.x; }

Real distance(const Point& p, const Point& q) { return (p - q).abs(); }

struct Line {
    Point a, b;

    Line() {}

    Line(const Point& a, const Point& b) : a(a), b(b) {}

    Line(const Real& A, const Real& B, const Real& C) {  // Ax + By = c
        if (equals(A, 0)) {
            assert(!equals(B, 0));
            a = Point(0, C / B);
            b = Point(1, C / B);
        } else if (equals(B, 0)) {
            a = Point(C / A, 0);
            b = Point(C / A, 1);
        } else {
            a = Point(0, C / B);
            b = Point(C / A, 0);
        }
    }

    friend std::istream& operator>>(std::istream& is, Line& l) { return is >> l.a >> l.b; }

    friend std::ostream& operator<<(std::ostream& os, const Line& l) { return os << l.a << " to " << l.b; }

    Point diff() const { return b - a; }
};

struct Segment : Line {
    Segment() {}

    Segment(Point a, Point b) : Line(a, b) {}

    Real length() const { return diff().abs(); }
};

Point proj(const Line& l, const Point& p) {
    Point v = l.diff().unit();
    return l.a + v * dot(v, p - l.a);
}

Point refl(const Line& l, const Point& p) {
    Point h = proj(l, p);
    return h + (h - p);
}

bool orthogonal(const Line& l, const Line& m) { return equals(dot(l.diff(), m.diff()), 0); }

bool parallel(const Line& l, const Line& m) { return equals(cross(l.diff(), m.diff()), 0); }

enum Position { COUNTER_CLOCKWISE = +1, CLOCKWISE = -1, ONLINE_BACK = +2, ONLINE_FRONT = -2, ON_SEGMENT = 0 };

Position ccw(const Point& a, Point b, Point c) {
    b -= a, c -= a;
    if (sgn(cross(b, c)) == +1) return COUNTER_CLOCKWISE;
    if (sgn(cross(b, c)) == -1) return CLOCKWISE;
    if (sgn(dot(b, c)) == -1) return ONLINE_BACK;
    if (compare(b.norm(), c.norm()) == -1) return ONLINE_FRONT;
    return ON_SEGMENT;
}

bool intersect(const Line& l, const Point& p) { return abs(ccw(l.a, l.b, p)) != 1; }

bool intersect(const Line& l, const Line& m) {
    Real A = cross(l.diff(), m.diff()), B = cross(l.diff(), l.b - m.a);
    if (equals(A, 0) && equals(B, 0)) return true;
    return !parallel(l, m);
}

bool intersect(const Line& l, const Segment& s) {
    return sgn(cross(l.diff(), s.a - l.a)) * sgn(cross(l.diff(), s.b - l.a)) <= 0;
}

bool intersect(const Segment& s, const Point& p) { return ccw(s.a, s.b, p) == ON_SEGMENT; }

bool intersect(const Segment& s, const Segment& t) {
    return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 && ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

Real distance(const Line& l, const Point& p) { return distance(p, proj(l, p)); }

Real distance(const Line& l, const Line& m) { return intersect(l, m) ? 0 : distance(l, m.a); }

Real distance(const Line& l, const Segment& s) {
    return intersect(l, s) ? 0 : std::min(distance(l, s.a), distance(l, s.b));
}

Real distance(const Segment& s, const Point& p) {
    Point h = proj(s, p);
    return intersect(s, h) ? distance(p, h) : std::min(distance(p, s.a), distance(p, s.b));
}

Real distance(const Segment& s, const Segment& t) {
    if (intersect(s, t)) return 0;
    return std::min({distance(s, t.a), distance(s, t.b), distance(t, s.a), distance(t, s.b)});
}

}  // namespace geometry

/**
 * @brief 2 次元幾何ライブラリ
 * @docs docs/geometry/geometry.md
 */

using namespace geometry;
const double INF = 1e9;

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(15);
    int N, M;
    cin >> N >> M;
    vector<Point> A(N), B(M);
    for (auto& p : A) cin >> p;
    for (auto& p : B) cin >> p;

    auto calc = [&]() {
        Segment other(B[0], B[1]);
        vector<double> dp(N, INF);
        vector<bool> used(N, false);
        dp[0] = 0;

        while (1) {
            int v = -1;
            for (int u = 0; u < N; u++) {
                if (!used[u] && (v == -1 || dp[u] < dp[v])) {
                    v = u;
                }
            }
            if (v < 0) break;
            used[v] = true;
            for (int u = 0; u < N; u++) {
                Segment seg(A[v], A[u]);
                if (!intersect(other, seg)) dp[u] = min(dp[u], dp[v] + seg.length());
            }
        }

        return dp[1] + other.length();
    };

    double ans = INF;
    for (int _ = 0; _ < 2; _++) {
        ans = min(ans, calc());
        swap(N, M);
        swap(A, B);
    }

    cout << (ans == INF ? -1 : ans) << '\n';
    return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 3620
final_rank: 7

code_snippet: #define LOCAL
#include <bits/stdc++.h>
using namespace std;
#pragma region Macros
typedef long long ll;
typedef __int128_t i128;
typedef unsigned int uint;
typedef unsigned long long ull;
#define ALL(x) (x).begin(), (x).end()

template <typename T> istream& operator>>(istream& is, vector<T>& v) {
    for (T& x : v) is >> x;
    return is;
}
template <typename T> ostream& operator<<(ostream& os, const vector<T>& v) {
    for (int i = 0; i < (int)v.size(); i++) {
        os << v[i] << (i + 1 == (int)v.size() ? "" : " ");
    }
    return os;
}
template <typename T, typename U> ostream& operator<<(ostream& os, const pair<T, U>& p) {
    os << '(' << p.first << ',' << p.second << ')';
    return os;
}
template <typename T, typename U> ostream& operator<<(ostream& os, const map<T, U>& m) {
    os << '{';
    for (auto itr = m.begin(); itr != m.end();) {
        os << '(' << itr->first << ',' << itr->second << ')';
        if (++itr != m.end()) os << ',';
    }
    os << '}';
    return os;
}
template <typename T, typename U> ostream& operator<<(ostream& os, const unordered_map<T, U>& m) {
    os << '{';
    for (auto itr = m.begin(); itr != m.end();) {
        os << '(' << itr->first << ',' << itr->second << ')';
        if (++itr != m.end()) os << ',';
    }
    os << '}';
    return os;
}
template <typename T> ostream& operator<<(ostream& os, const set<T>& s) {
    os << '{';
    for (auto itr = s.begin(); itr != s.end();) {
        os << *itr;
        if (++itr != s.end()) os << ',';
    }
    os << '}';
    return os;
}
template <typename T> ostream& operator<<(ostream& os, const multiset<T>& s) {
    os << '{';
    for (auto itr = s.begin(); itr != s.end();) {
        os << *itr;
        if (++itr != s.end()) os << ',';
    }
    os << '}';
    return os;
}
template <typename T> ostream& operator<<(ostream& os, const unordered_set<T>& s) {
    os << '{';
    for (auto itr = s.begin(); itr != s.end();) {
        os << *itr;
        if (++itr != s.end()) os << ',';
    }
    os << '}';
    return os;
}
template <typename T> ostream& operator<<(ostream& os, const deque<T>& v) {
    for (int i = 0; i < (int)v.size(); i++) {
        os << v[i] << (i + 1 == (int)v.size() ? "" : " ");
    }
    return os;
}

template <int i, typename T> void print_tuple(ostream&, const T&) {}
template <int i, typename T, typename H, class... Args> void print_tuple(ostream& os, const T& t) {
    if (i) os << ',';
    os << get<i>(t);
    print_tuple<i + 1, T, Args...>(os, t);
}
template <typename... Args> ostream& operator<<(ostream& os, const tuple<Args...>& t) {
    os << '{';
    print_tuple<0, tuple<Args...>, Args...>(os, t);
    return os << '}';
}

void debug_out() { cerr << '\n'; }
template <class Head, class... Tail> void debug_out(Head&& head, Tail&&... tail) {
    cerr << head;
    if (sizeof...(Tail) > 0) cerr << ", ";
    debug_out(move(tail)...);
}
#ifdef LOCAL
#define debug(...)                                                                   \
    cerr << " ";                                                                     \
    cerr << #__VA_ARGS__ << " :[" << __LINE__ << ":" << __FUNCTION__ << "]" << '\n'; \
    cerr << " ";                                                                     \
    debug_out(__VA_ARGS__)
#else
#define debug(...) 42
#endif

template <typename T> T gcd(T x, T y) { return y != 0 ? gcd(y, x % y) : x; }
template <typename T> T lcm(T x, T y) { return x / gcd(x, y) * y; }

int topbit(signed t) { return t == 0 ? -1 : 31 - __builtin_clz(t); }
int topbit(long long t) { return t == 0 ? -1 : 63 - __builtin_clzll(t); }
int botbit(signed a) { return a == 0 ? 32 : __builtin_ctz(a); }
int botbit(long long a) { return a == 0 ? 64 : __builtin_ctzll(a); }
int popcount(signed t) { return __builtin_popcount(t); }
int popcount(long long t) { return __builtin_popcountll(t); }
bool ispow2(int i) { return i && (i & -i) == i; }

template <class T> T ceil(T x, T y) {
    assert(y >= 1);
    return (x > 0 ? (x + y - 1) / y : x / y);
}
template <class T> T floor(T x, T y) {
    assert(y >= 1);
    return (x > 0 ? x / y : (x - y + 1) / y);
}

template <class T1, class T2> inline bool chmin(T1& a, T2 b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}
template <class T1, class T2> inline bool chmax(T1& a, T2 b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}
#pragma endregion

#include <algorithm>
#include <cassert>
#include <cmath>
#include <iostream>
#include <tuple>
#include <vector>

namespace geometry {
using Real = double;
constexpr Real EPS = 1e-8;
constexpr Real PI = 3.14159265358979323846L;

inline int sgn(Real x) { return x < -EPS ? -1 : x > EPS ? 1 : 0; }

inline int compare(Real a, Real b) { return sgn(a - b); }

inline bool equals(Real a, Real b) { return compare(a, b) == 0; }

struct Point {
    Real x, y;

    Point() {}

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

    Point& operator+=(const Point& p) {
        x += p.x, y += p.y;
        return *this;
    }

    Point& operator-=(const Point& p) {
        x -= p.x, y -= p.y;
        return *this;
    }

    Point& operator*=(const Real& k) {
        x *= k, y *= k;
        return *this;
    }

    Point& operator/=(const Real& k) {
        x /= k, y /= k;
        return *this;
    }

    Point operator+(const Point& p) const { return Point(*this) += p; }

    Point operator-(const Point& p) const { return Point(*this) -= p; }

    Point operator*(const Real& k) const { return Point(*this) *= k; }

    Point operator/(const Real& k) const { return Point(*this) /= k; }

    Point operator-() const { return Point(-x, -y); }

    bool operator==(const Point& p) const { return (compare(x, p.x) == 0 && compare(y, p.y) == 0); }

    bool operator!=(const Point& p) const { return !(*this == p); }

    bool operator<(const Point& p) const {
        return compare(x, p.x) < 0 || (compare(x, p.x) == 0 && compare(y, p.y) < 0);
    }

    bool operator>(const Point& p) const {
        return compare(x, p.x) > 0 || (compare(x, p.x) == 0 && compare(y, p.y) > 0);
    }

    friend std::istream& operator>>(std::istream& is, Point& p) { return is >> p.x >> p.y; }

    friend std::ostream& operator<<(std::ostream& os, const Point& p) { return os << p.x << ' ' << p.y; }

    Real norm() const { return x * x + y * y; }

    Real abs() const { return std::hypot(x, y); }

    Real arg() const { return std::atan2(y, x); }

    Point normal() const { return Point(-y, x); }

    Point unit() const { return *this / abs(); }

    Point rotate(Real theta) const {
        return Point(x * std::cos(theta) - y * std::sin(theta), x * std::sin(theta) + y * std::cos(theta));
    }
};

Point polar(const Real& r, const Real& theta) { return Point(cos(theta), sin(theta)) * r; }

Real dot(const Point& p, const Point& q) { return p.x * q.x + p.y * q.y; }

Real cross(const Point& p, const Point& q) { return p.x * q.y - p.y * q.x; }

Real distance(const Point& p, const Point& q) { return (p - q).abs(); }

struct Line {
    Point a, b;

    Line() {}

    Line(const Point& a, const Point& b) : a(a), b(b) {}

    Line(const Real& A, const Real& B, const Real& C) {  // Ax + By = c
        if (equals(A, 0)) {
            assert(!equals(B, 0));
            a = Point(0, C / B);
            b = Point(1, C / B);
        } else if (equals(B, 0)) {
            a = Point(C / A, 0);
            b = Point(C / A, 1);
        } else {
            a = Point(0, C / B);
            b = Point(C / A, 0);
        }
    }

    friend std::istream& operator>>(std::istream& is, Line& l) { return is >> l.a >> l.b; }

    friend std::ostream& operator<<(std::ostream& os, const Line& l) { return os << l.a << " to " << l.b; }

    Point diff() const { return b - a; }
};

struct Segment : Line {
    Segment() {}

    Segment(Point a, Point b) : Line(a, b) {}

    Real length() const { return diff().abs(); }
};

Point proj(const Line& l, const Point& p) {
    Point v = l.diff().unit();
    return l.a + v * dot(v, p - l.a);
}

Point refl(const Line& l, const Point& p) {
    Point h = proj(l, p);
    return h + (h - p);
}

bool orthogonal(const Line& l, const Line& m) { return equals(dot(l.diff(), m.diff()), 0); }

bool parallel(const Line& l, const Line& m) { return equals(cross(l.diff(), m.diff()), 0); }

enum Position { COUNTER_CLOCKWISE = +1, CLOCKWISE = -1, ONLINE_BACK = +2, ONLINE_FRONT = -2, ON_SEGMENT = 0 };

Position ccw(const Point& a, Point b, Point c) {
    b -= a, c -= a;
    if (sgn(cross(b, c)) == +1) return COUNTER_CLOCKWISE;
    if (sgn(cross(b, c)) == -1) return CLOCKWISE;
    if (sgn(dot(b, c)) == -1) return ONLINE_BACK;
    if (compare(b.norm(), c.norm()) == -1) return ONLINE_FRONT;
    return ON_SEGMENT;
}

bool intersect(const Line& l, const Point& p) { return abs(ccw(l.a, l.b, p)) != 1; }

bool intersect(const Line& l, const Line& m) {
    Real A = cross(l.diff(), m.diff()), B = cross(l.diff(), l.b - m.a);
    if (equals(A, 0) && equals(B, 0)) return true;
    return !parallel(l, m);
}

bool intersect(const Line& l, const Segment& s) {
    return sgn(cross(l.diff(), s.a - l.a)) * sgn(cross(l.diff(), s.b - l.a)) <= 0;
}

bool intersect(const Segment& s, const Point& p) { return ccw(s.a, s.b, p) == ON_SEGMENT; }

bool intersect(const Segment& s, const Segment& t) {
    return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 && ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

Real distance(const Line& l, const Point& p) { return distance(p, proj(l, p)); }

Real distance(const Line& l, const Line& m) { return intersect(l, m) ? 0 : distance(l, m.a); }

Real distance(const Line& l, const Segment& s) {
    return intersect(l, s) ? 0 : std::min(distance(l, s.a), distance(l, s.b));
}

Real distance(const Segment& s, const Point& p) {
    Point h = proj(s, p);
    return intersect(s, h) ? distance(p, h) : std::min(distance(p, s.a), distance(p, s.b));
}

Real distance(const Segment& s, const Segment& t) {
    if (intersect(s, t)) return 0;
    return std::min({distance(s, t.a), distance(s, t.b), distance(t, s.a), distance(t, s.b)});
}

}  // namespace geometry

/**
 * @brief 2 次元幾何ライブラリ
 * @docs docs/geometry/geometry.md
 */

const int INF = 1e9;
const long long IINF = 1e18;
const int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};
const char dir[4] = {'D', 'R', 'U', 'L'};
const long long MOD = 1000000007;
// const long long MOD = 998244353;

using namespace geometry;

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(15);
    int N, M;
    cin >> N >> M;
    vector<Point> A(N), B(M);
    for (auto& p : A) cin >> p;
    for (auto& p : B) cin >> p;

    auto calc = [&]() {
        Segment other(B[0], B[1]);
        vector<double> dp(N, INF);
        vector<bool> used(N, false);
        dp[0] = 0;

        while (1) {
            int v = -1;
            for (int u = 0; u < N; u++) {
                if (!used[u] && (v == -1 || dp[u] < dp[v])) {
                    v = u;
                }
            }
            if (v < 0) break;
            used[v] = true;
            for (int u = 0; u < N; u++) {
                Segment seg(A[v], A[u]);
                if (!intersect(other, seg)) dp[u] = min(dp[u], dp[v] + seg.length());
            }
        }

        return dp[1] + other.length();
    };

    double ans = INF;
    for (int _ = 0; _ < 2; _++) {
        ans = min(ans, calc());
        swap(N, M);
        swap(A, B);
    }

    cout << (ans == INF ? -1 : ans) << '\n';
    return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 3552
final_rank: 6

code_snippet: #pragma GCC optimize("Ofast")
#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
#include <queue>
#include <cstdio>
#include <ctime>
#include <assert.h>
#include <chrono>
#include <random>
#include <numeric>
#include <set>
#include <deque>
#include <stack>
#include <sstream>
#include <utility>
#include <cstring>
#include <unordered_map>
#include <unordered_set>
#include <tuple>
using namespace std;
typedef long long int ll;
typedef unsigned long long ull;

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
ll myRand(ll B) {
    return (ull)rng() % B;
}

const double eps=1e-10;

struct Point{
    double x,y;
};

struct Line{
    Point A,B;
};

// A-B
Point sub(Point A,Point B){
    A.x-=B.x; A.y-=B.y; return A;
}

double abs(Point P){
    return sqrt(P.x*P.x+P.y*P.y);
}

double dist(Point A,Point B){
    return abs(sub(A,B));
}

double dot(Point a,Point b){
    return a.x*b.x+a.y*b.y;
}

double cross(Point a,Point b){
    return a.x*b.y-a.y*b.x;
}

int ccw(Point a,Point b,Point c){
    b={b.x-a.x,b.y-a.y};
    c={c.x-a.x,c.y-a.y};
    if(cross(b,c)>eps)return 1; // a,b,c反時計回り
    if(cross(b,c)<-eps)return -1; // a,b,c時計周り
    if(dot(b,c)<-eps)return 2; // c,a,b 一直線
    if((b.x*b.x+b.y*b.y)<(c.x*c.x+c.y*c.y))return -2; // a,b,c 一直線
    return 0; // a,c,b 一直線
}

// 線分交差判定
bool intersect(Point a,Point b,Point c,Point d){
    if(ccw(a,b,c)*ccw(a,b,d)<=0 and ccw(c,d,a)*ccw(c,d,b)<=0)return 1;
    else return 0;
}

int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int n,m; cin >> n >> m;
    vector<Point> a(n),b(m);
    for(int i=0;i<n;i++){
        cin >> a[i].x >> a[i].y;
    }
    for(int i=0;i<m;i++){
        cin >> b[i].x >> b[i].y;
    }
    if(!intersect(a[0],a[1],b[0],b[1])){
        printf("%.9f\n",dist(a[0],a[1])+dist(b[0],b[1]));
        return 0;
    }
    double res = 1e18;
    // A
    {
        // 1点経由
        for(int i=2;i<n;i++){
            if(!intersect(a[0],a[i],b[0],b[1]) and !intersect(a[i],a[1],b[0],b[1])){
                res = min(res, dist(b[0],b[1])+dist(a[0],a[i])+dist(a[i],a[1]));
            }
        }
        // 2点経由
        for(int i=2;i<n;i++){
            for(int j=2;j<n;j++){
                if(i==j)continue;
                if(!intersect(a[0],a[i],b[0],b[1]) and !intersect(a[i],a[j],b[0],b[1]) and !intersect(a[j],a[1],b[0],b[1])){
                    res = min(res, dist(b[0],b[1])+dist(a[0],a[i])+dist(a[i],a[j])+dist(a[j],a[1]));
                }
            }
        }
    }
    // B
    {
        swap(a,b);
        swap(n,m);
        // 1点経由
        for(int i=2;i<n;i++){
            if(!intersect(a[0],a[i],b[0],b[1]) and !intersect(a[i],a[1],b[0],b[1])){
                res = min(res, dist(b[0],b[1])+dist(a[0],a[i])+dist(a[i],a[1]));
            }
        }
        // 2点経由
        for(int i=2;i<n;i++){
            for(int j=2;j<n;j++){
                if(i==j)continue;
                if(!intersect(a[0],a[i],b[0],b[1]) and !intersect(a[i],a[j],b[0],b[1]) and !intersect(a[j],a[1],b[0],b[1])){
                    res = min(res, dist(b[0],b[1])+dist(a[0],a[i])+dist(a[i],a[j])+dist(a[j],a[1]));
                }
            }
        }
    }
    if(res == 1e18){
        printf("-1\n");
    }
    else{
        printf("%.9f\n",res);
    }
}
accuracy: 1
time_ms: 20
memory_kb: 3612
final_rank: 2

code_snippet: #include <bits/stdc++.h>
#define rep(i,n) for(int i = 0; i < (n); i++)
using namespace std;
typedef long long ll;

using Real = double;
using Point = complex< double >;
using Polygon = vector< Point >;
const Real EPS = 1e-9, PI = acos(-1);
constexpr int COUNTER_CLOCKWISE = +1;
constexpr int CLOCKWISE = -1;
constexpr int ONLINE_BACK = +2;  // c-a-b
constexpr int ONLINE_FRONT = -2; // a-b-c
constexpr int ON_SEGMENT = 0;    // a-c-b

Point operator*(const Point &p, const Real &d) {
    return Point(real(p) * d, imag(p) * d);
}

Point operator/(const Point &p, const Real &d) {
    return Point(real(p) / d, imag(p) / d);
}

istream &operator>>(istream &is, Point &p) {
    Real a, b; is >> a >> b;
    p = Point(a, b);
    return is;
}

ostream &operator<<(ostream &os, const Point &p) {
    return os << fixed << setprecision(10) << real(p) << " " << imag(p);
}

namespace std {
    bool operator<(const Point &a, const Point &b) {
        return a.real() != b.real() ? a.real() < b.real() : a.imag() < b.imag();
    }
}

// 符号
inline int sign(const Real &r) {
    return r <= -EPS ? -1 : r >= EPS ? 1 : 0;
}

// a = b ? 
inline bool equals(const Real &a, const Real &b) {
    return sign(a - b) == 0;
}


// 単位ベクトル
Point unitVec(const Point &a){ return a / abs(a); }

// 法線ベクトル 半時計周り
Point normVec(const Point &a){ return a * Point(0, 1); }
//Point normVec(const Point &a){ return a * Point(0,-1); }

// 内積
Real dot(const Point &a, const Point &b) {
    return (a.real() * b.real() + a.imag() * b.imag());
}

// 外積
Real cross(const Point &a, const Point &b) {
    return (a.real() * b.imag() - a.imag() * b.real());
}

Point rotate(const Point &p, const Real &theta) {
    return Point(cos(theta) * p.real() - sin(theta) * p.imag(),
                 sin(theta) * p.real() + cos(theta) * p.imag());
}

Real Radian_To_Degree(const Real &radian){ return radian * 180.0 / PI; }
Real Degree_To_Radian(const Real &degree){ return degree * PI / 180.0; }

struct Line {
    Point a, b;
    Line() = default;
    Line(Point a, Point b) : a(a), b(b) {}

    // Ax + By = C
    Line(Real A, Real B, Real C) {
        if(equals(A, 0)) {
            a = Point(0, C / B), b = Point(1, C / B);
        }else if(equals(B,0)) {
            b = Point(C / A, 0), b = Point(C / A, 1);
        }else{
            a = Point(0, C / B), b = Point(C / A, 0);
        }
    }

    friend ostream &operator<<(ostream &os, Line &p) {
        return os << p.a << " " << p.b;
    }

    friend istream &operator>>(istream &is, Line &a) {
        return is >> a.a >> a.b;
    }
};

struct Segment : Line {
    Segment() = default;
    Segment(Point a, Point b) : Line(a, b) {}
};

struct Circle {
    Point p;
    Real r;
    Circle() = default;
    Circle(Point p, Real r) : p(p), r(r) {}

    friend ostream &operator<<(ostream &os, Circle &c) {
        return os << c.p << " " << c.r;
    }

    friend istream &operator>>(istream &is, Circle &c) {
        return is >> c.p >> c.r;
    }
};

// 直線lに点pから引いた垂線の足を求める
Point projection(const Line &l, const Point &p) {
    Real t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
    return l.a + (l.a - l.b) * t;
}

Point projection(const Segment &l, const Point &p) {
    Real t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
    return l.a + (l.a - l.b) * t;
}

// 直線lに関して点pと対称な点を求める
Point reflection(const Line &l, const Point &p) {
    return p + (projection(l, p) - p) * 2.0;
}

// 点の回転方向
// 点aを基準に点b,cの位置関係
int ccw(const Point &a, Point b, Point c) {
    b = b - a, c = c - a;
    if(sign(cross(b, c)) == +1) return COUNTER_CLOCKWISE; // 反時計回り
    if(sign(cross(b, c)) == -1) return CLOCKWISE;         // 時計回り
    if(sign(dot(b, c)) == -1) return ONLINE_BACK;         // c - a - b
    if(norm(b) < norm(c)) return ONLINE_FRONT;            // a - b - c
    return ON_SEGMENT;                                    // a - c - b
}

// 2直線の直交判定
bool is_orthogonal(const Line &a, const Line &b) {
    return equals(dot(a.b - a.a, b.b - b.a), 0);
}

// 2直線の平行判定
bool is_parallel(const Line &a, const Line &b) {
    return equals(cross(a.b - a.a, b.b - b.a), 0);
}

// 線分の交差判定
bool is_intersect_ss(const Segment &s, const Segment &t) {
    return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 &&
           ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

// 直線の交差判定
bool is_intersect_ll(const Line &l, const Line &m) {
    Real A = cross(l.b - l.a, m.b - m.a);
    Real B = cross(l.b - l.a, l.b - m.a);
    if(equals(abs(A), 0) && equals(abs(B), 0)) return true;
    return !is_parallel(l, m);
}

// 線分に点が乗っているか
bool is_intersect_sp(const Segment &s, const Point &p) {
    return ccw(s.a, s.b, p) == ON_SEGMENT;
}

// 点と点の距離
Real distance_pp(const Point &p1, const Point &p2) {
    return sqrt(pow(real(p1)-real(p2), 2) + pow(imag(p1)-imag(p2), 2));
}

// 点と直線の距離
Real distance_lp(const Line &l, const Point &p) {
    return abs(p - projection(l, p));
}

// 直線と直線の距離
Real distance_ll(const Line &l, const Line &m) {
    return is_intersect_ll(l, m) ? 0 : distance_lp(l, m.a);
}

// 点と線分の距離
Real distance_sp(const Segment &s, const Point &p) {
    Point r = projection(s, p);
    if(is_intersect_sp(s, r)) return abs(r - p);
    return min(abs(s.a - p), abs(s.b - p));
}

// 線分と線分の距離
Real distance_ss(const Segment &a, const Segment &b) {
    if(is_intersect_ss(a, b)) return 0;
    return min({distance_sp(a, b.a), distance_sp(a, b.b), distance_sp(b, a.a), distance_sp(b, a.b)});
}

// 交点
Point cross_point_ll(const Line &l, const Line &m) {
    Real A = cross(l.b - l.a, m.b - m.a);
    Real B = cross(l.b - l.a, l.b - m.a);
    if(equals(abs(A), 0) && equals(abs(B), 0)) return m.a;
    return m.a + (m.b - m.a) * B / A;
}

// 円と円の位置関係
int intersect(Circle c1, Circle c2) {
    if(c1.r < c2.r) swap(c1, c2);
    Real d = abs(c1.p - c2.p);
    if(c1.r + c2.r < d) return 4;
    if(equals(c1.r + c2.r, d)) return 3;
    if(c1.r - c2.r < d) return 2;
    if(equals(c1.r - c2.r, d)) return 1;
    return 0;
}

Real area(const Polygon &p){
    Real A = 0;
    for(int i = 0; i < p.size(); i++){
        A += cross(p[i], p[(i + 1) % p.size()]);
    }
    return A * 0.5;
}

bool is_convex(const Polygon &p){
    for(int i = 0; i < p.size(); i++){
        if(ccw(p[(i + p.size() - 1) % p.size()], p[i], p[(i + 1) % p.size()]) == -1) return false;
    }
    return true;
}

enum { OUT, ON, IN };
int contains(const Polygon &Q, const Point &p){
    bool in = false;
    for(int i = 0; i < Q.size(); i++){
        Point a = Q[i] - p, b = Q[(i + 1) % Q.size()] - p;
        if(a.imag() > b.imag()) swap(a, b);
        if(a.imag() <= 0 && 0 < b.imag() && cross(a, b) < 0) in = !in;
        if(cross(a, b) == 0 && dot(a, b) <= 0) return ON;
    }
    return in ? IN : OUT;
}

Polygon convex_hull(Polygon &p, bool strict = true){
    int n = (int)p.size(), k = 0;
    if(n <= 2) return p;
    sort(p.begin(), p.end());
    Polygon ch(2 * n);
    for(int i = 0; i < n; ch[k++] = p[i++]){
        while(k >= 2 && cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < 0) --k;
    }
    for(int i = n - 2, t = k + 1; i >= 0; ch[k++] = p[i--]){
        while(k >= t && cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < 0) --k;
    }
    ch.resize(k - 1);
    return ch;
}

Real convex_diameter(const Polygon &p){
    int n = (int)p.size();
    int is = 0, js = 0;
    for(int i = 1; i < n; i++){
        if(p[i].imag() > p[is].imag()) is = i;
        if(p[i].imag() < p[js].imag()) js = i;
    }
    Real maxdis = norm(p[is] - p[js]);
    int maxi, maxj, i, j;
    i = maxi = is;
    j = maxj = js;
    do {
        if(cross(p[(i + 1) % n] - p[i], p[(j + 1) % n] - p[j]) >= 0){
            j = (j + 1) % n;
        }else{
            i = (i + 1) % n;
        }

        if(norm(p[i] - p[j]) > maxdis){
            maxdis = norm(p[i] - p[j]);
            maxi = i;
            maxj = j;
        }

    }while(i != is || j != js);
    return sqrt(maxdis);
}

Polygon convex_cut(const Polygon &U, Line l){
    Polygon ret;
    for(int i = 0; i < U.size(); i++){
        Point now = U[i], nxt = U[(i + 1) % U.size()];
        if(ccw(l.a, l.b, now) != -1) ret.push_back(now);
        if(ccw(l.a, l.b, now) * ccw(l.a, l.b, nxt) < 0){
            ret.push_back(cross_point_ll(Line(now, nxt), l));
        }
    }
    return ret;
}

Real ClosetPair(Polygon& ps){
    if(ps.size() <= 1) throw (0);
    sort(begin(ps), end(ps));

    auto compare_y = [&](const Point &a, const Point &b) {
        return a.imag() < b.imag();
    };
    Polygon beet(ps.size());
    const double INF = 1e18;

    function< double(int, int) > rec = [&](int left, int right) {
        if(right - left <= 1) return INF;
        int mid = (left + right) >> 1;
        auto x = ps[mid].real();
        auto ret = min(rec(left, mid), rec(mid, right));
        inplace_merge(begin(ps) + left, begin(ps) + mid, begin(ps) + right, compare_y);
        int ptr = 0;
        for(int i = left; i < right; i++) {
            if(fabs((ps[i].real()) - x) >= ret) continue;
            for(int j = 0; j < ptr; j++) {
                auto luz = ps[i] - beet[ptr - j - 1];
                if(luz.imag() >= ret) break;
                ret = min(ret, abs(luz));
            }
            beet[ptr++] = ps[i];
        }
        return ret;
    };
    return rec(0, (int) ps.size());
}

pair< Point, Point > cross_point_cc(const Circle &c1, const Circle &c2) {
    Real d = abs(c1.p - c2.p);
    Real a = acos((c1.r * c1.r + d * d - c2.r * c2.r) / (2 * c1.r * d));
    Real t = atan2(c2.p.imag() - c1.p.imag(), c2.p.real() - c1.p.real());
    Point p1 = c1.p + Point(cos(t + a) * c1.r, sin(t + a) * c1.r);
    Point p2 = c1.p + Point(cos(t - a) * c1.r, sin(t - a) * c1.r);
    return {p1, p2};
}

const int BOTTOM = 0;
const int LEFT   = 1;
const int RIGHT  = 2;
const int TOP    = 3;

class endPoint {
    public:
        Point p;
        int seg; // id of Point
        int st; // kind of Point
        endPoint(){}
        endPoint(Point inp, int inseg, int inst):p(inp),seg(inseg),st(inst){}
        bool operator<(const endPoint &ep)const {
            if(p.imag() == ep.p.imag()) return st < ep.st;
            else return p.imag() < ep.p.imag();
        }
};

endPoint EP[220000];
int Manhattan_Intersections(vector< Segment > s){
    int n = s.size();
    double hoge;

    for(int i = 0, k = 0; i < n; i++){
        if(s[i].a.imag() == s[i].b.imag()){
            if(s[i].a.real() > s[i].b.real()){
                hoge = s[i].a.real();
                s[i].a.real(s[i].b.real());
                s[i].b.real(hoge);
            }
        }else if(s[i].a.imag() > s[i].b.imag()){
            hoge = s[i].a.imag();
            s[i].a.imag(s[i].b.imag());
            s[i].b.imag(hoge);
        }

        if(s[i].a.imag() == s[i].b.imag()){
            EP[k++] = endPoint(s[i].a, i, LEFT);
            EP[k++] = endPoint(s[i].b, i, RIGHT);
        }else{
            EP[k++] = endPoint(s[i].a, i, BOTTOM);
            EP[k++] = endPoint(s[i].b, i, TOP);
        }
    }

    sort(EP, EP + 2 * n);
    set<int> BT;
    BT.insert(1000000001);
    int cnt = 0;
    for(int i = 0; i < 2 * n; i++){
        if(EP[i].st == TOP) BT.erase(EP[i].p.real());
        else if(EP[i].st == BOTTOM) BT.insert(EP[i].p.real());
        else if(EP[i].st == LEFT){
            set<int>::iterator b = lower_bound(BT.begin(), BT.end(), s[EP[i].seg].a.real());
            set<int>::iterator e = upper_bound(BT.begin(), BT.end(), s[EP[i].seg].b.real());
            cnt += distance(b, e);
        }
    }

    return cnt;
}

// 内接円
Circle Inscribed_Circle(const Point& a, const Point& b, const Point& c){
    double A = abs(b - c), B = abs(c - a), C = abs(a - b);
    Point x = Point((a * A + b * B + c * C) / (A + B + C));
    double r = distance_sp(Segment(a,b),x);
    return Circle(x, r);
}

// 外接円
Circle Circumscribed_Circle(const Point& a, const Point& b, const Point& c){
    Point m1((a+b)/2.0), m2((b+c)/2.0);
    Point v((b-a).imag(), (a-b).real()), w((b-c).imag(), (c-b).real());
    Line s(m1, Point(m1+v)), t(m2, Point(m2+w));
    const Point x = cross_point_ll(s, t);
    return Circle(x, abs(a-x));
}

pair< Point, Point > cross_point_cl(const Circle &c, const Line &l) {
    Point pr = projection(l, c.p);
    if(equals(abs(pr - c.p), c.r)) return {pr, pr};
    Point e = (l.b - l.a) / abs(l.b - l.a);
    auto k = sqrt(norm(c.r) - norm(pr - c.p));
    return {pr - e * k, pr + e * k};
}

// 点pを通る円の接線
pair<Point,Point> tangent_cp(const Circle &c, const Point &p) {
    return cross_point_cc(c, Circle(p, sqrt(norm(c.p - p) - c.r * c.r)));
}

// 二つの円の共通接線
vector< Line > tangent_cc(Circle c1, Circle c2){
    vector< Line > ret;
    if(c1.r < c2.r) swap(c1,c2);
    double g = norm(c1.p-c2.p);
    if(equals(g,0.0)) return ret;
    Point u = (c2.p-c1.p)/sqrt(g);
    Point v = rotate(u, PI * 0.5);
    for(int s:{-1,1}){
        double h = (c1.r+ s*c2.r)/sqrt(g);
        if(equals(1- h*h, 0)){
            ret.emplace_back(c1.p+u*c1.r, c1.p+(u+v)*c1.r);
        }else if(1-h*h > 0){
            Point uu = u*h, vv = v*sqrt(1-h*h);
            ret.emplace_back(c1.p+(uu+vv)*c1.r, c2.p-(uu+vv)*c2.r*s);
            ret.emplace_back(c1.p+(uu-vv)*c1.r, c2.p-(uu-vv)*c2.r*s);
        }
    }
    return ret;
}

Real area_poly_c(const Polygon &p, const Circle &c) {
    if(p.size() < 3) return 0.0;
    function< Real(Circle, Point, Point) > cross_area = [&](const Circle &c, const Point &a, const Point &b) {
        Point va = c.p - a, vb = c.p - b;
        Real f = cross(va, vb), ret = 0.0;
        if(equals(f, 0.0)) return ret;
        if(max(abs(va), abs(vb)) < c.r + EPS) return f;
        if(distance_sp(Segment(a, b), c.p) > c.r - EPS) return c.r * c.r * arg(vb * conj(va));
        auto u = cross_point_cl(c, Segment(a, b));
        vector< Point > tot{a, u.first, u.second, b};
        for(int i = 0; i + 1 < tot.size(); i++) {
            ret += cross_area(c, tot[i], tot[i + 1]);
        }
        return ret;
    };
    Real A = 0;
    for(int i = 0; i < p.size(); i++) {
        A += cross_area(c, p[i], p[(i + 1) % p.size()]);
    }
    return A;
}

Real area_cc(const Circle &c1, const Circle &c2) {
    Real d = abs(c1.p - c2.p);
    if(c1.r + c2.r <= d + EPS) return 0.0;
    if(d <= fabs(c1.r - c2.r) + EPS) {
        Real r = min(c1.r, c2.r);
        return r * r * PI;
    }
    Real rc = (d * d + c1.r * c1.r - c2.r * c2.r) / (2 * d);
    Real theta = acos(rc / c1.r);
    Real phi = acos((d - rc) / c2.r);
    return (c1.r * c1.r*theta + c2.r*c2.r*phi - d*c1.r*sin(theta));
}

// g <- pair < v , cost > 
template < class T >
vector<T> Dijkstra(vector<vector<pair<int,T>>> &g, int s) {
    vector<T> dist(g.size(), -1);
    priority_queue<pair<T,int>> Q;
    Q.emplace(0, s);
    while(!Q.empty()){
        T cost = Q.top().first;
        int v = Q.top().second;
        Q.pop();
        cost = - cost;
        if(dist[v] == -1){
            dist[v] = cost;
            for(auto e : g[v]){
                if(dist[e.first] == -1){
                    Q.emplace(-(cost + e.second), e.first);
                }
            }
        }
    }
    for(auto &d : dist) if(d == -1) d = 1e9;
    return dist;
}

int main(){
    cin.tie(0);
    ios::sync_with_stdio(0);
    
    int N,M; cin >> N >> M;
    vector<Point> A(N),B(M);
    rep(i,N) cin >> A[i];
    rep(i,M) cin >> B[i];

    Segment l(B[0], B[1]);
    vector<vector<pair<int,Real>>> G(N);
    rep(j,N)rep(i,j){
        if(!is_intersect_ss(l, Segment(A[i], A[j]))){
            Real cost = abs(A[i] - A[j]);
            G[i].push_back({j, cost});
            G[j].push_back({i, cost});
        }
    }

    l = Segment(A[0], A[1]);
    vector<vector<pair<int,Real>>> H(M);
    rep(j,M)rep(i,j){
        if(!is_intersect_ss(l, Segment(B[i], B[j]))) {
            Real cost = abs(B[i] - B[j]);
            H[i].push_back({j, cost});
            H[j].push_back({i, cost});
        }
    }

    Real ans_a = Dijkstra(G, 0)[1] + abs(B[0] - B[1]);
    Real ans_b = Dijkstra(H, 0)[1] + abs(A[0] - A[1]);
    Real ans = min(ans_a, ans_b);
    cout.precision(17);
    cout << (ans < 1e9 ? ans : -1) << endl;
}
accuracy: 1
time_ms: 130
memory_kb: 54372
final_rank: 18

code_snippet: #include <bits/stdc++.h>
using namespace std;

#include <algorithm>
#include <iostream>
#include <complex>
#include <cstdio>
#include <cmath>
#include <utility>
#include <vector>
using namespace std;
using W = double;
using P = complex<W>;
using L = pair<P,P>;
using C = pair<P,W>;
using Poly = vector<P>;
#define X real()
#define Y imag()
const W EPS = (1e-10), pi = acos(-1);

namespace std{
  bool operator < (const P& a, const P& b){
    return a.X != b.X ? a.X < b.X : a.Y < b.Y;
  }
  bool cmp_y(const P &a, const P &b){
    return a.Y != b.Y ? a.Y < b.Y : a.X < b.X;
  }
  bool operator == (const P& a, const P& b){
    return abs(a-b) < EPS;
  }
}

double dot(P a, P b){ return a.X * b.X + a.Y * b.Y;}
W cross(P a, P b){ return a.X * b.Y - a.Y * b.X;}
P projection(P a, P b){ return dot(a, b)/abs(b)/abs(b)*b;}
P projection(P a, L l){ return l.first + projection(a-l.first,l.second-l.first);}

//直線aと直線bの交点
P intersection(L a, L b){
  P af = a.first, as = a.second, bf = b.first, bs = b.second;
  return af + cross(bs-bf,af-bf)/(-cross(bs-bf,as-bf)+cross(bs-bf,af-bf))*(as-af);
}

//cがa/bと重なってる時は0を返す
//cがa/bと重なってる時+-2を返して欲しいなら+-2のところのEPSの符号を逆にする
int ccw(P a, P b, P c){
  b -= a; c -= a;
  if(cross(b,c) > EPS) return +1;
  if(cross(b,c) < -EPS) return -1;
  if(dot(b,c) < -EPS) return +2;
  if(norm(b) < norm(c)-EPS) return -2;
  return 0;
}

//端点が重なっててもtrueになる
//等号を無くせば端点が重なってる時はfalseにできる
bool is_cross(L a, L b){
  P af = a.first, as = a.second, bf = b.first, bs = b.second;
  return (ccw(af,as,bf)*ccw(af,as,bs) <= 0 && ccw(bf,bs,af)*ccw(bf,bs,as) <= 0);
}

// バグるケース？
W ps_dist(P a, L s){
  P sf = s.first, ss = s.second;
  if(dot(ss-sf,a-sf) >= 0 && dot(sf-ss,a-ss) >= 0)
    return abs(cross(sf-ss,a-ss))/abs(sf-ss);
  return min(abs(a-sf), abs(a-ss));
}

W pl_dist(P a, L s){
  P sf = s.first, ss = s.second;
  return abs(cross(sf-ss,a-ss))/abs(sf-ss);
}

W ss_dist(L a, L b){
  if(is_cross(a,b)) return 0;
  P af = a.first, as = a.second, bf = b.first, bs = b.second;
  return min({ps_dist(af,b),ps_dist(as,b),ps_dist(bf,a),ps_dist(bs,a)});
}

// 反時計回り想定、でないとマイナス？
// 非凸でも面積は求められる
W area(const Poly &p){
  int n = p.size();
  W s = 0;
  for(int i = 0; i < n; ++i) s += cross(p[i],p[(i+1)%n])/2;
  return s;
}

// 凸かどうかの判定
// 内角が180度未満か
bool is_convex(const Poly &p){
  int n = p.size();
  for(int i = 0; i < n; ++i)
    if(cross(p[(i+1)%n]-p[i],p[(i+2)%n]-p[(i+1)%n]) < 0) return false;
  return true;
}

// 点が多角形のどこにある？
int in_poly(P a, const Poly &p){
  int n = p.size(), c = 0;
  for(int i = 0; i < n; ++i){
    P s = p[i]-a, t = p[(i+1)%n]-a;
    if(!ccw(s,t,P(0,0))) return 1;//辺上
    if(s.Y > t.Y + EPS) swap(s,t);
    if((s.Y*t.Y < 0 || (s.Y*t.Y < EPS && t.Y > EPS)) && cross(s,t) < EPS) ++c;
  }
  if(c%2) return 2;//内部
  return 0;//外部
}

// 凸包
Poly convex_hull(Poly v){
  int n = v.size(), k = 0;
  sort(v.begin(), v.end(), cmp_y);
  Poly r(2*n);
  for(int i = 0; i < n; i++){
    while(k>1 && cross(r[k-1]-r[k-2],v[i]-r[k-2]) < -EPS) k--;
    r[k++] = v[i];
  }
  for(int i = n-2, t = k; i >= 0; i--){
    while(k>t && cross(r[k-1]-r[k-2],v[i]-r[k-2]) < -EPS) k--;
    r[k++] = v[i];
  }
  r.resize(k-1);
  return r;
}

//凸多角形の直径(距離最長の2点)を求める
W convex_diam(Poly p){
  int n = p.size(), i = 0, j = 0;
  if(n <= 1) return 0;
  if(n == 2) return abs(p[0]-p[1]);

  for(int k = 0; k < n; ++k){
    if(!(p[i] < p[k])) i = k;
    if(p[j] < p[k]) j = k;
  }
  
  W res = 0;
  int si = i, sj = j;
  while(i != sj || j != si){
    res = max(res, abs(p[i]-p[j]));
    if(cross(p[(i+1)%n]-p[i],p[(j+1)%n]-p[j]) < 0) i = (i+1)%n;
    else j = (j+1)%n;
  }
  return res;
}

//円と円の交点
vector<P> intersection(C a, C b){
  P ca = a.first, cb = b.first;
  W d = abs(ca-cb), ra = a.second, rb = b.second;
  W t = (ra*ra-rb*rb+d*d)/2/d, h = sqrt(ra*ra-t*t);
  P m = t/abs(cb-ca)*(cb-ca)+ca;
  vector<P> cp(2,m);
  P n = (ca-cb)*P(0,1);
  n *= h/abs(n);
  cp[0] -= n;
  cp[1] += n;
  return cp;
}

//点pから円cに伸ばした接線の接点を求める
//intersection(C,C)が必要
vector<P> tangent_to_C(P p, C c){
  C c2 = C((p+c.first)/2.0,abs(p-c.first)/2.0);
  return intersection(c,c2);
}

//円a,bの共通接線の円aの接点を求める
//tangent_to_Cが必要
//注意：同じ円を与えると壊れる
vector<P> common_tangent(C a, C b){
  vector<P> ret, cp;
  P af = a.first, bf = b.first;
  W ar = a.second, br = b.second;
  if(abs(ar-br) < EPS){
    P n = (bf-af)*P(0,1);
    n /= abs(n);
    ret.push_back(af+ar*n);
    ret.push_back(af-ar*n);
  }
  P i = (af*br+bf*ar)/(ar+br);
  if(abs(af-bf) > ar+br){//4本
    cp = tangent_to_C(i,a);
    for(int i = 0; i < 2; ++i) ret.push_back(cp[i]);
    if(abs(ar-br) > EPS){
      P e = (af*br-bf*ar)/(br-ar);
      cp = tangent_to_C(e,a);
      for(int i = 0; i < 2; ++i) ret.push_back(cp[i]);
    }
  }else if(abs(abs(af-bf)-(ar+br)) < EPS){//3本
    cp = tangent_to_C(i,a);
    ret.push_back(cp[0]);
    if(abs(ar-br) > EPS){
      P e = (af*br-bf*ar)/(br-ar);
      cp = tangent_to_C(e,a);
      for(int i = 0; i < 2; ++i) ret.push_back(cp[i]);
    }
  }else if(abs(af-bf) > abs(ar-br)){//2本
    if(abs(ar-br) > EPS){
      P e = (af*br-bf*ar)/(br-ar);
      cp = tangent_to_C(e,a);
      for(int i = 0; i < 2; ++i) ret.push_back(cp[i]);
    }
  }else if(abs(abs(af-bf) - abs(ar-br)) < EPS){//1本
    P e = (af*br-bf*ar)/(br-ar);
    cp = tangent_to_C(e,a);
    ret.push_back(cp[0]);
  }
  return ret;//0本
}

//円cと直線lの交点
 //接する場合は同一の点を二つ返す
//交点がないときこわれる
//pl_distが必要
vector<P> intersection(C c, L l){
  W d = pl_dist(c.first,l), r = c.second;
  P lf = l.first, ls = l.second;
  P m = lf + projection(c.first-lf,ls-lf);
  P x = sqrt(r*r-d*d)/abs(ls-lf)*(ls-lf);
  vector<P> cp(2,m);
  cp[0] -= x;
  cp[1] += x;
  return cp;
}

//三角形の三辺の長さa, b, cから面積を求める
W Heron(W a, W b, W c){
  W s = (a+b+c)/2;
  return sqrt(s*(s-a)*(s-b)*(s-c));
}

//点pと直線lに対して線対称な点
P line_symmetry(L l, P p){
  P lf = l.first, ls = l.second;
  return p + (lf - p + projection(p-lf,ls-lf))*2.0;
}

P line_symmetry(P p, L l){
  return line_symmetry(l,p);
}

// Projection を写したくない時はこっち
// P line_symmetry(L l, P p){
//   P f = l.first, s = l.second - f, q = p - f;
//   if(abs(q) < EPS) return p;
//   return f + norm(q/s)*s*s/q;
// }

// 2点から等距離の点の線
L vertical_bisector(P a, P b){
  P d = (a-b);
  P m = (a+b)/2.0;
  return L(m,m+d*P(0.0,1.0));
}

// 角ABCの2等分線
L angle_bisector(P a, P b, P c){
  P p = b + (a-b)/abs(a-b) + (c-b)/abs(c-b);
  return L(b,p);
}

//円と円の共通面積
//intersection(C,C)が必要
W common_area(C a, C b){
  if(a.second > b.second) swap(a,b);
  P ca = a.first, cb = b.first;
  W ra = a.second, rb = b.second;
  if(ra < EPS) return 0;
  if(norm(ca - cb) < norm(ra - rb) + EPS)
    return min(ra*ra, rb*rb)*pi;
  if(norm(ca - cb) > norm(ra + rb) + EPS)
    return 0;
  vector<P> cp = intersection(a,b);
  if(norm(cp[0] - cp[1]) < EPS) return 0;
  P aa = (cp[0]-ca)/(cp[1]-ca);
  P bb = (cp[0]-cb)/(cp[1]-cb);
  W theta_a = abs(atan2l(aa.Y,aa.X));
  W theta_b = abs(atan2l(bb.Y,bb.X));

  if(ccw(cp[0], cp[1], ca)*ccw(cp[0], cp[1], cb) >= 0){
    theta_a = max(2*pi - theta_a, theta_a);
    theta_b = min(2*pi - theta_b, theta_b);
  }else{
    theta_a = min(2*pi - theta_a, theta_a);
    theta_b = min(2*pi - theta_b, theta_b);
  }
  W sa = (theta_a-sinl(theta_a))*0.5, sb = (theta_b-sinl(theta_b))*0.5;
  W ans = ra*sa*ra + rb*sb*rb;
  return ans;
}

//凸多角形を直線で切る
//l.firstからl.secondを見て左側が残る
//ccwが必要
//intersectionが必要
Poly convex_cut(const Poly &p, L l){
  Poly ret;
  int n = p.size();
  for(int i = 0; i < n; ++i){
    P cur = p[i], nex = p[(i+1)%n], lf = l.first, ls = l.second;
    if(ccw(lf, ls, cur) != -1)
      ret.push_back(cur);
    if((ccw(lf, ls, cur) != -1) ^ (ccw(lf, ls, nex) != -1))
      ret.push_back(intersection(L(cur, nex), l));
  }
  return ret;
}

//円と非凸多角形の共通面積
//ps_dist, intersection(C,L), ccw, が必要
W common_area(C c, Poly p){
  W ret = 0, r = c.second;
  int n = p.size();
  for(int i = 0; i < n; ++i) p[i] -= c.first;//これの必要性がわからん
  for(int i = 0; i < n; ++i){
    P cur = p[i], nex = p[(i+1)%n];
    if(abs(cur*nex) < EPS) continue;
    W d = arg(nex/cur);
    ret += r*r*d/2.0;
    if(ps_dist(P(0,0),L(cur,nex)) < r - EPS){
      vector<P> cps = intersection(C(P(0,0),r),L(cur,nex));//ここが変わるだけ？
      P a, b;
      if(ccw(cur,nex,cps[0]) == 0 &&
         ccw(cur,nex,cps[1]) == 0)
        a = cps[0], b = cps[1];
      else if(!ccw(cur,nex,cps[0]))
        a = cps[0], b = nex;
      else if(!ccw(cur,nex,cps[1]))
        a = cur, b = cps[1];
      else
        a = cur, b = nex;
      if(abs(a*b) < EPS) continue;
      d = arg(b/a);
      ret += cross(a,b)*0.5 - r*r*d*0.5;
    }
  }
  return ret;
}

/*
  ピックの定理
  頂点が全て格子点にあるような単純な多角形の面積を S とし,
  多角形の内部にある格子点の数を i, 辺上の格子点の数を b とすると
  S = i + b/2 - 1
  が成り立つ。
*/

using PP = pair<double,int>;
#define INF 1e9

int main() {
  
  ios::sync_with_stdio(false);
  cin.tie(0);
  
  int n1,n2;
  cin >> n1 >> n2;
  vector<double> x1(n1),y1(n1);
  vector<double> x2(n2),y2(n2);
  for (int i=0;i<n1;i++) {
    cin >> x1[i] >> y1[i];
  }
  for (int i=0;i<n2;i++) {
    cin >> x2[i] >> y2[i];
  }
  double ans = INF;
  vector<double> dist(n1,INF);
  dist[0] = 0.0;
  priority_queue<PP,vector<PP>,greater<PP>> pq; 
  pq.push(PP(0.0,0));
  vector<vector<double>> c1(n1,vector<double>(n1,INF));
  for (int i=0;i<n1;i++) {
    c1[i][i] = 0.0;
  }
  P pb21 = complex(x2[0],y2[0]);
  P pb22 = complex(x2[1],y2[1]);
  L lb2 = make_pair(pb21,pb22);
  for (int i=0;i<n1;i++) {
    for (int j=i+1;j<n1;j++) {
      P p1 = complex(x1[i],y1[i]);
      P p2 = complex(x1[j],y1[j]);
      L l1 = make_pair(p1,p2);
      if (!is_cross(lb2,l1)) {
        c1[i][j] = abs(p2-p1);
        c1[j][i] = abs(p2-p1);
      }
    }
  }
  while (!pq.empty()) {
    PP np = pq.top();
    pq.pop();
    double nd = np.first;
    int now = np.second;
    if (dist[now]+EPS < nd) continue;
    for (int j=0;j<n1;j++) {
      double tdist = nd+c1[now][j];
      if (tdist+EPS < dist[j]) {
        dist[j] = tdist;
        pq.push(PP(dist[j],j));
      }
    }
  }
  ans = min(ans,abs(pb21-pb22)+dist[1]);
  vector<double> dist2(n2,INF);
  dist2[0] = 0.0;
  pq.push(PP(0.0,0));
  vector<vector<double>> c2(n2,vector<double>(n2,INF));
  for (int i=0;i<n2;i++) {
    c2[i][i] = 0.0;
  }
  pb21 = complex(x1[0],y1[0]);
  pb22 = complex(x1[1],y1[1]);
  lb2 = make_pair(pb21,pb22);
  for (int i=0;i<n2;i++) {
    for (int j=i+1;j<n2;j++) {
      P p1 = complex(x2[i],y2[i]);
      P p2 = complex(x2[j],y2[j]);
      L l1 = make_pair(p1,p2);
      if (!is_cross(lb2,l1)) {
        c2[i][j] = abs(p2-p1);
        c2[j][i] = abs(p2-p1);
      }
    }
  }
  while (!pq.empty()) {
    PP np = pq.top();
    pq.pop();
    double nd = np.first;
    int now = np.second;
    if (dist2[now]+EPS < nd) continue;
    for (int j=0;j<n2;j++) {
      double tdist = nd+c2[now][j];
      if (tdist+EPS < dist2[j]) {
        dist2[j] = tdist;
        pq.push(PP(dist2[j],j));
      }
    }
  }
  ans = min(ans,abs(pb21-pb22)+dist2[1]);
  if (ans > INF/2.0) cout << -1 << endl;
  else cout << fixed << setprecision(15) << ans << endl;
}
accuracy: 1
time_ms: 30
memory_kb: 18964
final_rank: 11

code_snippet: #include <bits/stdc++.h>
using namespace std;

#include <algorithm>
#include <iostream>
#include <complex>
#include <cstdio>
#include <cmath>
#include <utility>
#include <vector>
using namespace std;
using W = double;
using P = complex<W>;
using L = pair<P,P>;
using C = pair<P,W>;
using Poly = vector<P>;
#define X real()
#define Y imag()
const W EPS = (1e-10), pi = acos(-1);

namespace std{
  bool operator < (const P& a, const P& b){
    return a.X != b.X ? a.X < b.X : a.Y < b.Y;
  }
  bool cmp_y(const P &a, const P &b){
    return a.Y != b.Y ? a.Y < b.Y : a.X < b.X;
  }
  bool operator == (const P& a, const P& b){
    return abs(a-b) < EPS;
  }
}

double dot(P a, P b){ return a.X * b.X + a.Y * b.Y;}
W cross(P a, P b){ return a.X * b.Y - a.Y * b.X;}
P projection(P a, P b){ return dot(a, b)/abs(b)/abs(b)*b;}
P projection(P a, L l){ return l.first + projection(a-l.first,l.second-l.first);}

//直線aと直線bの交点
P intersection(L a, L b){
  P af = a.first, as = a.second, bf = b.first, bs = b.second;
  return af + cross(bs-bf,af-bf)/(-cross(bs-bf,as-bf)+cross(bs-bf,af-bf))*(as-af);
}

//cがa/bと重なってる時は0を返す
//cがa/bと重なってる時+-2を返して欲しいなら+-2のところのEPSの符号を逆にする
int ccw(P a, P b, P c){
  b -= a; c -= a;
  if(cross(b,c) > EPS) return +1;
  if(cross(b,c) < -EPS) return -1;
  if(dot(b,c) < -EPS) return +2;
  if(norm(b) < norm(c)-EPS) return -2;
  return 0;
}

//端点が重なっててもtrueになる
//等号を無くせば端点が重なってる時はfalseにできる
bool is_cross(L a, L b){
  P af = a.first, as = a.second, bf = b.first, bs = b.second;
  return (ccw(af,as,bf)*ccw(af,as,bs) <= 0 && ccw(bf,bs,af)*ccw(bf,bs,as) <= 0);
}

// バグるケース？
W ps_dist(P a, L s){
  P sf = s.first, ss = s.second;
  if(dot(ss-sf,a-sf) >= 0 && dot(sf-ss,a-ss) >= 0)
    return abs(cross(sf-ss,a-ss))/abs(sf-ss);
  return min(abs(a-sf), abs(a-ss));
}

W pl_dist(P a, L s){
  P sf = s.first, ss = s.second;
  return abs(cross(sf-ss,a-ss))/abs(sf-ss);
}

W ss_dist(L a, L b){
  if(is_cross(a,b)) return 0;
  P af = a.first, as = a.second, bf = b.first, bs = b.second;
  return min({ps_dist(af,b),ps_dist(as,b),ps_dist(bf,a),ps_dist(bs,a)});
}

// 反時計回り想定、でないとマイナス？
// 非凸でも面積は求められる
W area(const Poly &p){
  int n = p.size();
  W s = 0;
  for(int i = 0; i < n; ++i) s += cross(p[i],p[(i+1)%n])/2;
  return s;
}

// 凸かどうかの判定
// 内角が180度未満か
bool is_convex(const Poly &p){
  int n = p.size();
  for(int i = 0; i < n; ++i)
    if(cross(p[(i+1)%n]-p[i],p[(i+2)%n]-p[(i+1)%n]) < 0) return false;
  return true;
}

// 点が多角形のどこにある？
int in_poly(P a, const Poly &p){
  int n = p.size(), c = 0;
  for(int i = 0; i < n; ++i){
    P s = p[i]-a, t = p[(i+1)%n]-a;
    if(!ccw(s,t,P(0,0))) return 1;//辺上
    if(s.Y > t.Y + EPS) swap(s,t);
    if((s.Y*t.Y < 0 || (s.Y*t.Y < EPS && t.Y > EPS)) && cross(s,t) < EPS) ++c;
  }
  if(c%2) return 2;//内部
  return 0;//外部
}

// 凸包
Poly convex_hull(Poly v){
  int n = v.size(), k = 0;
  sort(v.begin(), v.end(), cmp_y);
  Poly r(2*n);
  for(int i = 0; i < n; i++){
    while(k>1 && cross(r[k-1]-r[k-2],v[i]-r[k-2]) < -EPS) k--;
    r[k++] = v[i];
  }
  for(int i = n-2, t = k; i >= 0; i--){
    while(k>t && cross(r[k-1]-r[k-2],v[i]-r[k-2]) < -EPS) k--;
    r[k++] = v[i];
  }
  r.resize(k-1);
  return r;
}

//凸多角形の直径(距離最長の2点)を求める
W convex_diam(Poly p){
  int n = p.size(), i = 0, j = 0;
  if(n <= 1) return 0;
  if(n == 2) return abs(p[0]-p[1]);

  for(int k = 0; k < n; ++k){
    if(!(p[i] < p[k])) i = k;
    if(p[j] < p[k]) j = k;
  }
  
  W res = 0;
  int si = i, sj = j;
  while(i != sj || j != si){
    res = max(res, abs(p[i]-p[j]));
    if(cross(p[(i+1)%n]-p[i],p[(j+1)%n]-p[j]) < 0) i = (i+1)%n;
    else j = (j+1)%n;
  }
  return res;
}

//円と円の交点
vector<P> intersection(C a, C b){
  P ca = a.first, cb = b.first;
  W d = abs(ca-cb), ra = a.second, rb = b.second;
  W t = (ra*ra-rb*rb+d*d)/2/d, h = sqrt(ra*ra-t*t);
  P m = t/abs(cb-ca)*(cb-ca)+ca;
  vector<P> cp(2,m);
  P n = (ca-cb)*P(0,1);
  n *= h/abs(n);
  cp[0] -= n;
  cp[1] += n;
  return cp;
}

//点pから円cに伸ばした接線の接点を求める
//intersection(C,C)が必要
vector<P> tangent_to_C(P p, C c){
  C c2 = C((p+c.first)/2.0,abs(p-c.first)/2.0);
  return intersection(c,c2);
}

//円a,bの共通接線の円aの接点を求める
//tangent_to_Cが必要
//注意：同じ円を与えると壊れる
vector<P> common_tangent(C a, C b){
  vector<P> ret, cp;
  P af = a.first, bf = b.first;
  W ar = a.second, br = b.second;
  if(abs(ar-br) < EPS){
    P n = (bf-af)*P(0,1);
    n /= abs(n);
    ret.push_back(af+ar*n);
    ret.push_back(af-ar*n);
  }
  P i = (af*br+bf*ar)/(ar+br);
  if(abs(af-bf) > ar+br){//4本
    cp = tangent_to_C(i,a);
    for(int i = 0; i < 2; ++i) ret.push_back(cp[i]);
    if(abs(ar-br) > EPS){
      P e = (af*br-bf*ar)/(br-ar);
      cp = tangent_to_C(e,a);
      for(int i = 0; i < 2; ++i) ret.push_back(cp[i]);
    }
  }else if(abs(abs(af-bf)-(ar+br)) < EPS){//3本
    cp = tangent_to_C(i,a);
    ret.push_back(cp[0]);
    if(abs(ar-br) > EPS){
      P e = (af*br-bf*ar)/(br-ar);
      cp = tangent_to_C(e,a);
      for(int i = 0; i < 2; ++i) ret.push_back(cp[i]);
    }
  }else if(abs(af-bf) > abs(ar-br)){//2本
    if(abs(ar-br) > EPS){
      P e = (af*br-bf*ar)/(br-ar);
      cp = tangent_to_C(e,a);
      for(int i = 0; i < 2; ++i) ret.push_back(cp[i]);
    }
  }else if(abs(abs(af-bf) - abs(ar-br)) < EPS){//1本
    P e = (af*br-bf*ar)/(br-ar);
    cp = tangent_to_C(e,a);
    ret.push_back(cp[0]);
  }
  return ret;//0本
}

//円cと直線lの交点
 //接する場合は同一の点を二つ返す
//交点がないときこわれる
//pl_distが必要
vector<P> intersection(C c, L l){
  W d = pl_dist(c.first,l), r = c.second;
  P lf = l.first, ls = l.second;
  P m = lf + projection(c.first-lf,ls-lf);
  P x = sqrt(r*r-d*d)/abs(ls-lf)*(ls-lf);
  vector<P> cp(2,m);
  cp[0] -= x;
  cp[1] += x;
  return cp;
}

//三角形の三辺の長さa, b, cから面積を求める
W Heron(W a, W b, W c){
  W s = (a+b+c)/2;
  return sqrt(s*(s-a)*(s-b)*(s-c));
}

//点pと直線lに対して線対称な点
P line_symmetry(L l, P p){
  P lf = l.first, ls = l.second;
  return p + (lf - p + projection(p-lf,ls-lf))*2.0;
}

P line_symmetry(P p, L l){
  return line_symmetry(l,p);
}

// Projection を写したくない時はこっち
// P line_symmetry(L l, P p){
//   P f = l.first, s = l.second - f, q = p - f;
//   if(abs(q) < EPS) return p;
//   return f + norm(q/s)*s*s/q;
// }

// 2点から等距離の点の線
L vertical_bisector(P a, P b){
  P d = (a-b);
  P m = (a+b)/2.0;
  return L(m,m+d*P(0.0,1.0));
}

// 角ABCの2等分線
L angle_bisector(P a, P b, P c){
  P p = b + (a-b)/abs(a-b) + (c-b)/abs(c-b);
  return L(b,p);
}

//円と円の共通面積
//intersection(C,C)が必要
W common_area(C a, C b){
  if(a.second > b.second) swap(a,b);
  P ca = a.first, cb = b.first;
  W ra = a.second, rb = b.second;
  if(ra < EPS) return 0;
  if(norm(ca - cb) < norm(ra - rb) + EPS)
    return min(ra*ra, rb*rb)*pi;
  if(norm(ca - cb) > norm(ra + rb) + EPS)
    return 0;
  vector<P> cp = intersection(a,b);
  if(norm(cp[0] - cp[1]) < EPS) return 0;
  P aa = (cp[0]-ca)/(cp[1]-ca);
  P bb = (cp[0]-cb)/(cp[1]-cb);
  W theta_a = abs(atan2l(aa.Y,aa.X));
  W theta_b = abs(atan2l(bb.Y,bb.X));

  if(ccw(cp[0], cp[1], ca)*ccw(cp[0], cp[1], cb) >= 0){
    theta_a = max(2*pi - theta_a, theta_a);
    theta_b = min(2*pi - theta_b, theta_b);
  }else{
    theta_a = min(2*pi - theta_a, theta_a);
    theta_b = min(2*pi - theta_b, theta_b);
  }
  W sa = (theta_a-sinl(theta_a))*0.5, sb = (theta_b-sinl(theta_b))*0.5;
  W ans = ra*sa*ra + rb*sb*rb;
  return ans;
}

//凸多角形を直線で切る
//l.firstからl.secondを見て左側が残る
//ccwが必要
//intersectionが必要
Poly convex_cut(const Poly &p, L l){
  Poly ret;
  int n = p.size();
  for(int i = 0; i < n; ++i){
    P cur = p[i], nex = p[(i+1)%n], lf = l.first, ls = l.second;
    if(ccw(lf, ls, cur) != -1)
      ret.push_back(cur);
    if((ccw(lf, ls, cur) != -1) ^ (ccw(lf, ls, nex) != -1))
      ret.push_back(intersection(L(cur, nex), l));
  }
  return ret;
}

//円と非凸多角形の共通面積
//ps_dist, intersection(C,L), ccw, が必要
W common_area(C c, Poly p){
  W ret = 0, r = c.second;
  int n = p.size();
  for(int i = 0; i < n; ++i) p[i] -= c.first;//これの必要性がわからん
  for(int i = 0; i < n; ++i){
    P cur = p[i], nex = p[(i+1)%n];
    if(abs(cur*nex) < EPS) continue;
    W d = arg(nex/cur);
    ret += r*r*d/2.0;
    if(ps_dist(P(0,0),L(cur,nex)) < r - EPS){
      vector<P> cps = intersection(C(P(0,0),r),L(cur,nex));//ここが変わるだけ？
      P a, b;
      if(ccw(cur,nex,cps[0]) == 0 &&
         ccw(cur,nex,cps[1]) == 0)
        a = cps[0], b = cps[1];
      else if(!ccw(cur,nex,cps[0]))
        a = cps[0], b = nex;
      else if(!ccw(cur,nex,cps[1]))
        a = cur, b = cps[1];
      else
        a = cur, b = nex;
      if(abs(a*b) < EPS) continue;
      d = arg(b/a);
      ret += cross(a,b)*0.5 - r*r*d*0.5;
    }
  }
  return ret;
}

/*
  ピックの定理
  頂点が全て格子点にあるような単純な多角形の面積を S とし,
  多角形の内部にある格子点の数を i, 辺上の格子点の数を b とすると
  S = i + b/2 - 1
  が成り立つ。
*/

using PP = pair<double,int>;
#define INF 1e9

int main() {
  
  ios::sync_with_stdio(false);
  cin.tie(0);
  
  int n1,n2;
  cin >> n1 >> n2;
  vector<double> x1(n1),y1(n1);
  vector<double> x2(n2),y2(n2);
  for (int i=0;i<n1;i++) {
    cin >> x1[i] >> y1[i];
  }
  for (int i=0;i<n2;i++) {
    cin >> x2[i] >> y2[i];
  }
  double ans = INF;
  vector<double> dist(n1,INF);
  dist[0] = 0.0;
  priority_queue<PP,vector<PP>,greater<PP>> pq; 
  pq.push(PP(0.0,0));
  vector<vector<double>> c1(n1,vector<double>(n1,INF));
  for (int i=0;i<n1;i++) {
    c1[i][i] = 0.0;
  }
  P pb21 = complex(x2[0],y2[0]);
  P pb22 = complex(x2[1],y2[1]);
  L lb2 = make_pair(pb21,pb22);
  for (int i=0;i<n1;i++) {
    for (int j=i+1;j<n1;j++) {
      P p1 = complex(x1[i],y1[i]);
      P p2 = complex(x1[j],y1[j]);
      L l1 = make_pair(p1,p2);
      if (!is_cross(lb2,l1)) {
        c1[i][j] = abs(p2-p1);
        c1[j][i] = abs(p2-p1);
      }
    }
  }
  while (!pq.empty()) {
    PP np = pq.top();
    pq.pop();
    double nd = np.first;
    int now = np.second;
    if (dist[now]+EPS < nd) continue;
    for (int j=0;j<n1;j++) {
      double tdist = nd+c1[now][j];
      if (tdist+EPS < dist[j]) {
        dist[j] = tdist;
        pq.push(PP(dist[j],j));
      }
    }
  }
  ans = min(ans,abs(pb21-pb22)+dist[1]);
  vector<double> dist2(n2,INF);
  dist2[0] = 0.0;
  pq.push(PP(0.0,0));
  vector<vector<double>> c2(n2,vector<double>(n2,INF));
  for (int i=0;i<n2;i++) {
    c2[i][i] = 0.0;
  }
  pb21 = complex(x1[0],y1[0]);
  pb22 = complex(x1[1],y1[1]);
  lb2 = make_pair(pb21,pb22);
  for (int i=0;i<n2;i++) {
    for (int j=i+1;j<n2;j++) {
      P p1 = complex(x2[i],y2[i]);
      P p2 = complex(x2[j],y2[j]);
      L l1 = make_pair(p1,p2);
      if (!is_cross(lb2,l1)) {
        c2[i][j] = abs(p2-p1);
        c2[j][i] = abs(p2-p1);
      }
    }
  }
  while (!pq.empty()) {
    PP np = pq.top();
    pq.pop();
    double nd = np.first;
    int now = np.second;
    if (dist2[now]+EPS < nd) continue;
    for (int j=0;j<n2;j++) {
      double tdist = nd+c2[now][j];
      if (tdist+EPS < dist2[j]) {
        dist2[j] = tdist;
        pq.push(PP(dist2[j],j));
      }
    }
  }
  ans = min(ans,abs(pb21-pb22)+dist2[1]);
  if (ans > INF/2.0) cout << -1 << endl;
  else cout << fixed << setprecision(15) << ans << endl;
}
accuracy: 1
time_ms: 20
memory_kb: 18936
final_rank: 9