#include<iostream> #include<cstring> #include<cstdio> #include<string> #include<algorithm> #include<queue> #include<cmath> #include<vector> using namespace std; #define mnx 50050 #define LL long long #define mod 1000000007 #define inf 0x3f3f3f3f #define eps 1e-8 #define Pi acos(-1.0); #define lson l, m, rt << 1 #define rson m+1, r, rt << 1 | 1 // 角度与弧度转换 double todeg( double rad ){ return rad * 180 / Pi; } double torad( double deg ){ return deg / 180 * Pi; } int dcmp( double x ){ if( fabs( x ) < eps ) return 0; return x < 0 ? -1 : 1; } // 点 struct point{ double x, y; point( double x = 0, double y = 0 ) : x(x), y(y) {} point operator + ( const point &b ) const{ return point( x + b.x, y + b.y ); } point operator - ( const point &b ) const{ return point( x - b.x, y - b.y ); } point operator * ( const double &k ) const{ return point( x * k, y * k ); } point operator / ( const double &k ) const{ return point( x / k, y / k ); } bool operator < ( const point &b ) const{ return dcmp( x - b.x ) < 0 || dcmp( x - b.x ) == 0 && dcmp( y - b.y ) < 0; } bool operator == ( const point &b ) const{ return dcmp( x - b.x ) == 0 && dcmp( y - b.y ) == 0; } double len(){ return sqrt( x * x + y * y ); } }; typedef point Vector; // 点积 double dot( Vector a, Vector b ){ return a.x * b.x + a.y * b.y; } // 叉积 double cross( Vector a, Vector b ){ return a.x * b.y - a.y * b.x; } // 向量旋转 Vector rotate( Vector a, double rad ){ return Vector( a.x * cos(rad) - a.y * sin(rad), a.x * sin(rad) + a.y * cos(rad) ); } // 向量的单位法线 Vector normal( Vector a ){ double L = a.len(); return Vector( -a.y / L, a.x / L ); } // 点到直线的距离 double dis_to_line( point p, point a, point b ){ Vector v1 = b - a, v2 = p - a; return fabs( cross( v1, v2 ) / v1.len() ); } // 点到线段的距离 double dis_to_segment( point p, point a, point b ){ if( a == b ) return (p-a).len(); Vector v1 = b - a, v2 = p - a, v3 = p - b; if( dcmp( dot( v1, v2 ) ) < 0 ) return v2.len(); else if( dcmp( dot( v1, v3 ) ) > 0 ) return v3.len(); else return fabs( cross( v1, v2 ) ) / v1.len(); } // 点到直线上的投影 point get_line_projection( point p, point a, point b ){ Vector v = b - a; return a + v * ( dot( v, p - a ) / dot( v, v ) ); } // 线段相交判定 bool segment_intersection( point a1, point a2, point b1, point b2 ){ double c1 = cross( a2 - a1, b1 - a1 ), c2 = cross( a2 - a1, b2 - a1 ); double c3 = cross( b2 - b1, a1 - b1 ), c4 = cross( b2 - b1, a2 - b1 ); return dcmp(c1) * dcmp(c2) < 0 && dcmp(c3) * dcmp(c4) < 0; } // 判断点是否在一条线段上 bool on_segment( point p, point a1, point a2 ){ return dcmp( cross( a1 - p, a2 - p ) ) == 0 && dcmp( dot( a1 - p, a2 - p ) ) < 0; } // 多边形面积 double polygon_area( point *p, int n ){ double area = 0; for( int i = 1; i < n - 1; i++ ){ area += cross( p[i] - p[0], p[i+1] - p[0] ); } return area / 2; } // 点在多边形内判定 int point_in( point p, point *poly, int n ){ int wn = 0; poly[n] = poly[0]; for( int i = 0; i < n; i++ ){ if( on_segment( p, poly[i], poly[i+1] ) ) return -1; int k = dcmp( cross( poly[i+1] - poly[i], p - poly[i] ) ); int d1 = dcmp( poly[i].y - p.y ); int d2 = dcmp( poly[i+1].y - p.y ); if( k > 0 && d1 <= 0 && d2 > 0 ) wn++; if( k < 0 && d2 <= 0 && d1 > 0 ) wn--; } if( wn != 0 ) return 1; return 0; } // 多边形重心 point masscenter( point *p, int n ){ point ans = point( 0, 0 ); double sum = polygon_area( p, n ); if( dcmp( sum ) == 0 ) return ans; p[n] = p[0]; for( int i = 0; i < n; i++ ){ ans = ans + ( p[i] + p[i+1] ) * cross( p[i+1], p[i] ); } return ans / sum / 6.0; } // 凸包(要去重,边上没有输入点) int convex_hull( point *p, int n, point *ch ){ sort( p, p + n ); int b = 0, c = 0; while( c < n ){ p[b++] = p[c++]; while( c < n && p[b-1] == p[c] ) c++; } n = b; int m = 0; for( int i = 0; i < n; i++ ){ while( m > 1 && cross( ch[m-1] - ch[m-2], p[i] - ch[m-2] ) <= 0 ) m--; ch[m++] = p[i]; } int k = m; for( int i = n - 2; i >= 0; i-- ){ while( m > k && cross( ch[m-1] - ch[m-2], p[i] - ch[m-2] ) <= 0 ) m--; ch[m++] = p[i]; } if( n > 1 ) m--; return m; } // 线 struct Line{ point p; Vector v; double ang; Line() {} Line( point p, point v ) : p(p), v(v) { ang = atan2( v.y - 0.0, v.x - 0.0 ); } bool operator < ( const Line &b ) const{ return ang < b.ang; } }; // 点p在有向直线L的左边(线上不算) bool onleft( Line L, point p ){ return cross( L.v, p - L.p ) > 0; } // 二直线交点 point get_intersection( Line a, Line b ){ Vector u = a.p - b.p; double t = cross( b.v, u ) / cross( a.v, b.v ); return a.p + a.v + t; } // 半平面交 int half_plane_intersection( Line *L, int n, point *poly ){ sort( L, L + n ); int first, last; point *p = new point[n]; Line *q = new Line[n]; q[first = last = 0] = L[0]; for( int i = 1; i < n; i++ ){ while( first < last && !onleft( L[i], p[last-1] ) ) last--; while( first < last && !onleft( L[i], p[first] ) ) first++; q[++last] = L[i]; if( fabs( cross( q[last].v, q[last-1].v ) ) < eps ){ last--; if( onleft( q[last], L[i].p ) ) q[last] = L[i]; } if( first < last ){ p[last-1] = get_intersection( q[last-1], q[last] ); } } while( first < last && !onleft( q[first], p[last-1] ) ) last--; if( last - first <= 1 ) return 0; p[last] = get_intersection( q[last], q[first] ); int m = 0; for( int i = first; i <= last; i++ ) poly[m++] = p[i]; return m; } // 旋转卡壳 double rotating_calipers( point *ch, int n ){ int j = 1; double ans = 0; ch[n] = ch[0]; for( int i = 0; i < n; i++ ){ while( fabs( cross( ch[i+1]-ch[i], ch[j+1]-ch[i] ) ) > fabs( cross( ch[i+1]-ch[i], ch[j] - ch[i] ) ) ) j = ( j + 1 ) % n; ans = max( ans, max( ( ch[i] - ch[j] ).len(), ( ch[i+1] - ch[j] ).len() ) ); } return ans; } /// /// /// int main(){ return 0; }