# 洛谷CF1071E Rain Protection（计算几何，闵可夫斯基和，凸包，二分答案）

$(b-a,h)×(x_i-a,y_i)=0\$$h-y_i)a+y_ib-x_ih=0$ 这说明了\(a,b$$的关系，必须落在一条直线上！它在$$(0,0)(0,w)(w,w)(w,0)$$矩形范围内的部分就是可行域。

#include<bits/stdc++.h>
#define R register int
#define I inline
using namespace std;
typedef double DB;
const int SZ=1<<19,N=1e5+9;
const DB EPS=1e-8;
char buf[SZ],*ie=buf+SZ,*ip=ie-1;
inline int in(){
G;while(*ip<'-')G;
R x=*ip&15;G;
while(*ip>'-'){x*=10;x+=*ip&15;G;}
return x;
}
inline bool is0(DB x){return fabs(x)<EPS;}
struct Vec{
DB x,y;
I Vec(){x=y=0;}
I Vec(DB a){x=a;y=0;}
I Vec(DB a,DB b){x=a;y=b;}
I friend istream&operator>>(istream&cin,Vec&a){return a.x=in(),a.y=in(),cin;}
I Vec operator-(){return Vec(-x,-y);}
I Vec operator+(Vec a){return Vec(x+a.x,y+a.y);}
I Vec operator-(Vec a){return Vec(x-a.x,y-a.y);}
I Vec operator*(DB a){return Vec(x*a,y*a);}
I Vec operator/(DB a){return Vec(x/a,y/a);}
I friend Vec operator*(DB a,Vec b){b.x*=a,b.y*=a;return b;}
I Vec&operator+=(Vec a){x+=a.x,y+=a.y;return*this;}
I Vec&operator-=(Vec a){x-=a.x,y-=a.y;return*this;}
I DB operator*(Vec a){return x*a.x+y*a.y;}
I DB operator^(Vec a){return x*a.y-y*a.x;}
I bool operator==(Vec a){return is0(x-a.x)&&is0(y-a.y);}
I friend bool operator<(Vec a,Vec b){
return (a^b)>0||(is0(a^b)&&Len(a)<Len(b));
}
I friend DB Len(Vec a){
return sqrt(a.x*a.x+a.y*a.y);
}
}a[N],b[N],c[9],d[9],e;
int t[N],st[N];
I Vec LineCross(Vec a1,Vec a2,Vec b1,Vec b2){
a2-=a1;b2-=b1;
return b2^a2?a1+(b2^(b1-a1))/(b2^a2)*a2:Vec(NAN,NAN);
}
I Vec SegCross(Vec&a1,Vec&a2,Vec&b1,Vec&b2){
Vec c=LineCross(a1,a2,b1,b2);
return (a1-c)*(a2-c)>EPS||(b1-c)*(b2-c)>EPS?Vec(NAN,NAN):c;
}
I int Convex(Vec*a,R n){
R k=0,p=0;Vec bs;
for(R i=1;i<n;++i)
if(a[i].y<a[k].y||(a[i].y==a[k].y&&a[i].x<a[k].x))k=i;
swap(a[0],a[k]);bs=a[0];
for(R i=0;i<n;++i)a[i]-=bs;
sort(a+1,a+n);
for(R i=1;i<n;st[++p]=i++)
while(p&&((a[i]-a[st[p-1]])^(a[st[p]]-a[st[p-1]]))>-EPS)--p;
for(R i=0;i<=p;++i)a[i]=a[st[i]]+bs;
return a[p+1]=bs,p+1;
}
I int Minkowski(Vec*a,R n,DB t){
for(R i=n-1,j=4*n;j;--i){
a[--j]=a[i]+Vec(-t,-t);
a[--j]=a[i]+Vec( t,-t);
a[--j]=a[i]+Vec( t, t);
a[--j]=a[i]+Vec(-t, t);
}
return Convex(a,4*n);
}
I bool Inside(Vec*a,R n,Vec v){//点是否在凸包内
for(R i=0;i<n;++i)
if(((a[i+1]-a[i])^(v-a[i]))<-EPS)return 0;
return 1;
}
I bool Check(R q,DB mid){
R n=1,p;
c[0]=e;
for(R i=1;i<=q;++i){
n=Minkowski(c,n,(t[i]-t[i-1])*mid);
for(R j=p=0;j<n;++j){//搞出所有交点，注意去重
d[p]=SegCross(a[i],b[i],c[j],c[j+1]);
p+=!(isnan(d[p].x)||(p&&d[p-1]==d[p]));
}
if(p==0){//更新当前可行域，讨论开始
if(!Inside(c,n,a[i]))return 0;
c[0]=a[i],c[1]=b[i];
}
else if(p==1){
if(Inside(c,n,a[i]))
c[1]=Inside(c,n,b[i])?(d[0]==b[i]?a[i]:b[i]):a[i];
else c[1]=Inside(c,n,b[i])?b[i]:d[0];
c[0]=d[0];
}
else c[0]=d[0],c[1]=d[1];//讨论结束
n=1+!(c[0]==c[1]);
}
return 1;
}
I void Err(bool f){if(f)cout<<"-1\n",exit(0);}
int main(){
ios::sync_with_stdio(0);
R n=in(),q=0,w=in(),h=in(),lx=0,ly=0;
cin>>e;
for(R i=1;i<=n;++i){
R tt=in(),x=in(),y=in();
Vec u=0,v=0;//求可行域线段，讨论开始
if((u.x=(DB)x*h/(h-y))>w)u=Vec(w,(DB)(x*h-(h-y)*w)/y);
if((v.y=(DB)x*h/y    )>w)v=Vec((DB)(x*h-y*w)/(h-y),w);//讨论结束
if(tt!=t[q])++q,a[q]=u,b[q]=v;//合并t相同的可行域，讨论开始
else if(a[q]==b[q]){
if(u==v)Err(!(u==a[q]));//点交点
else Err(!is0((u-a[q])^(v-a[q])));//点交线段
}
else if(x!=lx||y!=ly){
if(u==v)Err(!is0((u-a[q])^(u-b[q])));//点交线段
else Err(isnan((u=SegCross(a[q],b[q],u,v)).x));//线段交线段
a[q]=b[q]=u;
}//讨论结束
t[q]=tt;lx=x;ly=y;
}
DB l=0,r=w,mid;
while((r-l)/max(1.0,l)>1e-4)
mid=(l+r)/2,(Check(q,mid)?r:l)=mid;
cout<<fixed<<setprecision(6)<<(l+r)/2<<'\n';
return 0;
}

posted @ 2019-01-16 21:51  Flash_Hu  阅读(756)  评论(2编辑  收藏  举报