计算几何板子

#define i128 long long
inline i128 ABS(i128 x){return x<0?-x:x;}
struct frac{
	i128 x,y;
	frac(){}
	frac(i128 xx,i128 yy=1ll):x(xx),y(yy){
		if(y<0)x=-x,y=-y;
	}
	friend frac operator +(frac a,frac b){return frac(a.x*b.y+a.y*b.x,a.y*b.y);}
	friend frac operator -(frac a,frac b){return frac(a.x*b.y-a.y*b.x,a.y*b.y);}
	friend frac operator *(frac a,frac b){return frac(a.x*b.x,a.y*b.y);}
	friend frac operator /(frac a,frac b){return a*frac(b.y,b.x);}
	friend bool operator <(frac a,frac b){return a.x*b.y<b.x*a.y;}
	friend bool operator >(frac a,frac b){return a.x*b.y>b.x*a.y;}
	friend bool operator <=(frac a,frac b){return !(a>b);}
	friend bool operator >=(frac a,frac b){return !(a<b);}
	friend bool operator ==(frac a,frac b){return a.x*b.y==b.x*a.y;}
	friend bool operator !=(frac a,frac b){return !(a==b);}
	frac operator - () {return frac(0)-x;}
};

int

typedef double db;
const db eps=1e-8,pi=3.14159265358979323846;
int sgn(int x){return x<0?-1:x>0;}
int cmp(int a,int b){return sgn(a-b);}

struct P{
	int x,y;
	P(int x=0,int y=0):x(x),y(y){}
	P&operator +=(P o){return x+=o.x,y+=o.y,*this;}
	P&operator -=(P o){return x-=o.x,y-=o.y,*this;}
	P&operator *=(int o){return x*=o,y*=o,*this;}
	P&operator /=(int o){return x/=o,y/=o,*this;}
	friend P operator +(P a,P b){return a+=b;}
	friend P operator -(P a,P b){return a-=b;}
	friend P operator *(P a,int b){return a*=b;}
	friend P operator /(P a,int b){return a/=b;}
	friend bool operator <(P a,P b){return fabs(a.x-b.x)<eps?a.y<b.y:a.x<b.x;}
	friend bool operator ==(P a,P b){return cmp(a.x,b.x)==0 && cmp(a.y,b.y)==0;}
	friend bool operator !=(P a,P b){return !(a==b);}
	friend int operator %(P a,P b){return a.x*b.x+a.y*b.y;} // dot
	friend int operator *(P a,P b){return a.x*b.y-a.y*b.x;} // cross
	
	P rot90(){return P(-y,x);}
	db ang(){return atan2(y,x);}
	db len(){return sqrt(x*x+y*y);}
	int len2(){return x*x+y*y;}
	
	int half(){return sgn(y)==1||(sgn(y)==0&&sgn(x)>=0);}
//	P unit(){return ((*this))/len();}
	
	void read(){cin>>x>>y;}
	void out(){cout<<"("<<x<<","<<y<<")"<<endl;}
};
bool cmp_dir(P a,P b){
	if(a.half()!=b.half())return a.half()<b.half();
	return sgn(a*b)>0;
}

db dis(P a,P b){return (a-b).len();}
int cross(P a,P b,P c){
	// (a->b)*(a->c)
	return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}
int cmp3(P a,P b,P c){
	return sgn(cross(a,b,c));
}

double

typedef double db;
const db eps=1e-8,pi=3.14159265358979323846;
int sgn(db x){return x<-eps?-1:x>eps;}
int cmp(db a,db b){return sgn(a-b);}

struct P{
	db x,y;
	P(db x=0,db y=0):x(x),y(y){}
	P&operator +=(P o){return x+=o.x,y+=o.y,*this;}
	P&operator -=(P o){return x-=o.x,y-=o.y,*this;}
	P&operator *=(db o){return x*=o,y*=o,*this;}
	P&operator /=(db o){return x/=o,y/=o,*this;}
	friend P operator +(P a,P b){return a+=b;}
	friend P operator -(P a,P b){return a-=b;}
	friend P operator *(P a,db b){return a*=b;}
	friend P operator /(P a,db b){return a/=b;}
	friend bool operator <(P a,P b){return fabs(a.x-b.x)<eps?a.y<b.y:a.x<b.x;}
	friend bool operator ==(P a,P b){return cmp(a.x,b.x)==0 && cmp(a.y,b.y)==0;}
	friend bool operator !=(P a,P b){return !(a==b);}
	friend db operator %(P a,P b){return a.x*b.x+a.y*b.y;} // dot
	friend db operator *(P a,P b){return a.x*b.y-a.y*b.x;} // cross
	
