#include <iostream>
#include <string.h>
#include <queue>
#include <stdio.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
using namespace std;
const int maxn=1e4+10;
const int mod=998244353;
using namespace std;
const ll eps = 1e-8;
int sgn(ll x)
{
if(fabs(x) < eps)return 0;
if(x < 0) return -1;
return 1;
}
struct Point
{
ll x,y;
Point(){}
Point(ll _x,ll _y)
{
x = _x;y = _y;
}
Point operator -(const Point &b)const
{
return Point(x - b.x,y - b.y);
}
ll operator ^(const Point &b)const
{
return x*b.y - y*b.x;
}
ll operator *(const Point &b)const
{
return x*b.x + y*b.y;
}
ll operator ==(const Point &b)const
{
return x==b.x&&y==b.y;
}
};
struct Line
{
Point s,e;
Line(){}
Line(Point _s,Point _e)
{
s = _s;e = _e;
}
};
ll xmult(Point p0,Point p1,Point p2) //p0p1 X p0p2
{
return (p1-p0)^(p2-p0);
}
ll xmult(Point p0,Point p1,Point p2,Point p3) //p0p1 X p2p3
{
return (p1-p0)^(p3-p2);
}
bool Seg_inter_line(Line l1,Line l2) //判断直线l1和线段l2是否相交
{
return sgn(xmult(l2.s,l1.s,l1.e))*sgn(xmult(l2.e,l1.s,l1.e)) <= 0;
}
ll dist(Point a,Point b)
{
return sqrt( (b - a)*(b - a) );
}
//多边形面积s的二倍(参数按逆时针给出)
ll get_mianji(Point *P,int num)
{
ll ans=0;
for(int i=0;i<num;i++)
{
ans+=P[i]^P[(i+1)%num];
}
return ans;
}
//多边形形面积e
//凸包s
Point tubao[maxn];
int num_tubao;
Point t(0,1e9+7);
bool cmp_jijiao(Point p1,Point p2)
{
if(xmult(t, p1, p2)>0)
{
return 1;
}
else if(xmult(t, p1, p2)==0)
{
return dist(t, p1)<dist(t, p2);
}
else
return 0;
}
void get_tubao(Point *P,int num)
{
t.x=0;
t.y=1e9+7;
for(int i=0;i<num;i++)
{
if(P[i].y<t.y)
{
t=P[i];
}
else if(P[i].y==t.y)
{
t.x=min(P[i].x,t.x);
}
}
sort(P, P+num, cmp_jijiao);
num_tubao=2;
tubao[0]=P[0];tubao[1]=P[1];
for(int i=2;i<num;i++)
{
while(xmult(tubao[num_tubao-2], tubao[num_tubao-1], P[i])<0)
{
num_tubao--;
}
tubao[num_tubao]=P[i];
num_tubao++;
}
}
//凸包e
//旋转卡壳s(求最大四边形面积)
ll ro_ka(Point *P,int num)
{
ll ans=0;
//去掉重复的点s
int num2=1;
for(int i=1;i<num;i++)
{
if(P[i].x==P[i-1].x&&P[i].y==P[i-1].y)
{
continue;
}
else
{
P[num2]=P[i];
num2++;
}
}
num=num2;
//去掉重复的点e
for(int i=0;i<num;i++)
P[i+num]=P[i];
//检查是否凸包上的点全部共线s
int flag=1;
for(int i=2;i<num;i++)
{
if(xmult(P[0], P[1], P[2])!=0)
flag=0;
}
if(flag==1)
return 0;
//检查是否凸包上的点全部共线e
for(int i=0;i<num;i++){
int l=i,r;
for(int j=i+1;j<num;j++)
{
if(xmult(P[l], P[l+1], P[j],P[j+1])<0){
r=j;
break;
}
}
for(int j=i+1;j<num;j++)
{
while(xmult(P[l], P[l+1], P[i],P[j])>0)
l++;
while(xmult(P[r], P[r+1], P[i],P[j])<0)
r++;
Point t[4]={P[i],P[l],P[j],P[r]};
ans=max(ans,get_mianji(t, 4));
}
}
return ans;
}
//旋转卡壳e
//坐标旋转s
Point rotate(Point p,double angle){
Point v = p;
double c = cos(angle), s = sin(angle);
return Point(v.x*c - v.y*s , v.x*s + v.y*c);
}
//坐标旋转e
//半平面交s
Point dad_anticlock[maxn];//输入弄好就行了
Line dad_half_line[maxn],que[maxn];
//得到极角角度
double getAngle(Point a) {
return atan2(a.y, a.x);
}
//得到极角角度
double getAngle(Line a) {
return atan2(a.e.y - a.s.y, a.e.x - a.s.x);
}
bool onRight(Line a, Line b, Line c) {
Point o = getIntersectPoint(b, c);
if (((a.e - a.s) ^ (o - a.s)) < 0) return true;
return false;
}
bool cmp_half(Line L1,Line L2)
{
Point va = L1.e - L1.s, vb = L2.e - L2.s;
double A = getAngle(va), B = getAngle(vb);
if (fabs((double)(A - B)) < eps) return ((va) ^ (L2.e - L1.s)) >= 0;
return A < B;
}
bool Is_half(int num)
{
for(int i=0;i<num;i++)
{
dad_half_line[i].s=dad_anticlock[i];
dad_half_line[i].e=dad_anticlock[(i+1)%num];
}
sort(dad_half_line, dad_half_line+num, cmp_half);
int head = 0, tail = 0, cnt = 0;//模拟双端队列
//去重,极角相同时取最后一个。
for (int i = 0; i < num - 1; i++) {
if (fabs(getAngle(dad_half_line[i]) - getAngle(dad_half_line[i + 1])) < eps) {
continue;
}
dad_half_line[cnt++] = dad_half_line[i];
}
dad_half_line[cnt++] = dad_half_line[num - 1];
for (int i = 0; i < cnt; i++) {
//判断新加入直线产生的影响
while(tail - head > 1 && onRight(dad_half_line[i], que[tail - 1], que[tail - 2])) tail--;
while(tail - head > 1 && onRight(dad_half_line[i], que[head], que[head + 1])) head++;
que[tail++] = dad_half_line[i];
}
//最后判断最先加入的直线和最后的直线的影响
while(tail - head > 1 && onRight(que[head], que[tail - 1], que[tail - 2])) tail--;
while(tail - head > 1 && onRight(que[tail - 1], que[head], que[head + 1])) head++;
if (tail - head < 3) return false;
return true;
}
//半平面交e