CF1016E Rest In The Shades
给出第四象限的线段 \(AB:y=s_y(a\le x\le b)\) 还有 \(x\) 轴正半轴上 \(n\) 条不相交的线段 \(L_iR_i:y_i=0(l_i\le x\le r_i)\),以及 \(q\) 个第一象限的整点 \(P_i(x_i,y_i)\),有一动点 \(Q\) 在 \(AB\) 上,速度为 \(1\) 单位每秒。称点 \(P_i\) 在阴影内,当且仅当 \(P_iQ\) 与任意一条 \(L_jR_j\) 相交。求 \(Q\) 运动过程中,每个点在阴影内的时间。
\(n,q\le2\times 10^5\)。
记从 \(x\) 轴左到右第 \(i\) 个端点为 \(p_i\)。
显然可以先算出挡住一个点的线段的总长度,然后平行线之间相似算对应 \(Q\) 的路程以及时间。考虑 \(Q\) 位于端点的情况,用待定系数法算出对应的 \(P_iA,P_iB\) 与 \(x\) 轴的交点 \(x_1,x_2\),然后就是求 \([x_1,x_2]\) 与栅栏的交。先二分出完全包含在 \([x_1,x_2]\) 内的左右两个端点 \(ql,qr\)。设 \(s_i\) 为 \(x\) 轴上 \(x\in [0,p_i]\) 区间内线段总长,因为线段不相交所以若 \(p_i\) 为左端点,则 \(s_i=s_{i-1}\);否则 \(s_i=s_{i-1}+r_{\frac{i}{2}}-l_{\frac{i}{2}}\)。那么可以先计算 \([ql,qr]\) 内的长度为 \(s_{qr}-s_{ql}\)。最后判一下 \(ql,qr\) 是左端点还是右端点,以 \(ql\) 为例,如果 \(ql\) 是右端点,则 \([x_1,ql]\) 也是被线段覆盖的,需要计算上。另一边同理。
时间复杂度为 \(\mathcal{O}(q\log n)\),空间复杂度为 \(\mathcal{O}(n+q)\)。开了一堆 double,所以很慢。
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+5;
int n,q,cnt;
double sy,a,b,s[N],p[N];
double jiaox(double u,double v,double p,double q){
return u==p?u:u-v*(p-u)/(q-v);
}
signed main(){
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(0);
cin>>sy>>a>>b>>n;
for(int i=1,l,r;i<=n;++i){
cin>>l>>r;
p[++cnt]=l;
s[cnt]=s[cnt-1];
p[++cnt]=r;
s[cnt]=s[cnt-1]+r-l;
}
cin>>q;
for(int i=1;i<=q;++i){
double x,y;
cin>>x>>y;
double l=jiaox(a,sy,x,y),r=jiaox(b,sy,x,y);
int ql=lower_bound(p+1,p+1+cnt,l)-p,qr=upper_bound(p+1,p+cnt+1,r)-p-1;
if(ql>qr){
cout<<fixed<<setprecision(16)<<(qr&1?b-a:0)<<'\n';
}else{
cout<<fixed<<setprecision(16)<<(s[qr]-s[ql]+(ql&1?0:p[ql]-l)+(qr&1?r-p[qr]:0))*(b-a)/(r-l)<<'\n';
}
}
return 0;
}

浙公网安备 33010602011771号