	P rot(db o){
		db s=sin(o),c=cos(o);
		return P(x*c-y*s,x*s+y*c);
	}
	P rot90(){return P(-y,x);}
	db ang(){return atan2(y,x);}
	db len(){return sqrt(x*x+y*y);}
	db len2(){return x*x+y*y;}
	
	int half(){return sgn(y)==1||(sgn(y)==0&&sgn(x)>=0);}
	P unit(){return ((*this))/len();}
	
	void read(){cin>>x>>y;}
	void out(){cout<<"("<<x<<","<<y<<")"<<endl;}
};
bool cmp_dir(P a,P b){
	if(a.half()!=b.half())return a.half()<b.half();
	return sgn(a*b)>0;
}

db dis(P a,P b){return (a-b).len();}
db cross(P a,P b,P c){
	// (a->b)*(a->c)
	return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}
int cmp3(P a,P b,P c){
	return sgn(cross(a,b,c));
}

bool in_tri(P a,P b,P c,P p){
	if(cmp3(a,b,c)<0) swap(b,c);
	return cmp3(a,b,p)>=0 && cmp3(b,c,p)>=0 && cmp3(c,a,p)>=0;
}
db area_tri(P a,P b,P c){
	return fabs(cross(a,b,c))/2;
}

bool paral(P p1,P p2,P q1,P q2){
	// is parallel
	return sgn((p2-p1)*(q2-q1))==0;
}
P interl(P p1,P p2,P q1,P q2){
	// intersect point
	db s1=cross(q1,q2,p1),s2=-cross(q1,q2,p2);
	return (p1*s2+p2*s1)/(s1+s2);
}

bool inter(db l1,db r1,db l2,db r2){
	if(l1>r1)swap(l1,r1); if(l2>r2)swap(l2,r2);
	return !(cmp(r1,l2)==-1||cmp(r2,l1)==-1);
}
bool ismid(db a,db m,db b){
	return sgn(a-m)==0||sgn(b-m)==0||((a<m)!=(b<m));
}
bool ismid(P a,P m,P b){
	return ismid(a.x,m.x,b.x)&&ismid(a.y,m.y,b.y);
}

bool isseg(P p1,P p2,P q1,P q2){
	return inter(p1.x,p2.x,q1.x,q2.x) && inter(p1.y,p2.y,q1.y,q2.y) &&
	cmp3(p1,p2,q1)*cmp3(p1,p2,q2)<=0 && cmp3(q1,q2,p1)*cmp3(q1,q2,p2)<=0;
}
bool isseg_strict(P p1,P p2,P q1,P q2){
	return cmp3(p1,p2,q1)*cmp3(p1,p2,q2)<0 && cmp3(q1,q2,p1)*cmp3(q1,q2,p2)<0;
}

struct L{
	P a,b;
	L(P aa=P(0,0),P bb=P(0,0)){a=aa,b=bb;}
	bool in(P p){return sgn((b-a)*(p-a))>0;}
	int in_sgn(P p){return sgn((b-a)*(p-a));}
	P dir(){return b-a;}
	bool onl(P p){
		return cmp3(a,b,p)==0;
	}
	bool onseg(P p){
		return onl(p)&&ismid(a,p,b);
	}
	bool onseg_strict(P p){
		return onl(p)&&sgn((p-a)%(a-b))*sgn((p-b)%(a-b))<0;
	}
	void out(){cout<<"("<<a.x<<","<<a.y<<")---("<<b.x<<","<<b.y<<")\n";}
};

bool isseg(L a,L b){
	return isseg(a.a,a.b,b.a,b.b);
}
bool paral(L a,L b){
	// is parallel
	return paral(a.a,a.b,b.a,b.b);
}
P operator &(L a,L b){
	return interl(a.a,a.b,b.a,b.b);
}
bool samedir(L a,L b){
	return paral(a,b) && sgn(a.dir()%b.dir())==1;
}
bool operator <(L a,L b){
	if(samedir(a,b)) return b.in(a.a);
	return cmp_dir(a.dir(),b.dir());
}

