#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef double db;
const db Pi = acos(-1);
const db inf = 1e15;
const db eps = 1e-11;
// 判断正、负还是0
inline int dcmp(db x){
if(fabs(x) < eps) return 0;
return x > 0 ? 1 : -1;
}
db Acos(db x){
if(x <= -1) return Pi;
if(x >= 1) return 0;
return acos(x);
}
db Asin(db x){
if(x >= 1) return Pi / 2;
if(x <= -1) return -Pi / 2;
return asin(x);
}
db Tan(db x){
if(dcmp(x - Pi / 2) == 0) return 4e18;
return tan(x);
}
typedef struct Point{
db x, y;
Point(db a = 0, db b = 0) { x = a, y = b; }
Point operator -(const Point &ret)const { return Point{x - ret.x, y - ret.y}; }
Point operator +(const Point &ret)const { return Point{x + ret.x, y + ret.y}; }
Point operator *(db mul)const { return Point{x * mul, y * mul}; }
Point operator /(db div)const { return Point{x / div, y / div}; }
//db operator *(const Point &ret) { return x * ret.x + y * ret.y; } // 点积
//db operator ^(const Point &ret) { return x * ret.y - y * ret.x; } // 叉积
db length() { return sqrt(x * x + y * y); }
}Vector;
struct Line{
Point p[2];
db k, b;
Line(db a = 0, db b = 0, db c = 0, db d = 0) { p[0].x = a, p[0].y = b, p[1].x = c, p[1].y = d; }
Line(Point a, Point b) { p[0] = a, p[1] = b; }
db length(){
return sqrt((p[0].x - p[1].x) * (p[0].x - p[1].x) + (p[0].y - p[1].y) * (p[0].y - p[1].y));
}
// 获取直线k,b参数
void get_para(){
if(dcmp(p[0].x - p[1].x) == 0){
k = inf;
b = inf;
}
else{
k = (p[1].y - p[0].y) / (p[1].x - p[0].x);
b = p[0].y - k * p[0].x;
}
}
// 点到直线距离
db dis_Point(Point ret){
db x = ret.x, y = ret.y;
if(k == inf) return fabs(x - p[0].x);
return fabs(k * x - y + b) / sqrt(1 + k * k);
}
};
// 点积
db dot(Vector a, Vector b) { return a.x * b.x + a.y * b.y; }
// 叉积
db cross(Vector a, Vector b) { return a.x * b.y - a.y * b.x; }
// 判断两直线是否相交,包含端点
bool intersection(const Line &l1, const Line &l2){
// 快速排斥实验
if(max(l1.p[0].x, l1.p[1].x) < min(l2.p[0].x, l2.p[1].x) || max(l2.p[0].x, l2.p[1].x) < min(l1.p[0].x, l1.p[1].x)) return false;
if(max(l1.p[0].y, l1.p[1].y) < min(l2.p[0].y, l2.p[1].y) || max(l2.p[0].y, l2.p[1].y) < min(l1.p[0].y, l1.p[1].y)) return false;
// 跨立实验
Vector L1 = {l1.p[1].x - l1.p[0].x, l1.p[1].y - l1.p[0].y}, L2 = {l2.p[1].x - l2.p[0].x, l2.p[1].y - l2.p[0].y};
Vector h = {l2.p[0].x - l1.p[0].x, l2.p[0].y - l1.p[0].y}, hh = {l2.p[1].x - l1.p[0].x, l2.p[1].y - l1.p[0].y};
if(dcmp(cross(L1, h) * cross(L1, hh)) > 0) return false;
h = {l1.p[0].x - l2.p[0].x, l1.p[0].y - l2.p[0].y}, hh = {l1.p[1].x - l2.p[0].x, l1.p[1].y - l2.p[0].y};
if(dcmp(cross(L2, h) * cross(L2, hh)) > 0) return false;
return true;
}
// 逆时针旋转,顺时针的话角度取反即可
Point rorate_point(const Point &p, db A){
return Point{p.x * cos(A) - p.y * sin(A), p.x * sin(A) + p.y * cos(A)};
}
// 找直线交点
bool inter_point(const Line &l1, const Line &l2, Point &ans){
Point a = l1.p[0], b = l2.p[0];
if(l1.k == l2.k) return 0;
if(l1.k == inf) ans = {a.x, l2.k * a.x + l2.b};
else if(l2.k == inf) ans = {b.x, l1.k * b.x + l1.b};
else{
ans.x = (l1.b - l2.b) / (l2.k - l1.k);
ans.y = l1.k * ans.x + l1.b;
}
return 1;
}
// 两点距离
db point_dis(const Point &a, const Point &b){
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
// 极角排序 p0是基准点
Point p0;
bool cmp_jijiao(Point p1, Point p2){
Vector a = p1 - p0, b = p2 - p0;
return dcmp(cross(a, b)) > 0;
}
// 凸包,返回凸包周长,n是点的个数
db Graham(int n){
// goal是构成凸包的点,n是点的个数, 基准点是1
Point p[100], goal[100];
int cnt = 1;
for(int i = 2; i <= n; ++i){
if(p[i].y < p[1].y) swap(p[1], p[i]);
}
sort(p + 2, p + 1 + n, cmp_jijiao);
goal[1] = p[1];
for(int i = 2; i <= n; ++i){
while(cnt > 1 && dcmp(cross(goal[cnt] - goal[cnt - 1], p[i] - goal[cnt])) < 0) --cnt;
goal[++cnt] = p[i];
}
goal[++cnt] = p[1];
db len = 0;
for(int i = 2; i <= cnt; ++i)
len += point_dis(goal[i], goal[i - 1]);
return len;
}
// 任意多边形面积,顶点按照顺时针或逆时针排序,n是顶点数
db GetPolygonArea(int n){
Point p[100];
if(n < 3) return 0;
db ans = 0;
for(int i = 2; i < n; ++i) ans += cross(p[i] - p[1], p[i + 1] - p[1]);
return fabs(ans / 2);
}