[luogu3222]射箭

假设抛物线为$y=ax^{2}+bx$,二分枚举答案后,每个靶子的限制即半平面

换言之,问题即对这些半平面求交(是否为空),需注意$a\le 0$和$b\ge 0$的自身限制

关于半平面交,与凸包(指维护直线极值)类似,具体流程如下:

1.用点+向量的形式描述直线(规定其左侧为可行区域),并加入足够大的外边框

2.将所有直线按向量极角排序,并对同极角的直线仅保留最左侧的一条

3.维护一个队列,不断弹出队尾/队首,直至队尾/队首两直线交点在当前直线左侧

(注意:要优先处理队尾,反例即应仅保留队首时,若优先处理队首会仅保留队尾)

4.最终,不断弹出队尾,直至队尾两直线交点在队首左侧

时间复杂度为$o(n\log n)$(排序可以预处理),可以通过

另外,精度要求较高,以下代码仅供参考

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 200005
 4 #define eps 1e-18
 5 #define ld long double
 6 #define y1 y11
 7 int n,m,l,r,rk[N];ld x,y1,y2;
 8 struct Point{
 9     ld x,y;
10     Point operator + (const Point &k)const{
11         return Point{x+k.x,y+k.y};
12     }
13     Point operator - (const Point &k)const{
14         return Point{x-k.x,y-k.y};
15     }
16     Point operator * (const ld &k)const{
17         return Point{x*k,y*k};
18     }
19     ld operator * (const Point &k)const{
20         return x*k.y-y*k.x;
21     }
22 }P[N];
23 struct Line{
24     ld z;Point k,v;
25     Line(){}
26     Line(ld a,ld b,ld c){
27         if (fabsl(a)>eps)k=Point{c/a,0};
28         else k=Point{0,c/b};
29         z=atan2l(-a,b),v=Point{b,-a};
30     }
31     bool operator < (const Line &n)const{
32         if (fabsl(z-n.z)>eps)return z<n.z;
33         return (n.k-k)*v>0;
34     }
35 }a[N],q[N];
36 bool cmp(int x,int y){
37     return a[x]<a[y];
38 }
39 Point get_cross(Line x,Line y){
40     return x.k+x.v*(((y.k-x.k)*y.v)/(x.v*y.v));
41 }
42 bool check(int k){
43     l=1,r=0;
44     for(int i=1;i<=m;i++)
45         if (rk[i]<=k){
46             if ((l<=r)&&(fabsl(a[rk[i]].z-q[r].z)<eps))continue;
47             while ((l<r)&&((P[r]-a[rk[i]].k)*a[rk[i]].v)>0)r--;
48             while ((l<r)&&((P[l+1]-a[rk[i]].k)*a[rk[i]].v)>0)l++;
49             q[++r]=a[rk[i]];if (l<r)P[r]=get_cross(q[r],q[r-1]);
50         }
51     while ((l<r)&&((P[r]-q[l].k)*q[l].v)>0)r--;
52     return l+1<r;
53 }
54 int main(){
55     scanf("%d",&n);
56     a[++m]=Line(-1,0,0),a[++m]=Line(0,1,0);
57     a[++m]=Line(1,0,-1e9),a[++m]=Line(0,-1,-1e9);
58     for(int i=1;i<=n;i++){
59         scanf("%Lf%Lf%Lf",&x,&y1,&y2);
60         a[++m]=Line(x,1,y1/x),a[++m]=Line(-x,-1,-y2/x);
61     }
62     for(int i=1;i<=m;i++)rk[i]=i;
63     sort(rk+1,rk+m+1,cmp);
64     int l=0,r=n;
65     while (l<r){
66         int mid=(l+r+1>>1);
67         if (check((mid<<1)+4))l=mid;
68         else r=mid-1;
69     }
70     printf("%d\n",l);
71     return 0;
72 }
View Code

 

posted @ 2022-07-15 19:21  PYWBKTDA  阅读(30)  评论(0编辑  收藏  举报