P proj(L a,P b){
	P d=a.dir();
	return a.a+d*((d%(b-a.a))/d.len2());
}
P reflect(L a,P b){
	return proj(a,b)*2-b;
}
db dis(L a,P b){
	db s=abs((b-a.a)*(b-a.b));
	return s/dis(a.a,a.b);
}
db dis_seg(L a,P b){
	if(a.a==a.b) return	dis(a.a,b);
	P h=proj(a,b);
	if(ismid(a.a,h,a.b)) return dis(h,b);
	return min(dis(a.a,b),dis(a.b,b));
}
db dis_ss(L a,L b){
	if(isseg(a,b)) return 0;
	return min(min(dis_seg(a,b.a),dis_seg(a,b.b)),min(dis_seg(b,a.a),dis_seg(b,a.b)));
}

db rad(P a,P b){
	return atan2l(a*b,a%b);
}

// polygon
db area(vector<P>a){
	db res=0;
	For(i,0,(int)a.size()-1)res+=a[i]*a[(i+1)%a.size()];
	return res/2;
}
int contain(vector<P>a,P p){
	int n=a.size(),res=0;
	For(i,0,n-1){
		P u=a[i],v=a[(i+1)%n];
		if(L(u,v).onseg(p))return 1;
		if(cmp(u.y,v.y)<=0)swap(u,v);
		if(cmp(p.y,u.y)>0 || cmp(p.y,v.y)<=0)continue;
		res^=cmp3(p,u,v)>0;
	}
	return res*2;
}
vector<P>cut(vector<P>&a,P q1,P q2){
	vector<P>b; int n=a.size();
	For(i,0,n-1){
		P p1=a[i],p2=a[(i+1)%n];
		int d1=cmp3(q1,q2,p1),d2=cmp3(q1,q2,p2);
		if(d1>=0)b.pb(p1);
		if(d1*d2<0)b.pb(interl(p1,p2,q1,q2));
	}
	return b;
}
vector<P>cut(vector<P>&a,L l){
	return cut(a,l.a,l.b);
}

vector<P>convex(vector<P>a){
	int n=a.size(),m=0; if(n<=1)return a;
	sort(a.begin(),a.end());
	vector<P>st(n*2); int tp=0;
	For(i,0,n-1){
		while(tp>1 && cmp3(st[tp-2],st[tp-1],a[i])<=0)--tp;
		st[tp++]=a[i];
	}
	int t=tp;
	Rep(i,n-2,0){
		while(tp>t && cmp3(st[tp-2],st[tp-1],a[i])<=0)--tp;
		st[tp++]=a[i];
	}
	st.resize(tp-1);
	return st;
}
// <=0 to <0: non-strict (need to unique points)

bool check(L a,L b,L c){
	return c.in(a&b);
}
int checksgn(L a,L b,L c){
	return c.in_sgn(a&b);
}
vector<P>hpis(vector<L>&l){
	sort(l.begin(),l.end());
	deque<L>q;
	For(i,0,(int)l.size()-1){
		if(i&&samedir(l[i],l[i-1]))continue;
		while(q.size()>1 && !check(q[q.size()-2],q[q.size()-1],l[i]))q.pop_back();
		while(q.size()>1 && !check(q[1],q[0],l[i]))q.pop_front();
		q.pb(l[i]);
	}
	while(q.size()>2 && !check(q[q.size()-2],q[q.size()-1],q[0]))q.pop_back();
	while(q.size()>2 && !check(q[1],q[0],q[q.size()-1]))q.pop_front();
	vector<P>res;
	For(i,0,(int)q.size()-1) res.pb(q[i]&q[(i+1)%q.size()]);
	return res;
}

mt19937_64 rnd(64);

vector<L>cut(vector<L>&a,L l){
	vector<L>b; int n=a.size();
	For(i,0,n-1){
		L a1=a[i],a2=a[(i+1)%n],a3=a[(i+2)%n];
		int d1=checksgn(a1,a2,l),d2=checksgn(a2,a3,l);
		if(d1>0 || d2>0 || (d1==0&&d2==0)) b.pb(a2);
		if(d1>=0 && d2<0) b.pb(l);
	}
	return b;
}

