[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
标签:队尾,ld,射箭,return,Point,operator,const,luogu3222 来源: https://www.cnblogs.com/PYWBKTDA/p/16482593.html