思路很明显,对于一个确定的v 从第一个线段出发,最多能到达的区间为
(l-((y[i+1]-y[i])*hv*1.0)/v , r+((y[i+1]-y[i])*hv*1.0)/v) 然后与下一个线段相交即可。
那么二分上线就可以了。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <list>
#include <cmath>
#include <sstream>
#include <cctype>
#include <string>
using namespace std;
typedef long long LL;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn = 1e6+100;
int s[maxn],w,hv,n;
double x[maxn],y[maxn];
void intersection(double& x,double& y,double a,double b){
if(y<a||b<x){x=-1;y=-1;}
else if(x<=a&&b<=y) {x=a,y=b;}
else if(a<=x&&y<=b) {x=x,y=y;}
else if(x<=a&&a<=y){x=a;}
else {y=b;}
}
int judge(int v){
double l=x[1],r=x[1]+w;
for(int i=1;i<n;i++){
double pl = l-((y[i+1]-y[i])*hv*1.0)/v;
double pr = r+((y[i+1]-y[i])*hv*1.0)/v;
double tl = x[i+1],tr = x[i+1]+w;
intersection(tl,tr,pl,pr);
if(tl==-1) return 0;
l=tl,r=tr;
}
return 1;
}
int find_max(){
int l=1,r=1e6+1;
while(l<r){
int m=(l+r)>>1;
if(judge(m)) l=m+1;
else r = m;
}
if(l==1 && !judge(l)) return 0;
return l-1;
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d %d %d",&w,&hv,&n);
for(int i=1;i<=n;i++){
scanf("%lf %lf",&x[i],&y[i]);
}
int M;
scanf("%d",&M);
for(int i=0;i<M;i++) scanf("%d",&s[i]);
sort(s,s+M);
int ok = 0;
int max_ = find_max();
for(int i=M-1;i>=0;i--)
if(s[i]<=max_){ok=1; printf("%d\n",s[i]); break;}
if(!ok) printf("IMPOSSIBLE\n");
}
}
/*
2
3 2 3
1 1
5 2
1 3
3
3
2
1
3 2 3
1 1
5 2
1 3
1
*/