L bisec(P a,P b){
	// contain a
	P o=(a+b)*0.5;
	return L(o,o+((b-a).rot90()));
}
vector<vector<L>> voronoi(vector<P>a){
	int n=a.size();
	vector<P>b=a;
	shuffle(b.begin(),b.end(),rnd);
	const db U=1e5;
	vector<vector<L>> res(n,{
		L(P(-U,-U),P(U,-U)),
		L(P(U,-U),P(U,U)),
		L(P(U,U),P(-U,U)),
		L(P(-U,U),P(-U,-U))
	});
	For(i,0,n-1){
		for(auto x:b){
			if(dis(x,a[i])>eps) res[i]=cut(res[i],bisec(a[i],x));
		}
	}
	return res;
}
vector<vector<L>> neg_voronoi(vector<P>a){
	int n=a.size();
	vector<P>b=a;
	shuffle(b.begin(),b.end(),rnd);
	const db U=1e5;
	vector<vector<L>> res(n,{
		L(P(-U,-U),P(U,-U)),
		L(P(U,-U),P(U,U)),
		L(P(U,U),P(-U,U)),
		L(P(-U,U),P(-U,-U))
	});
	For(i,0,n-1){
		for(auto x:b){
			if(dis(x,a[i])>eps){
				L tmp=bisector(x,a[i]); tmp.id=x.id;
				res[i]=cut(res[i],tmp);
			}
			if(res[i].empty()) break;
		}
	}
	return res;
}

diam

db diam(vector<P>a){
	int n=a.size();
	if(n<=1)return 0;
	int ii=0,jj=0;
	For(k,1,n-1){
		if(a[k]<a[ii])ii=k;
		if(a[jj]<a[k])jj=k;
	}
	int i=ii,j=jj;
	db res=dis(a[i],a[j]);
	do{
		if((a[(i+1)%n]-a[i])*(a[(j+1)%n]-a[j])>=0) (++j)%=n;
		else (++i)%=n;
		res=max(res,dis(a[i],a[j]));
	}while(i!=ii||j!=jj);
	return res;
}

simple_polygon

bool inangle(P a,P b,P c){
	if(sgn(a*b)>0) return sgn(a*c)>=0 && sgn(c*b)>=0;
	return !(sgn(b*c)>0 && sgn(c*a)>0);
}
bool contain(P s,P t,vector<P>&p,bool half=0){
	if(s==t)return 1; int n=p.size();
	vi cnt(2);
	For(i,0,n-1){
		P a=p[i],b=p[(i+1)%n];
		if(isseg_strict(s,t,a,b)) return 0;
		if(L(s,t).onseg(a)){
			P c=::a[(i+n-1)%n];
			if(s!=a && !inangle(s-a,b-a,c-a)) return 0;
			if(t!=a && !inangle(t-a,b-a,c-a)) return 0;
			if(half && s!=a && t!=a){
				int d=sgn((c-a)*(t-s));
				if(d) cnt[d>0]++;
				d=sgn((b-a)*(t-s));
				if(d) cnt[d>0]++;
				if(cnt[1] && cnt[0]) return 0;
			}
		}else{
			if(s!=a && s!=b && L(a,b).onseg(s) && sgn((t-s)*(b-a))>0) return 0;
			if(t!=a && t!=b && L(a,b).onseg(t) && sgn((s-t)*(b-a))>0) return 0;
		}
	}
	return 1;
}

convex_polygon

db gmax(vector<P>&a,P d){
    int n=a.size();
    db mx=0;
    if(a[0]%d>a[n-1]%d){
        int l=0,r=n-1;
        while(l+1<r){
            int mid=l+r>>1;
            if(a[mid]%d>a[l]%d && a[mid]%d>a[mid-1]%d) l=mid;
            else r=mid-1;
        }return a[l]%d;
    }else{
        int l=0,r=n-1;
        while(l+1<r){
            int mid=l+r>>1;
            if(a[mid]%d>a[r]%d && a[mid]%d>a[mid+1]%d) r=mid;
            else l=mid;
        }return a[r]%d;
    }
    return mx;
}
int getid(vector<P>&a,P b){
	int n=a.size(),l=1,r=n-1,res=0;
	while(l<=r){
		int mid=l+r>>1;
		if(cmp3(a[0],a[mid],b)>=0) l=mid+1,res=mid;
		else r=mid-1;
	}
	return res;
}
bool inconvex(vector<P>&a,P b){
	int i=getid(a,b);
	if(i==0)++i;
	if(i+1==a.size())--i;
	return in_tri(a[0],a[i],a[i+1],b);
}

int p0;
int bound(vector<P>&a,P b,int l,int r,int op){
	// 111000
	int n=a.size();
	while(l<r){
		int mid=l+r>>1;
		if(cmp3(a[mid],a[(mid+1)%n],b)==op) l=mid+1;
		else r=mid;
	}
	return l;
}

