传送门:hzwer
题解
二分+半平面交比较显然,但常数大且卡精度。
考虑二分求解的本质:
随距离增加不断将所有边向内移,在凸包面积恰好为0时的距离就是答案。
在不断内移的过程中,一些边对凸包的限制会被其相邻两条边取代(等价于二分半平面交时这条边不在双端队列中)。于是求出每条边被取代的时刻
t
i
t_i
ti压入堆,每次取
m
i
n
(
t
i
)
min(t_i)
min(ti)弹出,更改其相邻两条边的信息(双向链表维护)。直到最后只剩两条边。
t i t_i ti的求法:
- 相邻两条边平行, t i = t_i= ti=相邻两条边距离的一半
- 相邻两条边不平行, t i = t_i= ti=相邻两角的角平分线交点到当前边的距离‘
注意:
- 特判角平分线平行的情况( + ∞ +\infty +∞)
- 若弹出边的相邻边平行,则凸包面积必然已经为零,直接输出答案
代码
直接贴黄学长的了qwq
#include<queue>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define abs(x) ((x)>0?(x):-(x))
#define eps 1e-13
#define LL long long
#define LB long double
#define pa pair<LB,int>
#define mp(x,y) make_pair(x,y)
using namespace std;
LL read()
{
LL x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n;
int pre[200005],nxt[200005];
bool del[200005];
LB ans;
struct P{
LB x,y;
friend LB operator*(P a,P b){
return a.x*b.y-a.y*b.x;
}
friend P operator+(P a,P b){
return (P){a.x+b.x,a.y+b.y};
}
friend P operator-(P a,P b){
return (P){a.x-b.x,a.y-b.y};
}
friend P operator*(P a,LB b){
return (P){a.x*b,a.y*b};
}
friend LB dis(P a){
return sqrt(a.x*a.x+a.y*a.y);
}
}p[200005];
void print(P a)
{
printf("(%.3Lf,%.3Lf)",a.x,a.y);
}
struct L{
P a,b;
friend P cp(L a,L b){// crossover point
double k1,k2,t;
k1=(a.a-b.b)*(b.a-b.b),k2=(b.a-b.b)*(a.b-b.b);
t=k1/(k1+k2);
return (P){a.a.x+(a.b.x-a.a.x)*t,a.a.y+(a.b.y-a.a.y)*t};
}
}l[200005];
L ab(P a,P b,P c){ // angle a,b,c // angular bisector
LB l1=dis(a-b),l2=dis(b-c);
a=b+(a-b)*(l2/l1);
P t=a+c;t.x/=2;t.y/=2;
return (L){b,t};
}
LB dis(L l,P a){
return abs((l.b-l.a)*(a-l.a))/dis(l.a-l.b);
}
priority_queue<pa,vector<pa>,greater<pa> >pq;
void add(int x)
{
L ll=l[pre[x]],rl=l[nxt[x]];
LB t;
if(fabs((ll.b-ll.a)*(rl.b-rl.a))<eps)
t=dis(ll,rl.b)/2;
else
{
L l1=ab(ll.a,ll.b,l[x].b);
L l2=ab(l[x].a,rl.a,rl.b);
if(fabs((l1.b-l1.a)*(l2.b-l2.a))<eps)t=1e20;
else
{
P p=cp(l1,l2);t=dis(l[x],p);
}
}
pq.push(mp(t,x));
}
int main()
{
n=read();
for(int i=1;i<=n;i++)
p[i].x=read(),p[i].y=read();
p[n+1]=p[1];
for(int i=1;i<=n;i++)
l[i]=(L){p[i],p[i+1]};
for(int i=1;i<=n;i++)
pre[i]=i-1,nxt[i]=i+1;
pre[1]=n;nxt[n]=1;
for(int i=1;i<=n;i++)add(i);
for(int i=1;i<=n-2;i++)
{
int id=pq.top().second;
while(del[id])
{
pq.pop();
id=pq.top().second;
}
int L=pre[id],R=nxt[id];del[id]=1;
ans=max(ans,pq.top().first);
pq.pop();
if(abs((l[L].b-l[L].a)*(l[R].b-l[R].a))<eps)break;
P p=cp(l[L],l[R]);
l[L].b=l[R].a=p;
nxt[L]=R;pre[R]=L;
add(L);add(R);
}
printf("%.6lf",(double)ans);
return 0;
}