题目链接:
点击打开链接loj
首先将所有挡板翻转至以直线导轨为X轴的坐标系中,记录每个挡板两个端点的坐标,然后我们考虑如何处理挡板之间的遮挡情况,我们可以使用扫描线+set维护,我们将每个端点按x值排序,左端点记1 ,右端点记-1,然后我们可以用set维护在每段区间最下方的直线斜率是多少,遇到左端点在set中插入线段,遇到右端点,删除该线段。
最后我们考虑如何O(n)的统计答案,首先我们注意到最后所选的导轨上的区间的两端点一定有一个卡在挡板的端点之一,然后我们区间向右移动所含的挡板区间也单调向右,扫一遍
左端点,扫一遍
右端点即可。
附代码:写丑了最好不要参考
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<set>
#define double long double
using namespace std;
const double eps = 1e-13;
const double pi= acos(-1);
double curx;
struct node{
double x,y,xx,yy;
}lin[1000010] , model;
struct straight{
double a,b,c;
}lne;
struct node2{
double x,y,k,xx,yy;
}nw1[1000010],nw2[1000010];
int t,n;
double l;
struct point
{
int id,belong;
double x,y;
}pt1[100100],pt2[100010];
struct line1{
point aa,bb;
double jieju,xielv;
inline bool operator < (const line1 &p) const
{
return (jieju+xielv*curx)<(p.jieju+p.xielv*curx);
}
}le1[1000010],le2[1000010];
void get(node x)
{
if(fabs(x.x-x.xx)<eps)
{
lne.a=1;
lne.b=0;
lne.c=-x.x;
return ;
}
if(fabs(x.yy-x.y)<eps)
{
lne.a=0;
lne.b=1;
lne.c=-x.y;
return ;
}
double a=(x.y-x.yy)/(x.x-x.xx);
double b=-1;
double c=x.y-(x.y-x.yy)/(x.x-x.xx)*x.x;
lne.a=a;
lne.b=b;
lne.c=c;
}
int getwhere(double x,double y)
{
double tmp=lne.a*x+lne.c;
if(tmp>y) return 1;
else return 2;
}
bool cmp(node2 p,node2 q)
{
return p.x<q.x;
}
double ans=0,ret=0;
bool cmpp(point p,point q)
{
return p.x<q.x;
}
struct xianduan{
double x,xx,k;
}ed1[500100],ed2[500010];
bool cmppp(xianduan p,xianduan q)
{
if(p.x==q.x)
return p.xx<q.xx;
else return p.x<q.x;
}
double sum[500010],summ[500010];
double work(int cnt1,int cnt2)
{
for(register int i=1;i<=cnt1;++i) sum[i]=0;
for(register int i=1;i<=cnt2;++i) summ[i]=0;
double ret=0;
ans=0;
int ll=0,rr=0,ul=0,ur=0;
for(register int i=1;i<=cnt1;++i)
{
double tmp=ed1[i].xx-ed1[i].x;
double tmpp=tmp*ed1[i].k;
sum[i]=sqrt(tmp*tmp+tmpp*tmpp);
sum[i]+=sum[i-1];
// printf("%Lf %Lf %Lf %Lf\n",ed1[i].x,ed1[i].xx,ed1[i].k,sum[i]);
}
for(register int i=1;i<=cnt2;++i)
{
double tmp=ed2[i].xx-ed2[i].x;
double tmpp=tmp*ed2[i].k;
summ[i]=sqrt(tmp*tmp+tmpp*tmpp);
summ[i]+=summ[i-1];
// printf("%Lf %Lf %Lf %Lf\n",ed2[i].x,ed2[i].xx,ed2[i].k,summ[i]);
}
for(register int i=1;i<=cnt1;++i)
{
ret=0;
double left=ed1[i].x,rt=ed1[i].x+l;
ll=i;
while((ed1[rr].xx<rt||!rr)&&rr<cnt1) rr++;
ret+=(sum[rr-1]-sum[i-1]);
double tmp=min(rt,ed1[rr].xx)-max(left,ed1[rr].x);
if(tmp>eps)
{
double tmpp=tmp*ed1[rr].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
}
while((ed2[ul].xx<left||!ul)&&ul<cnt2) ul++;
while((ed2[ur].xx<rt||!ur)&&ur<cnt2) ur++;
ret+=max(summ[ur-1]-summ[ul],(double)0.0);
if(ur==ul)
{
double tmp=min(rt,ed2[ur].xx)-max(left,ed2[ur].x);
if(tmp>eps)
{
double tmpp=tmp*ed2[ur].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
}
if(ret>ans) ans=ret;
}
else
{
double tmp=min(rt,ed2[ur].xx)-max(left,ed2[ur].x);
if(tmp>eps)
{
double tmpp=tmp*ed2[ur].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
}
tmp=min(rt,ed2[ul].xx)-max(left,ed2[ul].x);
if(tmp>eps)
{
double tmpp=tmp*ed2[ul].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
}
if(ret>ans) ans=ret;
}
}
ul=ur=ll=rr=0;
for(register int i=1;i<=cnt1;++i)
{
ret=0;
double left=ed1[i].xx-l,rt=ed1[i].xx;
while((ed1[ll].xx<left||!ll)&&ll<cnt1) ll++;
rr=i;
ret+=(sum[rr]-sum[ll]);
double tmp=min(rt,ed1[ll].xx)-max(left,ed1[ll].x);
if(tmp>eps)
{
double tmpp=tmp*ed1[ll].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
}
while((ed2[ul].xx<left||!ul)&&ul<cnt2) ul++;
while((ed2[ur].xx<rt||!ur)&&ur<cnt2) ur++;
ret+=max(summ[ur-1]-summ[ul],(double)0);
if(ur==ul)
{
double tmp=min(rt,ed2[ur].xx)-max(left,ed2[ur].x);
if(tmp>eps)
{
double tmpp=tmp*ed2[ur].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
}
if(ret>ans) ans=ret;
}
else
{
double tmp=min(rt,ed2[ur].xx)-max(left,ed2[ur].x);
if(tmp>eps)
{
double tmpp=tmp*ed2[ur].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
}
tmp=min(rt,ed2[ul].xx)-max(left,ed2[ul].x);
if(tmp>eps)
{
double tmpp=tmp*ed2[ul].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
}
if(ret>ans) ans=ret;
}
}
ul=ur=ll=rr=0;
for(register int i=1;i<=cnt2;++i)
{
ret=0;
double left=ed2[i].xx-l,rt=ed2[i].xx;
while((ed2[ll].xx<left||!ll)&&ll<cnt2)ll++;
rr=i;
ret+=(summ[rr]-summ[ll]);
double tmp=min(rt,ed2[ll].xx)-max(left,ed2[ll].x);
if(tmp>eps)
{
double tmpp=tmp*ed2[ll].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
}
while((ed1[ul].xx<left||!ul)&&ul<cnt1) ul++;
while((ed1[ur].xx<rt||!ur)&&ur<cnt1) ur++;
ret+=max(sum[ur-1]-sum[ul],(double)0);
if(ur==ul)
{
double tmp=min(rt,ed1[ur].xx)-max(left,ed1[ur].x);
if(tmp>eps)
{
double tmpp=tmp*ed1[ur].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
}
if(ret>ans) ans=ret;
}
else
{
double tmp=min(rt,ed1[ur].xx)-max(left,ed1[ur].x);
if(tmp>eps)
{
double tmpp=tmp*ed1[ur].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
}
tmp=min(rt,ed1[ul].xx)-max(left,ed1[ul].x);
if(tmp>eps)
{
double tmpp=tmp*ed1[ul].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
}
if(ret>ans) ans=ret;
}
}
ul=ur=ll=rr=0;
for(register int i=1;i<=cnt2;++i)
{
ret=0;
double left=ed2[i].x,rt=ed2[i].x+l;
ll=i;
while((ed2[rr].xx<rt||!rr)&&rr<cnt2) rr++;
ret+=(summ[rr-1]-summ[i-1]);
double tmp=min(rt,ed2[rr].xx)-max(left,ed2[rr].x);
if(tmp>eps)
{
double tmpp=tmp*ed2[rr].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
}
while((ed1[ul].xx<left||!ul)&&ul<cnt1) ul++;
while((ed1[ur].xx<rt||!ur)&&ur<cnt1) ur++;
// printf("%Lf %Lf %d %d %d %d\n",left,rt,ll,rr,ul,ur);
ret+=max(sum[ur-1]-sum[ul],(double)0);
if(ur==ul)
{
double tmp=min(rt,ed1[ur].xx)-max(left,ed1[ur].x);
if(tmp>eps)
{
double tmpp=tmp*ed1[ur].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
}
if(ret>ans) ans=ret;
}
else
{
double tmp=min(rt,ed1[ur].xx)-max(left,ed1[ur].x);
if(tmp>eps)
{
double tmpp=tmp*ed1[ur].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
}
tmp=min(rt,ed1[ul].xx)-max(left,ed1[ul].x);
if(tmp>eps)
{
double tmpp=tmp*ed1[ul].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
}
if(ret>ans) ans=ret;
}
// cout<<endl<<ret<<endl;
}
}
inline int read()
{
int w=1,s=0;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-') w=-1;
ch=getchar();
}
while(isdigit(ch))
{
s=s*10+ch-'0';
ch=getchar();
}
return w*s;
}
int main(){
// freopen("01.in","r",stdin);
// freopen("laser.out","w",stdout);
cin>>t;
while(t--)
{
set< line1 > st;
ans=0;
curx=0;
n=read();
for(register int i=1;i<=n;++i)
{
int x,y;
x=read(),y=read(); lin[i].x=x,lin[i].y=y;x=read(),y=read();lin[i].xx=x,lin[i].yy=y;
}
int x,y,xx,yy,ll;
x=read();y=read();xx=read();yy=read();ll=read();
model.x=x,model.y=y,model.xx=xx,model.yy=yy;l=ll;
get(model);
double degree;
if(fabs(lne.a)>eps)
degree=atan(lne.a);
if(lne.a==0){
degree=0;
}
if(lne.b==0)
{
degree=pi/2;
}
int cnt1=0,cnt2=0;
for(register int i=1;i<=n;++i)
{
double tx=lin[i].x,ty=lin[i].y;
double lx=lin[i].xx,ly=lin[i].yy;
double a=lne.a,b=lne.b,c=lne.c;
int op=getwhere(tx,ty);
if(op==2)
{
cnt1++;
nw1[cnt1].x=cos(degree)*tx+sin(degree)*ty;
nw1[cnt1].y=abs(a*tx+b*ty+c)/sqrt(a*a+b*b);
nw1[cnt1].xx=cos(degree)*lx+sin(degree)*ly;
nw1[cnt1].yy=abs(a*lx+b*ly+c)/sqrt(a*a+b*b);
nw1[cnt1].k=(nw1[cnt1].yy-nw1[cnt1].y)/(nw1[cnt1].xx-nw1[cnt1].x);
if(nw1[cnt1].xx<nw1[cnt1].x) swap(nw1[cnt1].xx,nw1[cnt1].x),swap(nw1[cnt1].yy,nw1[cnt1].y);
}
if(op==1)
{
cnt2++;
nw2[cnt2].x=cos(degree)*tx+sin(degree)*ty;
nw2[cnt2].y=abs(a*tx+b*ty+c)/sqrt(a*a+b*b);
nw2[cnt2].xx=cos(degree)*lx+sin(degree)*ly;
nw2[cnt2].yy=abs(a*lx+b*ly+c)/sqrt(a*a+b*b);
nw2[cnt2].k=(nw2[cnt2].yy-nw2[cnt2].y)/(nw2[cnt2].xx-nw2[cnt2].x);
if(nw2[cnt2].xx<nw2[cnt2].x) swap(nw2[cnt2].xx,nw2[cnt2].x),swap(nw2[cnt2].yy,nw2[cnt2].y);
}
}
int tot1=0,tot2=0;
for(register int i=1;i<=cnt1;++i)
{
pt1[++tot1].x= nw1[i].x;pt1[tot1].y=nw1[i].y;pt1[tot1].id=1;pt1[tot1].belong=i;
le1[i].aa=pt1[tot1];
pt1[++tot1].x=nw1[i].xx;pt1[tot1].y=nw1[i].yy;pt1[tot1].id=-1;pt1[tot1].belong=i;
le1[i].bb=pt1[tot1];
le1[i].xielv=nw1[i].k;
le1[i].jieju=(nw1[i].y-nw1[i].k*nw1[i].x);
}
for(register int i=1;i<=cnt2;++i)
{
pt2[++tot2].x= nw2[i].x;pt2[tot2].y=nw2[i].y;pt2[tot2].id=1;pt2[tot2].belong=i;
le2[i].aa=pt2[tot2];
pt2[++tot2].x=nw2[i].xx;pt2[tot2].y=nw2[i].yy;pt2[tot2].id=-1;pt2[tot2].belong=i;
le2[i].bb=pt2[tot2];
le2[i].xielv=nw2[i].k;
le2[i].jieju=(nw2[i].y-nw2[i].k*nw2[i].x);
}
sort(pt1+1,pt1+tot1+1,cmpp);
sort(pt2+1,pt2+tot2+1,cmpp);
curx=pt1[1].x;
cnt1=0;
st.insert(le1[pt1[1].belong]);
for(register int i=2;i<=tot1;++i)
{
int tmp=pt1[i].belong;
if(pt1[i].id==1){
if(!st.empty()){
ed1[++cnt1].x=curx,ed1[cnt1].xx=pt1[i].x;line1 qaq=*st.begin();ed1[cnt1].k=qaq.xielv;
}
curx=pt1[i].x;st.insert(le1[tmp]);
}
if(pt1[i].id==-1)
{
if(!st.empty())
{
ed1[++cnt1].x=curx,ed1[cnt1].xx=pt1[i].x;line1 qaq=*st.begin();ed1[cnt1].k=qaq.xielv;
}
curx=pt1[i].x;
st.erase(le1[tmp]);
}
}
curx=pt2[1].x;
cnt2=0;
st.insert(le2[pt2[1].belong]);
for(register int i=2;i<=tot2;++i)
{
int tmp=pt2[i].belong;
if(pt2[i].id==1){if(!st.empty()){ed2[++cnt2].x=curx,ed2[cnt2].xx=pt2[i].x;line1 qaq=*st.begin();ed2[cnt2].k=qaq.xielv;};curx=pt2[i].x;st.insert(le2[tmp]);};
if(pt2[i].id==-1)
{
if(!st.empty())
{
ed2[++cnt2].x=curx,ed2[cnt2].xx=pt2[i].x;line1 qaq=*st.begin();ed2[cnt2].k=qaq.xielv;
}
curx=pt2[i].x;
st.erase(le2[tmp]);
}
}
sort(ed1+1,ed1+cnt1+1,cmppp);
sort(ed2+1,ed2+cnt2+1,cmppp);
work(cnt1,cnt2);
printf("%.15Lf\n",ans);
}
return 0;
}