#include #include #include #include #include #include #include #include #include #include #include #include #include #define debug_value(x) cerr << "line" << __LINE__ << ":<" << __func__ << ">:" << #x << "=" << x << endl; #define debug(x) cerr << "line" << __LINE__ << ":<" << __func__ << ">:" << x << endl; template inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; } template inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; } using namespace std; typedef long long ll; template vector> vec2d(int n, int m, T v){ return vector>(n, vector(m, v)); } template vector>> vec3d(int n, int m, int k, T v){ return vector>>(n, vector>(m, vector(k, v))); } template void print_vector(vector v, char delimiter=' '){ if(v.empty()) { cout << endl; return; } for(int i = 0; i+1 < v.size(); i++) cout << v[i] << delimiter; cout << v.back() << endl; } template struct line { line(T a, T b, T c): a(a), b(b), c(c){}; T a, b, c; }; template ostream& operator<<(ostream& os, const line& l){ os << l.a << "*x + " << l.b << "*y+ " << l.c; return os; } template inline T add(T a, T b){ return a+b; } const double eps = 1e-10; inline double add(double a, double b){ if(abs(a+b) < eps*(abs(a)+abs(b))) return 0.0; return a+b; } template class point { public: point(T x, T y): x(x), y(y){}; point(): x(0), y(0){}; T x, y; point operator + (point p){ return point(add(x, p.x), add(y, p.y)); }; point operator - (point p){ return point(add(x, -p.x), add(y, -p.y)); }; point operator * (T d){ return point(x*d, y*d); }; T dot(point p){ return add(x*p.x, y*p.y); }; T det(point p){ return add(x*p.y, -y*p.x); }; }; /** * 直線lとp1, p2を結ぶ直線を求めます */ template line from_points(point p1, point p2){ return line(p2.y-p1.y, p1.x-p2.x, p1.y*p2.x-p1.x*p2.y); } /** * l: ax+by+c = 0としたときにax+by+cの値を返します */ template T substitute(line l, point p){ return p.x*l.a+p.y*l.b+l.c; } /** * 直線lとp1, p2を結ぶ線分が交点を持つか否かを返します */ template bool intersect(line l, point p1, point p2){ return (substitute(l, p1) > 0) ^ (substitute(l, p2) > 0); } /** * p1, p2を結ぶ線分とq1, q2を結ぶ線分が交点を持つか否かを返します */ template bool intersect(point p1, point p2, point q1, point q2){ auto lp = from_points(p1, p2); auto lq = from_points(q1, q2); bool fq = (substitute(lq, p1) > 0) ^ (substitute(lq, p2) > 0); bool fp = (substitute(lp, q1) > 0) ^ (substitute(lp, q2) > 0); return fp&&fq; } template double dist(point p1, point p2){ T dx = p1.x-p2.x; T dy = p1.y-p2.y; return sqrt(dx*dx+dy*dy); } template T dist_sq(point p1, point p2){ T dx = p1.x-p2.x; T dy = p1.y-p2.y; return dx*dx+dy*dy; } /** * 線分p1p2の垂直二等分線を求めます */ line vertical_bisector(point p1, point p2){ double a = 2.0*(p2.x-p1.x); double b = 2.0*(p2.y-p1.y); double c = p2.x*p2.x-p1.x*p1.x+p2.y*p2.y-p1.y*p1.y; return line(a, b, -c); } /** * 直線l1と直線l2がただ一つの交点を持つかを返します */ bool intersect(line l1, line l2){ if(abs(l1.a*l2.b-l2.a*l1.b) < eps) return false; return true; } /** * 直線l1と直線l2の交点を求めます * 戻り値をoptionalに書き換えるほうが良さそう */ point intersection(line l1, line l2){ assert(intersect(l1, l2)); double x = l1.b*l2.c-l2.b*l1.c; double y = l2.a*l1.c-l1.a*l2.c; double d = l1.a*l2.b-l2.a*l1.b; return point(x/d, y/d); } point rot(double theta, point p){ double x = p.x; double y = p.y; double c = cos(theta); double s = sin(theta); return point(c*x-s*y, c*y+s*x); } const double INF = 1e+15; vector> warshallfloyd(vector> g){ int n = g.size(); vector> dist(n, vector(n)); for(int i = 0; i < n; i++){ for(int j = 0; j < n; j++){ dist[i][j] = g[i][j]; } dist[i][i] = 0; } for(int i = 0; i < n; i++){ for(int j = 0; j < n; j++){ for(int k = 0; k < n; k++){ double new_len = dist[j][i] + dist[i][k]; dist[j][k] = min(new_len, dist[j][k]); } } } return dist; } using Po = point; int main(){ ios::sync_with_stdio(false); cin.tie(0); cout << setprecision(10) << fixed; int n, m; cin >> n >> m; vector> points; for(int i = 0; i < n; i++){ points.push_back({}); for(int j = 0; j < 2; j++){ int x, y; cin >> x >> y; points.back().push_back(Po(x, y)); } } auto to_idx = [&](int i, int j){ return i*2+j; }; auto g = vec2d(n*2, n*2, INF); for(int i = 0; i < n; i++){ for(int j = 0; j < 2; j++){ for(int k = 0; k < n; k++){ for(int l = 0; l < 2; l++){ if(i == k) continue; bool ok = true; for(int p = 0; p < n; p++){ if(p == i || p == k) continue; if(intersect(points[i][j], points[k][l], points[p][0], points[p][1])) ok = false; } if(ok){ int idx0 = to_idx(i, j); int idx1 = to_idx(k, l); g[idx0][idx1] = dist(points[i][j], points[k][l]); // cout << i << ' ' << j << "->" << k << ' ' << l << ':' << g[idx0][idx1] << endl; } } } } } auto dist = warshallfloyd(g); for(int i = 0; i < m; i++){ int a, b, c, d; cin >> a >> b >> c >> d; a--; b--; c--; d--; int i0 = to_idx(a, b); int i1 = to_idx(c, d); cout << dist[i0][i1] << endl; } }