struct Pos{ // 点 or 向量,排序到底用atan2还是叉积还是斜率看数据范围,默认叉积
#define Vec Pos
double x,y;
Pos(){}
Pos(double a,double b):x(a),y(b){}
void Print(){ cerr<<fixed<<setprecision(2)<<x<<" "<<y<<"\n"; }
friend Vec operator + (const Vec &a,const Vec &b) { return Vec(a.x+b.x,a.y+b.y); }
friend Vec operator - (const Vec &a,const Vec &b) { return Vec(a.x-b.x,a.y-b.y); }
friend Vec operator * (const double &b,const Vec &a){ return Vec(a.x*b,a.y*b); }
friend double operator * (const Vec &a,const Vec &b){ return a.x*b.y-a.y*b.x; }
friend double operator ^ (const Vec &a,const Vec &b){ return a.x*b.x+a.y*b.y; }
friend double operator / (const Vec &a,const Vec &b){ return (b.y-a.y)/(b.x-a.x);}
friend double operator & (const Vec &a,const Vec &b){ return (b-a).Len(); }
double Len()const{ return sqrt(x*x+y*y); }
bool AboveX()const{
static int d;
d=dcmp(Vec(1,0)*(*this));
if(!d)return dcmp((*this)*Vec(0,1))>0;
return d>0;
}
friend bool operator < (const Vec &A,const Vec &B){
static bool ab1,ab2;int d;
ab1=A.AboveX(),ab2=B.AboveX();
if(ab1!=ab2)return ab1;
d=dcmp(A*B);
if(!d)return dcmp(B.Len()-A.Len())>0;
return d>0;
}
};
struct Line{ // 直线
Pos p;Vec e;
Line(){}
Line(Pos _p,Vec _e):p(_p),e(_e){}
bool operator<(const Line &rhs){ return e<rhs.e; }
friend Pos Itse(const Line &A,const Line &B){
double t=((B.p-A.p)*B.e)/(A.e*B.e);
return A.p+t*A.e;
}
friend bool OnRight(const Line &A,const Pos &B){ return dcmp(A.e*(B-A.p))<1; }
static Line MidLine(const Pos &A,const Pos &B){
Pos pm=0.5*(A+B);Vec pe=(pm-A);swap(pe.x,pe.y);pe.y=-pe.y;
if(dcmp((B-A)*pe)<1)pe=-1*pe;
return Line(pm,pe);
}
};
struct Convex{ // 动态凸包,静态的比较简单就鸽了
set<Pos>S;
set<Pos>::iterator Next(set<Pos>::iterator it){ return next(it)==S.end() ? S.begin() : next(it); }
set<Pos>::iterator Prev(set<Pos>::iterator it){ return it==S.begin() ? prev(S.end()) : prev(it); }
bool In(Pos A){
auto it = S.lower_bound(A);
if(it==S.end())it=S.begin();
int d=dcmp((A-*it)*(*Prev(it)-*it));
if(!d)return dcmp((*Prev(it)-*it).Len()-(A-*it).Len())>-1;
return d>0;
}
void Insert(Pos A){
if(In(A))return;
auto it = S.lower_bound(A);
if(it==S.end())it=S.begin();
S.insert(A);
while(S.size()>3 && dcmp((*Next(it)-A)*(*it-A))>-1){ it=Next(it);S.erase(Prev(it)); }
it=Prev(S.find(A));
while(S.size()>3 && dcmp((A-*it)*(*it-*Prev(it)))>-1){ it=Prev(it);S.erase(Next(it)); }
}
};
struct HalfPlane{ //半平面交
vector<Line>L;Line q[maxn];Pos P[maxn];int l,r;double S;
void Push(const Line &x){ L.push_back(x); }
double Area(){ S=0;for(int i=l;i<r;++i)S+=P[i]*P[i+1]; S+=P[r]*P[l]; S/=2;return S; }
bool Sol(){
sort(L.begin(),L.end());l=1,r=0;
q[++r]=L.front();
for(int i=1;i<L.size();++i){
while(l<r && OnRight(L[i],P[r]))--r;
while(l<r && OnRight(L[i],P[l+1]))++l;
q[++r]=L[i];
if(!dcmp(q[r].e*q[r-1].e)){
if(OnRight(q[r],q[r-1].p) && dcmp(q[r].e^q[r-1].e)<0)return false;
--r;
if(!OnRight(q[r],L[i].p))q[r]=L[i];
}
if(l<r)P[r]=Itse(q[r],q[r-1]);
}
while(l<r && OnRight(q[l],P[r]))--r;
if(r-l<=1)return false;
P[l]=Itse(q[l],q[r]);
return true;
}
};