vector<P> tanline(vector<P>&a,P b){
	int n=a.size();
	if(b.x<a[0].x){
		int t1=bound(a,b,0,p0-1,-1);
		int t2=bound(a,b,p0,n-1,1);
		return {a[t1],a[t2]};
	}
	int id=getid(a,b);
	int t1=bound(a,b,id+1,n-1,-1);
	int t2=bound(a,b,0,id,1);
	return {a[t1],a[t2]};
}

circles

// circles
struct cir{
	P o; db r;
	cir(P oo=P(0,0),db rr=0){o=oo,r=rr;}
	bool in(P x){return sgn(dis(x,o)-r)<=0;}
	bool in_strict(P x){return sgn(dis(x,o)-r)<0;}
};
int type(cir a,cir b){
	db d=dis(a.o,b.o);
	if(cmp(d,a.r+b.r)==1)return 4;
	if(cmp(d,a.r+b.r)==0)return 3;
	if(cmp(d,fabs(a.r-b.r))==1)return 2;
	if(cmp(d,fabs(a.r-b.r))==0)return 1;
	return 0;
}

P bary(P a,P b,P c,db aa,db bb,db cc){
	return (a*aa+b*bb+c*cc)/(aa+bb+cc);
}
P centroid(P a,P b,P c){
	return bary(a,b,c,1,1,1);
}
P incenter(P a,P b,P c){
	return bary(a,b,c,(b-c).len(),(c-a).len(),(a-b).len());
}
P excenter(P a,P b,P c){
	db A=(b-c).len(),B=(c-a).len(),C=(a-b).len();
	return bary(a,b,c,-A,B,C);
	//return bary(a,b,c,A,-B,C);
	//return bary(a,b,c,A,B,-C);
}
P circumcenter(P a,P b,P c){
	P bb=b-a,cc=c-a;
	db B=bb.len2(),C=cc.len2(),d=2*(bb*cc);
	return a-P(bb.y*C-cc.y*B,cc.x*B-bb.x*C)/d;
}
P othrocenter(P a,P b,P c){
	db A=(b-c).len2(),B=(c-a).len2(),C=(a-b).len2();
	return bary(a,b,c,(A+B-C)*(C+A-B),(B+C-A)*(A+B-C),(C+A-B)*(B+C-A));
}

cir incircle(P a,P b,P c){
	db A=(b-c).len(),B=(c-a).len(),C=(a-b).len();
	return cir(bary(a,b,c,A,B,C),fabs((b-a)*(c-a))/(A+B+C));
}
cir circumcircle(P a,P b,P c){
	P o=circumcenter(a,b,c);
	return cir(o,(a-o).len());
}
cir circ(P a,P b){
	return cir((a+b)/2,(a-b).len()/2);
}
cir mincircle(vector<P>a){
	shuffle(a.begin(),a.end(),rnd);
	cir c=cir(a[0],0);
	int n=a.size();
	For(i,1,n-1){
		if(c.in(a[i]))continue;
		c=circ(a[0],a[i]);
		For(j,1,i-1){
			if(c.in(a[j]))continue;
			c=circ(a[i],a[j]);
			For(k,0,j-1){
				if(c.in(a[k]))continue;
				c=circumcircle(a[i],a[j],a[k]);
			}
		}
	}
	return c;
}

