[几何][单调] JZOJ P3636 Mobile
Description
著名的手机网络运营商Totalphone 修建了若干基站收发台,以用于把信号网络覆盖一条新建的高速公路。因为Totalphone 的程序员总是很马虎的,所以,基站的传功功率不能独立设置,只能将所有新基站的功率设置为一个相同的值。为了让能源的消耗尽量少,公司希望知道公路中任意点到最近基站距离的最大值。
Input
输入的第一行包括两个整数N(1<=N<=10^6)和L(1<=L<=10^9)分别表示基站收发台的数量和高速公路的长度。接下来N行,每行包含一对整数xi,yi(-10^9<=xi,yi<=10^9)描述一个基站的坐标。所有给出的点都互不相同。点按照x坐标不下降排列。如果两个点的x坐标相同,那么它们之间按照y坐标的升序排列。
高速公路是一条从(0,0) 到(L,0) 的直线线段。
Output
输出的唯一一行包含单独一个数字——任意点到最近基站距离的最大值。你的输出被认为是正确的仅当它与精确结果的误差不大于10^-3。
Sample Input
2 10
0 0
11 1
Sample Output
5.545455
Data Constraint
总值25 分的数据满足N<=5000
总值50 分的数据满足N<=1000000。
注意 :这题的时超范围是0.5s (c++不加读入优化会超)
题解
这几天的题贼鸡儿变态
不想说了,自行脑补......
如果有两个点x坐标相同,那么显然只需要保留y坐标绝对值较小的一个即可。
接下来对于相邻顺序的两个点,作两点连线段的中垂线。
显然,中垂线左侧的点距离x坐标较小的点较近,中垂线右侧的点距离x坐标较大的点较近。
因此按x坐标的顺序从小到大扫描n个整点,用一个栈保存可能成为最近点的整点。
同时维护栈中两点连线段中垂线与给出线段交点x坐标单调递增。
每当加入一个点前,判断是否破坏了栈的单调性,如果不满足单调性则弹出栈顶元素直到单调性被满足,再将新点加入栈顶。
最后答案即为线段的端点以及所有中垂线交点与他们最近点的距离的最大值。最后总的时间复杂度为O(n)。
代码
#include<cstdio>
#include<cmath>
#include<iostream>
#define inf 9999999999999
using namespace std;
int n,l,tot,f[1000005];
long double xx,yy,ans,mn,x[1000005],y[1000005];
long double sqr(long double x){return x*x;}
long double qiu(double x1,double y1,double x2,double y2) { return ((sqr(x1)-sqr(x2)+sqr(y1)-sqr(y2))/(2*(x1-x2))); }
long double read()
{
int x=0,i=1;
char ch=getchar();
while (ch<'0'||ch>'9')
{
if (ch=='-') i=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*i;
}
int main()
{
//freopen("mobile.in","r",stdin);
//freopen("mobile.out","w",stdout);
n=read(); l=read();
for (int i=1;i<=n;i++)
{
double xx=read(),yy=read();
if (xx==yy&&xx==0&&i==1)
{
tot++;
continue;
}
if (xx!=x[tot])
{
x[++tot]=xx;
y[tot]=yy;
}
else if (xx==x[tot]&&abs(yy)<abs(y[tot])) y[tot]=yy;
}
long double mn=inf;
for (int i=1;i<=tot;i++)
if (sqrt(sqr(x[i])+sqr(y[i]))<mn)
mn=sqrt(sqr(x[i])+sqr(y[i]));
ans=mn;
mn=inf;
long double p=l;
for (int i=1;i<=tot;i++)
if (sqrt(sqr(x[i]-p)+sqr(y[i]))<mn)
mn=sqrt(sqr(x[i]-p)+sqr(y[i]));
ans=max(ans,mn);
f[1]=1;
int head=1,tail=1;
for (int i=2;i<=tot;i++)
{
while ((head<tail)&&qiu(x[f[head]],y[f[head]],x[f[head+1]],y[f[head+1]])<0) head++;
while ((head<tail)&&qiu(x[f[tail]],y[f[tail]],x[f[tail-1]],y[f[tail-1]])>qiu(x[i],y[i],x[f[tail]],y[f[tail]])) tail--;
f[++tail]=i;
}
for (int i=head;i<tail;i++)
{
p=qiu(x[f[i]],y[f[i]],x[f[i+1]],y[f[i+1]]);
if (p>l) break;
mn=sqrt(sqr(x[f[i]]-p)+sqr(y[f[i]]));
ans=max(ans,mn);
}
ans=max(ans,mn);
printf("%.5lf\n",(double)ans);
return 0;
}