题目描述
20%
暴力搞就行了……
每次用反正切(atan)来搞
100%
水法
cdq分治。
每次按照x来排序,左右各扫一遍。
可以通过感性理解来发现弧度最小的点一定在凸壳上
所以分别维护一个上凸壳,之后在上面暴力用叉积判方向即可
code
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(x,y) (x<y?x:y)
#define max(x,y) (x>y?x:y)
using namespace std;
double x[100001];
double y[100001];
int A[100001][2];
int a[200001][4];
bool bz[100001];
int d[200001];
double ans1[100001];
double ans2[100001];
int i,j,k,l,n,m,len;
inline int getint() { char c; int ret=0; for(c=getchar(); c<'0' || c>'9'; c=getchar()); for(; c>='0'&&c<='9'; c=getchar()) ret=ret*10+c-'0'; return ret; }
void swap(double &a,double &b) {double c=a;a=b;b=c;}
double cross(int i,int j,int k) {return (x[i]-x[k])*(y[j]-y[k])-(x[j]-x[k])*(y[i]-y[k]);}
void qsort(int l,int r)
{
int i,j;
double mid;
i=l;
j=r;
mid=x[(l+r)/2];
while (i<=j)
{
while (x[i]<mid) i++;
while (x[j]>mid) j--;
if (i<=j)
{
swap(x[i],x[j]);
swap(y[i],y[j]);
i++,j--;
}
}
if (l<j) qsort(l,j);
if (i<r) qsort(i,r);
return;
}
void Qsort(int l,int r)
{
int i,j,mid,Mid;
i=l;
j=r;
mid=a[(l+r)/2][1];
Mid=a[(l+r)/2][0];
while (i<=j)
{
while (a[i][1]<mid || a[i][1]==mid && a[i][0]>Mid) i++;
while (a[j][1]>mid || a[j][1]==mid && a[j][0]<Mid) j--;
if (i<=j)
{
swap(a[i][0],a[j][0]);
swap(a[i][1],a[j][1]);
swap(a[i][2],a[j][2]);
swap(a[i][3],a[j][3]);
i++,j--;
}
}
if (l<j) Qsort(l,j);
if (i<r) Qsort(i,r);
return;
}
double xl(int i,int j)
{
if (y[i]==y[j]) return 0;
return (y[j]-y[i])/(x[j]-x[i]);
}
double work(int X,int S,int R)
{
int L,Mid,MMid;
double m1,m2,s;
for (L=R; L>1 && cross(d[L],d[L-1],X)*S<0; L--);
if (y[d[L]]==y[X])
s=M_PI_2;
else
s=atan(S*(x[X]-x[d[L]])/(y[d[L]]-y[X]));
if (s<0) s+=M_PI;
return s;
}
void dg(int l,int r)
{
int i,j,L,R,Mid,MMid,mid=(l+r)/2;
double s,m1,m2;
if (l==r) return;
dg(l,mid);
dg(mid+1,r);
len=0;
Qsort(l,r);
fo(i,l,r)
if (!a[i][0] && a[i][2]<=mid)
{
while (len>1 && xl(d[len-1],d[len])<xl(d[len],a[i][1])) len--;
d[++len]=a[i][1];
}
else
if ( a[i][0] && a[i][2]> mid && len)
{
s=work(a[i][1],1,len);
ans1[a[i][3]]=min(ans1[a[i][3]],s);
}
fo(i,l,r-1)
if (a[i][1]==a[i+1][1] && a[i][0]>a[i+1][0])
swap(a[i][0],a[i+1][0]),swap(a[i][1],a[i+1][1]),swap(a[i][2],a[i+1][2]),swap(a[i][3],a[i+1][3]);
len=0;
fd(i,r,l)
if (!a[i][0] && a[i][2]<=mid)
{
while (len>1 && xl(d[len],d[len-1])>xl(a[i][1],d[len])) len--;
d[++len]=a[i][1];
}
else
if ( a[i][0] && a[i][2]> mid && len)
{
for (R=len; R && d[R]==a[i][1]; R--);
s=work(a[i][1],-1,R);
ans2[a[i][3]]=min(ans2[a[i][3]],s);
}
}
int main()
{
// freopen("lhxsb2.in","r",stdin);
n=getint();
m=getint();
fo(i,1,n)
x[i]=getint(),y[i]=getint();
qsort(1,n);
fo(i,1,m)
{
A[i][0]=getint();
A[i][1]=getint();
if (!A[i][0]) bz[A[i][1]]=1;
}
j=0;
fo(i,1,n)
if (!bz[i])
{
j++;
a[j][0]=0;
a[j][1]=i;
a[j][2]=j;
}
l=0;
fd(i,m,1)
{
j++;
a[j][0]=A[i][0];
a[j][1]=A[i][1];
a[j][2]=j;
if (a[j][0])
{
l++;
ans1[l]=233;
ans2[l]=233;
a[j][3]=l;
}
}
m=j;
dg(1,m);
fd(i,l,1)
printf("%0.6lf\n",ans1[i]+ans2[i]);
return 0;
}
正解(伪)
在凸壳上三分
因为是个凸壳,所以可以三分求极值
慢到爆炸
其实一开始是用O2卡过的
没错这是我自己想的SB方法
code
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(x,y) (x<y?x:y)
#define max(x,y) (x>y?x:y)
using namespace std;
double x[100001];
double y[100001];
int A[100001][2];
int a[200001][4];
bool bz[100001];
int d[200001];
double ans1[100001];
double ans2[100001];
int i,j,k,l,n,m;
inline int getint() { char c; int ret=0; for(c=getchar(); c<'0' || c>'9'; c=getchar()); for(; c>='0'&&c<='9'; c=getchar()) ret=ret*10+c-'0'; return ret; }
void swap(double &a,double &b) {double c=a;a=b;b=c;}
void qsort(int l,int r)
{
int i,j;
double mid;
i=l;
j=r;
mid=x[(l+r)/2];
while (i<=j)
{
while (x[i]<mid) i++;
while (x[j]>mid) j--;
if (i<=j)
{
swap(x[i],x[j]);
swap(y[i],y[j]);
i++,j--;
}
}
if (l<j) qsort(l,j);
if (i<r) qsort(i,r);
return;
}
void Qsort(int l,int r)
{
int i,j,mid,Mid;
i=l;
j=r;
mid=a[(l+r)/2][1];
Mid=a[(l+r)/2][0];
while (i<=j)
{
while (a[i][1]<mid || a[i][1]==mid && a[i][0]>Mid) i++;
while (a[j][1]>mid || a[j][1]==mid && a[j][0]<Mid) j--;
if (i<=j)
{
swap(a[i][0],a[j][0]);
swap(a[i][1],a[j][1]);
swap(a[i][2],a[j][2]);
swap(a[i][3],a[j][3]);
i++,j--;
}
}
if (l<j) Qsort(l,j);
if (i<r) Qsort(i,r);
return;
}
double xl(int i,int j)
{
if (y[i]==y[j]) return 0;
return (y[j]-y[i])/(x[j]-x[i]);
}
double Xl(int i,int j)
{
if (y[i]==y[j]) return 0;
return (y[i]-y[j])/(x[j]-x[i]);
}
void dg(int l,int r)
{
int i,j,L,R,Mid,MMid,mid=(l+r)/2;
double s,m1,m2;
if (l==r) return;
dg(l,mid);
dg(mid+1,r);
int len=0;
Qsort(l,r);
fo(i,l,r)
if (!a[i][0] && a[i][2]<=mid)
{
while (len>1 && xl(d[len-1],d[len])<xl(d[len],a[i][1])) len--;
d[++len]=a[i][1];
}
else
if ( a[i][0] && a[i][2]> mid && len)
{
L=1;
R=len;
while (L<R)
{
Mid=(L+R)/2;
MMid=(Mid+R)/2;
if (Mid==MMid)
Mid--,MMid++;
if (L+1==R)
Mid=L,MMid=R;
if (y[d[Mid]]==y[a[i][1]])
m1=M_PI_2;
else
m1=atan((x[a[i][1]]-x[d[Mid]])/(y[d[Mid]]-y[a[i][1]]));
if (m1<0) m1+=M_PI;
if (y[d[MMid]]==y[a[i][1]])
m2=M_PI_2;
else
m2=atan((x[a[i][1]]-x[d[MMid]])/(y[d[MMid]]-y[a[i][1]]));
if (m2<0) m2+=M_PI;
if (L+1==R)
{
if (m1>m2)
L++; else R--;
break;
}
if (m1<=m2)
{
if (R==MMid)
R--;else R=MMid;
}
else
{
if (L==Mid)
L++;else L=Mid;
}
}
if (y[d[L]]==y[a[i][1]])
s=M_PI_2;
else
s=atan((x[a[i][1]]-x[d[L]])/(y[d[L]]-y[a[i][1]]));
if (s<0) s+=M_PI;
ans1[a[i][3]]=min(ans1[a[i][3]],s);
}
fo(i,l,r-1)
if (a[i][1]==a[i+1][1] && a[i][0]>a[i+1][0])
swap(a[i][0],a[i+1][0]),swap(a[i][1],a[i+1][1]),swap(a[i][2],a[i+1][2]),swap(a[i][3],a[i+1][3]);
len=0;
fd(i,r,l)
if (!a[i][0] && a[i][2]<=mid)
{
while (len>1 && Xl(d[len],d[len-1])<Xl(a[i][1],d[len])) len--;
d[++len]=a[i][1];
}
else
if ( a[i][0] && a[i][2]> mid && len)
{
L=1;
for (R=len; R && d[R]==a[i][1]; R--);
while (L<R)
{
Mid=(L+R)/2;
MMid=(Mid+R)/2;
if (Mid==MMid)
Mid--,MMid++;
if (L+1==R)
Mid=L,MMid=R;
if (y[d[Mid]]==y[a[i][1]])
m1=M_PI_2;
else
m1=atan((x[d[Mid]]-x[a[i][1]])/(y[d[Mid]]-y[a[i][1]]));
if (m1<0) m1+=M_PI;
if (y[d[MMid]]==y[a[i][1]])
m2=M_PI_2;
else
m2=atan((x[d[MMid]]-x[a[i][1]])/(y[d[MMid]]-y[a[i][1]]));
if (m2<0) m2+=M_PI;
if (L+1==R)
{
if (m1>m2)
L++; else R--;
break;
}
if (m1<=m2)
{
if (R==MMid)
R--;else R=MMid;
}
else
{
if (L==Mid)
L++;else L=Mid;
}
}
if (y[d[L]]==y[a[i][1]])
s=M_PI_2;
else
s=atan((x[d[L]]-x[a[i][1]])/(y[d[L]]-y[a[i][1]]));
if (s<0) s+=M_PI;
ans2[a[i][3]]=min(ans2[a[i][3]],s);
}
}
int main()
{
n=getint();
m=getint();
fo(i,1,n)
x[i]=getint(),y[i]=getint();
qsort(1,n);
fo(i,1,m)
{
A[i][0]=getint();
A[i][1]=getint();
if (!A[i][0]) bz[A[i][1]]=1;
}
j=0;
fo(i,1,n)
if (!bz[i])
{
j++;
a[j][0]=0;
a[j][1]=i;
a[j][2]=j;
}
l=0;
fd(i,m,1)
{
j++;
a[j][0]=A[i][0];
a[j][1]=A[i][1];
a[j][2]=j;
if (a[j][0])
{
l++;
ans1[l]=233;
ans2[l]=233;
a[j][3]=l;
}
}
m=j;
dg(1,m);
fd(i,l,1)
printf("%0.6lf\n",ans1[i]+ans2[i]);
return 0;
}
正解
直接二分就ok了
二分判叉积
code
无奇怪的优化
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(x,y) (x<y?x:y)
#define max(x,y) (x>y?x:y)
using namespace std;
struct BND{int s0,s1,s2,s3;};
struct DDF{double x,y;};
DDF z[100001];
int A[100001][2];
BND a[200001];
bool bz[100001];
int d[200001];
double Xl[200001];
double ans1[100001];
double ans2[100001];
int i,j,k,l,n,m,len;
inline int gt() { char c; int ret=0; for(c=getchar(); c<'0' || c>'9'; c=getchar()); for(; c>='0'&&c<='9'; c=getchar()) ret=ret*10+c-'0'; return ret; }
inline double cross(int i,int j,int k) {return (z[i].x-z[k].x)*(z[j].y-z[k].y)-(z[j].x-z[k].x)*(z[i].y-z[k].y);}
inline void swap(BND &a,BND &b) {BND c=a;a=b;b=c;}
bool cmp(DDF a,DDF b) {return a.x<b.x;}
bool Cmp(BND a,BND b) {return a.s1<b.s1;}
double xl(int i,int j)
{
if (z[i].y==z[j].y) return 0;
return (z[j].y-z[i].y)/(z[j].x-z[i].x);
}
double work(int X,int S,int R)
{
int L,Mid;
double m1,m2,s;
L=1;
R--;
while (L<R)
{
Mid=(L+R)>>1;
if (cross(d[Mid],d[Mid+1],X)*S<0)
L=Mid+1; else R=Mid;
}
if (L==R && cross(d[L],d[L+1],X)*S<0) L++;
if (z[d[L]].y==z[X].y)
s=M_PI_2;
else
s=atan(S*(z[X].x-z[d[L]].x)/(z[d[L]].y-z[X].y));
if (s<0) s+=M_PI;
return s;
}
void dg(int l,int r)
{
int i,j,R,Mid,MMid,mid=(l+r)>>1;
double s,m1,m2;
if (l==r) return;
dg(l,mid);
dg(mid+1,r);
stable_sort(a+l,a+r+1,Cmp);
len=0;
fo(i,l,r)
if (!a[i].s0 && a[i].s2<=mid)
{
while (len>1 && Xl[len-1]<xl(d[len],a[i].s1)) len--;
d[++len]=a[i].s1;
if (len>1) Xl[len-1]=xl(d[len-1],d[len]);
}
else
if ( a[i].s0 && a[i].s2> mid && len)
{
for (R=len; R && d[R]==a[i].s1; R--);
if (R)
{
s=work(a[i].s1,1,R);
ans1[a[i].s3]=min(ans1[a[i].s3],s);
}
}
len=0;
fd(i,r,l)
if (!a[i].s0 && a[i].s2<=mid)
{
while (len>1 && Xl[len-1]>xl(a[i].s1,d[len])) len--;
d[++len]=a[i].s1;
if (len>1) Xl[len-1]=xl(d[len-1],d[len]);
}
else
if ( a[i].s0 && a[i].s2> mid && len)
{
for (R=len; R && d[R]==a[i].s1; R--);
if (R)
{
s=work(a[i].s1,-1,R);
ans2[a[i].s3]=min(ans2[a[i].s3],s);
}
}
}
int main()
{
n=gt();m=gt();
fo(i,1,n)
z[i].x=gt(),z[i].y=gt();
stable_sort(z+1,z+n+1,cmp);
fo(i,1,m)
{
A[i][0]=gt();A[i][1]=gt();
if (!A[i][0]) bz[A[i][1]]=1;
}
j=0;
fo(i,1,n)
if (!bz[i])
{
j++;
a[j].s0=0;
a[j].s1=i;
a[j].s2=j;
}
l=0;
fd(i,m,1)
{
j++;
a[j].s0=A[i][0];
a[j].s1=A[i][1];
a[j].s2=j;
if (a[j].s0)
{
l++;
ans1[l]=233;
ans2[l]=233;
a[j].s3=l;
}
}
m=j;
dg(1,m);
fd(i,l,1)
printf("%0.6lf\n",ans1[i]+ans2[i]);
return 0;
}