// cir&line
vector<P> operator &(cir a,L b){
	if(cmp(abs(((a.o-b.a)*(b.b-b.a))/dis(b.a,b.b)),a.r)>0) return {};
	db x=(b.a-a.o)%(b.b-b.a);
	db y=(b.b-b.a).len2();
	db d=x*x-y*((b.a-a.o).len2()-a.r*a.r);
	d=max(d,(db)0.0);
	P m=b.a-(b.b-b.a)*(x/y);
	P dr=(b.b-b.a)*(sqrt(d)/y);
	return {m-dr,m+dr}; //along dir: p1->p2
}
// cir&cir
vector<P> operator &(cir a,cir b){ //need to check whether two circles are the same
	db d=dis(a.o,b.o);
	if(cmp(d,a.r+b.r)==1 || cmp(d,abs(a.r-b.r))==-1)return {};
	d=min(d,a.r+b.r);
	db y=(a.r*a.r+d*d-b.r*b.r)/(d*2),x=sqrt(a.r*a.r-y*y);
	P dir=(b.o-a.o).unit();
	P q1=(a.o+dir*y),q2=((dir.rot90())*x);
	return {q1-q2,q1+q2};
}
vector<P> tanCP(cir a,P p){
	db x=(p-a.o).len2(),d=x-a.r*a.r;
	if(sgn(d)<=0) return {}; // on circle => no tangent
	P q1=a.o+(p-a.o)*(a.r*a.r/x);
	P q2=(p-a.o).rot90()*(a.r*sqrt(d)/x);
	return {q1-q2,q1+q2}; //counter clock-wise
}
// extanCC, intanCC : -r2, tanCP : r2 = 0
vector<L> tanCC(cir a,cir b){
	P d=b.o-a.o;
	db dr=a.r-b.r;
	db d2=d.len2(),h2=d2-dr*dr;
	if (sgn(d2)==0 || sgn(h2)<0) return {};
	if(h2<0) h2=0;
	vector<L>res;
	for(db si:{-1,1}){
		P v = (d*dr+d.rot90()*sqrt(h2)*si)/d2;
		res.pb(L(a.o+v*a.r,b.o+v*b.r));
	}
	if(sgn(h2)==0)res.pop_back();
	return res;
}
vector<L> alltanCC(cir a,cir b){
	if(sgn(b.r)==0){
		vector<L>res;
		for(auto t:tanCP(a,b.o)) res.pb(L(b.o,t));
		return res;
	}
	auto res1=tanCC(a,b),res2=tanCC(a,cir(b.o,-b.r));
	for(auto t:res2)res1.pb(t);
	return res1;
}
db areaCT(db r,P p1,P p2){
	vector<P>is=(cir(P(0,0),r)&(L(p1,p2)));
	if(!is.size()) return r*r*rad(p1,p2)/2;
	bool b1=(cmp(p1.len2(),r*r)>0), b2=(cmp(p2.len2(),r*r)>0);
	if(b1&&b2){
		if(sgn((p1-is[0])%(p2-is[0]))<=0) 
			return (r*r*(rad(p1,is[0])+rad(is[1],p2))+(is[0]*is[1]))/2;
		return r*r*rad(p1,p2)/2;
	}
	if(b1) return (r*r*rad(p1,is[0])+is[0]*p2)/2;
	if(b2) return (p1*is[1]+r*r*rad(is[1],p2))/2;
	return (p1*p2)/2;
}
db areaCP(cir t,vector<P>p){
	db res=0;
	For(i,0,SZ(p)-1)res+=areaCT(t.r,p[i]-t.o,p[(i+1)%SZ(p)]-t.o);
	return res;
}
db areaCS(cir a,P p1,P p2){
	p1-=a.o,p2-=a.o;
	db d=p2.ang()-p1.ang();
	if(d<0)d+=pi*2;
	return (d*a.r*a.r-p1*p2)/2;
}
db areaCC(cir a,cir b){
	if(a.r<b.r)swap(a,b);
	int op=type(a,b);
	if(op<=1)return pi*b.r*b.r;
	if(op>=3)return 0;
	auto p=(a&b);
	return areaCS(a,p[0],p[1])+areaCS(b,p[1],p[0]);
}

L bisec(cir a,cir b){
	P d=(b.o-a.o)*2;
	db v=((b.o%b.o)-b.r*b.r)-((a.o%a.o)-a.r*a.r);
	P p1;
	if(fabs(d.x)>fabs(d.y))p1=P(v/d.x,0);
	else p1=P(0,v/d.y);
	return L(p1,p1+d.rot90());
}
vector<vector<L> > cir_voronoi(vector<cir>a){
	int n=a.size();
	vector<cir>b=a;
	shuffle(b.begin(),b.end(),rnd);
	const db U=3e6;
	vector<vector<L>> res(n,{
		L(P(-U,-U),P(U,-U)),
		L(P(U,-U),P(U,U)),
		L(P(U,U),P(-U,U)),
		L(P(-U,U),P(-U,-U))
	});
	For(i,0,n-1){
		for(auto x:b){
			if(dis(a[i].o,x.o)>eps) res[i]=cut(res[i],bisec(a[i],x));
		}
	}
	return res;
}

