两个凸集的和(每两个不同集的x,y分别相加得新点)为凸集。
将两个凸集按同样时针求向量,极角排序后按向量走既得新凸集(但还需对应点平移)。
应用:求两凸集距离。
area
求新凸集面积。
不需平移,直接叉积。
这道题证明二分快排是可以卡的。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
struct point
{
long long x,y,c;
};
const double eps=1e-6;
point a[300000],b[3][300000],p[300000];
int n,m,tot,t[3],st[3][300000];
int cmper(const void *i,const void *j)
{
point *p=(point *)i,*q=(point *)j;
if (0==(p->y - q->y)) return (p->x-q->x);
// if (p->y == q->y) return p->x - q->x;
return p->y-q->y;
}
inline long long cross(point e,point r)
{
return ((e.x*r.y)-(e.y*r.x));
}
int check(int c,int i,int j,int k)
{
point u,v,w;
u=a[i],v=a[j],w=a[k];
point e,r;
e.x=v.x-u.x,e.y=v.y-u.y;
r.x=w.x-u.x,r.y=w.y-u.y;
long long kk=cross(e,r);
return (kk>=0) ? 1 : 0;
}
void work(int c,int s)
{
qsort(a+1,s,sizeof(a[1]),cmper);
memset(st[c],0,sizeof(st[c]));
t[c]=1;st[c][t[c]]=1;
int i,k;
for (i=2;i<=s;i++)
{
for (;(t[c]>1)&&(check(c,st[c][t[c]-1],st[c][t[c]],i));t[c]--) ;
st[c][++t[c]]=i;
}
k=t[c];
for (i=s-1;i>0;i--)
{
for (;(t[c]>k)&&(check(c,st[c][t[c]-1],st[c][t[c]],i));t[c]--) ;
st[c][++t[c]]=i;
}
if (s>1) t[c]--;
}
void init()
{
scanf("%d%d\n",&n,&m);
int i;
for (i=1;i<=n;i++)
{
scanf("%I64d%I64d",&a[i].x,&a[i].y);
// b[1][i]=a[i];
}
scanf("\n");
work(1,n);
for (i=1;i<=n;i++) b[1][i]=a[i];
memset(a,0,sizeof(a));
for (i=1;i<=m;i++)
{
scanf("%I64d%I64d",&a[i].x,&a[i].y);
// b[2][i]=a[i];
}
scanf("\n");
work(2,m);
for (i=1;i<=m;i++) b[2][i]=a[i];
}
long long equ(long long x)
{
if ((x>-eps)&&(x<eps)) return 1;
return 0;
}
void doit(int c)
{
int i;
for (i=2;i<=t[c];i++)
{
tot++;
p[tot].x=b[c][st[c][i]].x-b[c][st[c][i-1]].x;
p[tot].y=b[c][st[c][i]].y-b[c][st[c][i-1]].y;
if ((p[tot].x>0)&&((p[tot].y>0)||(equ(p[tot].y)))) p[tot].c=1;
if (((p[tot].x<0)||(equ(p[tot].x)))&&(p[tot].y>0)) p[tot].c=2;
if ((p[tot].x<0)&&((p[tot].y<0)||(equ(p[tot].y)))) p[tot].c=3;
if (((p[tot].x>0)||(equ(p[tot].x)))&&(p[tot].y<0)) p[tot].c=4;
}
tot++;
p[tot].x=b[c][st[c][1]].x-b[c][st[c][i-1]].x;
p[tot].y=b[c][st[c][1]].y-b[c][st[c][i-1]].y;
if ((p[tot].x>0)&&((p[tot].y>0)||(equ(p[tot].y)))) p[tot].c=1;
if (((p[tot].x<0)||(equ(p[tot].x)))&&(p[tot].y>0)) p[tot].c=2;
if ((p[tot].x<0)&&((p[tot].y<0)||(equ(p[tot].y)))) p[tot].c=3;
if (((p[tot].x>0)||(equ(p[tot].x)))&&(p[tot].y<0)) p[tot].c=4;
}
inline int chek(point a,point b)
{
if (a.c<b.c) return 1 ;
else if (a.c>b.c) return 0;
long long k=cross(a,b);
// if (k<=0) return 0;
if (k>0) return 1;
return 0;
}
void qs(int l,int r)
{
int i=l,j=r;
point x=p[rand () % (r - l + 1) + l],c;
// long long xx=cross(x,x);
for (;i<=j;)
{
for (;chek(p[i],x);i++) ;
for (;chek(x,p[j]);j--) ;
if (i<=j)
{
c=p[i],p[i]=p[j],p[j]=c;
i++,j--;
}
}
if (i<r) qs(i,r);
if (l<j) qs(l,j);
}
int cmp(const void *i,const void *j)
{
point a=*(point*)i,b=*(point*)j;
if (a.c<b.c) return -1 ;
else if (a.c>b.c) return 1;
long long k=cross(a,b);
// if (k<=0) return 0;
if (k>0) return -1;
return 1;
}
void make()
{
// qs(1,tot);
qsort(p+1,tot,sizeof(p[1]),cmp) ;
int i;
long long ans=0;
point u,v;
u.x=0,u.y=0;
for (i=1;i<=tot;i++)
{
v.x=u.x+p[i].x;
v.y=u.y+p[i].y;
ans+=cross(u,v);
u=v;
}
if (ans<eps) ans=-ans;
printf("%I64d\n",ans);
}
int main()
{
freopen("area.in","r",stdin);
freopen("area.out","w",stdout);
srand( int(time(NULL)));
init();
tot=0;
doit(1);
doit(2);
make();
return 0;
}