CF1016ERestInShades题解--二分+几何

CF1016ERest In Shades题解—二分+几何

题目链接

https://cn.vjudge.net/problem/CodeForces-1016E

分析

我们将固定的点视作光源,实际上就是求点与轨迹端点连线之间在$x$轴上不被遮盖的长度,然后运用相似转化即可

维护每个线段之前有多少长度没被遮盖的前缀和,二分得到端点所在或最近的线段就好了

注意二分别写挂以及特判,还要处理两端多出来的部分

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <iostream>
#include <queue>
#define ll lon long
#define ri register int
using std::min;
using std::max;
template <class T>inline void read(T &x){
x=0;int ne=0;char c;
while(!isdigit(c=getchar()))ne=c=='-';
x=c-48;
while(isdigit(c=getchar()))x=x*10+c-48;
x=ne?-x:x;return ;
}
const int maxn=200005;
const double eps=1e-11;
const int inf=0x7fffffff;
struct Seg{
double l,r;
}seg[maxn];
double sum[maxn];
double sy,a,b;
int n,q;
int main(){
scanf("%lf %lf %lf\n",&sy,&a,&b);
sy=-sy;
read(n);
sum[0]=0;
for(ri i=1;i<=n;i++){
read(seg[i].l),read(seg[i].r);
sum[i]=sum[i-1]+(seg[i].r-seg[i].l);
}
sum[n+1]=sum[n];
seg[0].l=seg[0].r=-1926081793.0;
seg[n+1].l=seg[n+1].r=1926081793.0;
read(q);
double x,y,xx,yy;
int L=0,R=n+1;
int px,py;double ans;
while(q--){
read(x),read(y);
xx=x-(x-a)*y/(y+sy),yy=x+(b-x)*y/(y+sy);
L=0,R=n+1,px=0;
if(yy<seg[0].l||xx>seg[n].r){
puts("0.0000000000");
continue;
}
if(eps<seg[0].l-xx)px=0;
else while(L<=R){
int mid=(L+R)>>1;
if(eps<xx-seg[mid].l)L=mid+1,px=mid;
else R=mid-1;
}
L=0,R=n+1,py=n+1;
if(yy-seg[n].r>eps)py=n+1;
else while(L<=R){
int mid=(L+R)>>1;
if(seg[mid].r-yy>eps)R=mid-1,py=mid;
else L=mid+1;
}
ans=sum[py-1]-sum[px]+max(1.0*0,seg[px].r-xx)+max(1.0*0,yy-seg[py].l);
ans=ans*(y+sy)/y;
printf("%.10lf\n",ans);
}
return 0;
}