signed main()
{
	int n=read();
	vector<P>a(n);
	For(i,0,n-1)a[i].read();
//	sort(a.begin(),a.end());
//	a.erase(unique(a.begin(),a.end()),a.end());
//	a=convex(a);
	db res=diam(a);
	printf("%.12lf",res);
	return 0;
}
/*

*/
// 3D geometry
struct P3{
	db x,y,z;
	P3(db x=0,db y=0,db z=0):x(x),y(y),z(z){}
	P3&operator +=(P3 o){return x+=o.x,y+=o.y,z+=o.z,*this;}
	P3&operator -=(P3 o){return x-=o.x,y-=o.y,z-=o.z,*this;}
	P3&operator *=(db o){return x*=o,y*=o,z*=o,*this;}
	P3&operator /=(db o){return x/=o,y/=o,z/=o,*this;}
	friend P3 operator +(P3 a,P3 b){return a+=b;}
	friend P3 operator -(P3 a,P3 b){return a-=b;}
	friend P3 operator *(P3 a,db b){return a*=b;}
	friend P3 operator /(P3 a,db b){return a/=b;}
	friend bool operator <(P3 a,P3 b){
		if(sgn(a.x-b.x))return a.x<b.x;
		if(sgn(a.y-b.y))return a.y<b.y;
		return a.z<b.z;
	}
	friend bool operator ==(P3 a,P3 b){return cmp(a.x,b.x)==0 && cmp(a.y,b.y)==0 && cmp(a.z,b.z)==0;}
	
	friend db operator %(P3 a,P3 b){return a.x*b.x+a.y*b.y+a.z*b.z;}
	friend P3 operator *(P3 a,P3 b){return P3(a.y*b.z-a.z*b.y,a.z*b.x-a.x*b.z,a.x*b.y-a.y*b.x);}
	
	db len2(){return x*x+y*y+z*z;}
	db len(){return sqrt(len2());}
	P3 unit(){return (*this)/len();}
	
	void read(){cin>>x>>y>>z;}
	void out(){cout<<"("<<x<<","<<y<<","<<z<<")\n";}
};

db rnddb(){return 1.0*rnd()/ULLONG_MAX;}
P3 rndp3(db e){return P3(e*(rnddb()-0.5),e*(rnddb()-0.5),e*(rnddb()-0.5));}
void shake(P3&p,db t=eps*10){p+=rndp3(t);}

P3 perp(P3 a){
	return fabs(a.x)>fabs(a.z)?P3(a.y,-a.x,0):P3(0,-a.z,a.y);
}
db dis(P3 a,P3 b){return (a-b).len();}
P3 cross(P3 a,P3 b,P3 c){
	return (b-a)*(c-a);
}
db volume(P3 a,P3 b,P3 c,P3 d){
	return ((b-a)*(c-a))%(d-a);
}
int above(P3 a,P3 b,P3 c,P3 d){
	return sgn(volume(a,b,c,d));
}

struct plane{
	P3 a[3];
	plane(P3 x,P3 y,P3 z){a[0]=x,a[1]=y,a[2]=z;}
	P3 &operator [](int x){return a[x];}
	P3 norm(){
		return (a[1]-a[0])*(a[2]-a[0]);
	}
	bool above(P3 p){
		return sgn(volume(a[0],a[1],a[2],p))>0;
	}
};

db disLP(P3 p1,P3 p2,P3 q){
	return ((p2-p1)*(q-p1)).len()/(p2-p1).len();
}
db disLL(P3 p1,P3 p2,P3 q1,P3 q2){
	P3 o=(p2-p1)*(q2-q1);
	if(o.len()<=eps)return disLP(p1,p2,q1);
	return fabs(o.unit()%(p1-p2));
}

vector<plane>convex3d(vector<P3>p){
	auto pp=p;
//	for(auto&x:p) shake(x);
	int n=p.size();
	For(i,0,n-1) if(p[i]<p[0]) swap(p[0],p[i]),swap(pp[0],pp[i]);
	For(i,2,n-1) if((p[i].x-p[0].x)*(p[1].y-p[0].y)>(p[i].y-p[0].y)*(p[1].x-p[0].x)) swap(p[1],p[i]),swap(pp[1],pp[i]);
	vector<plane>res;
	set<pii>eg;
	function<void(int,int)> wrap=[&](int a,int b){
		if(eg.count(mkp(a,b)))return;
		int c=-1;
		For(i,0,n-1) if(i!=a && i!=b) 
			if(c==-1 || volume(p[c],p[a],p[b],p[i])>0) c=i;
		if(c==-1) return;
		res.pb(plane(pp[a],pp[b],pp[c]));
		eg.insert(mkp(a,b)),eg.insert(mkp(b,c)),eg.insert(mkp(c,a));
		wrap(c,b),wrap(a,c);
	};
	wrap(0,1);
	return res;
}










下面是旧的板子

struct P{
	int x,y;
	P(int x=0,int y=0):x(x),y(y){}
	P&operator +=(P o){return x+=o.x,y+=o.y,*this;}
	P&operator -=(P o){return x-=o.x,y-=o.y,*this;}
	P&operator *=(int o){return x*=o,y*=o,*this;}
	P&operator /=(int o){return x/=o,y/=o,*this;}
	friend P operator +(P a,P b){return a+=b;}
	friend P operator -(P a,P b){return a-=b;}
	friend P operator *(P a,int b){return a*=b;}
	friend P operator /(P a,int b){return a/=b;}
	friend bool operator <(P a,P b){return a.x==b.x?a.y<b.y:a.x<b.x;}
	friend int operator *(P a,P b){return a.x*b.x+a.y*b.y;} // dot
	friend int operator %(P a,P b){return a.x*b.y-a.y*b.x;} // cross
	inline double ang(){return atan2(y,x);}
	inline double l(){return sqrt((*this)*(*this));}
};
const double eps=1e-10,pi=3.14159265358979323846;
struct P{
	double x,y;
	P(double x=0,double y=0):x(x),y(y){}
	P&operator +=(P o){return x+=o.x,y+=o.y,*this;}
	P&operator -=(P o){return x-=o.x,y-=o.y,*this;}
	P&operator *=(double o){return x*=o,y*=o,*this;}
	P&operator /=(double o){return x/=o,y/=o,*this;}
	friend P operator +(P a,P b){return a+=b;}
	friend P operator -(P a,P b){return a-=b;}
	friend P operator *(P a,double b){return a*=b;}
	friend P operator /(P a,double b){return a/=b;}
	friend bool operator <(P a,P b){return fabs(a.x-b.x)<eps?a.y<b.y:a.x<b.x;}
	friend double operator *(P a,P b){return a.x*b.x+a.y*b.y;} // dot
	friend double operator %(P a,P b){return a.x*b.y-a.y*b.x;} // cross
	inline void spin(double o){double s=sin(o),c=cos(o),xx=x*c-y*s,yy=x*s-y*c;x=xx,y=yy;}
	inline double ang(){return atan2(y,x);}
	inline double l(){return sqrt((*this)*(*this));}
	void in(){cin>>x>>y;}
};
inline double d(P a,P b){return (a-b).l();}
struct line{
	P a,b;double c;
	line(){}
	line(P a,P b):a(a),b(b){c=b.ang();}
	friend P operator * (line a,line b){return a.a+a.b*(b.b%(a.a-b.a)/(a.b%b.b));}
	friend bool operator <(line a,line b){return fabs(a.c-b.c)<eps?(b.a-a.a)%a.b<0:a.c<b.c;}
};
P dir(line a){
	return a.b/(a.b.l());
}

double dis(line a,P b){
	return (((b-a.a)%a.b)/(a.b.l()));
}

struct cir{
	P o; double r;
	bool operator <(const cir&b)const{return r<b.r;}
};
vector<P>convex(vector<P>o){
	sort(o.begin(),o.end());
	int n=o.size();
	vector<P>p;
	For(i,0,n-1){
		while(p.size()>1&&(p.back()-p[p.size()-2])%(o[i]-p[p.size()-2])<eps) p.pop_back();
		p.pb(o[i]);
	}
	int m=p.size();
	Rep(i,n-2,0){
		while(p.size()>m&&(p.back()-p[p.size()-2])%(o[i]-p[p.size()-2])<eps) p.pop_back();
		if(i)p.pb(o[i]); 
	}
	return p;
}
vector<P>halfplane(vector<line>l)
{
	vector<P>res;
	sort(l.begin(),l.end());
	deque<P>p; deque<line>q;
	for(auto o:l){
		while(p.size()&&(p.back()-o.a)%o.b>0) q.pop_back(),p.pop_back();
		while(p.size()&&(p.front()-o.a)%o.b>0)q.pop_front(),p.pop_front();
		if (q.size()&&fabs(o.b%q.back().b)<eps){
			if (fabs(o.b.ang()-q.back().b.ang()) > eps)
				return p.clear(),res;
			q.pop_back(); if(p.size())p.pop_back();
		}
		if(q.size())p.pb(q.back()*o); q.pb(o); 
	}
	while(p.size()&&(p.back()-q.front().a)%(q.front().b)>0)
		q.pop_back(),p.pop_back();
	if(q.size()<3)p.clear();
	else p.pb(q.front()*q.back());
	while(p.size())res.pb(p.front()),p.pop_front();
	return res;
}
posted @ 2023-11-21 16:49  Rainbow_qwq  阅读(151)  评论(0编辑  收藏  举报