BZOJ題面php
咱們射箭的函數形如$y=Ax^2+Bx$node
考慮每個靶子$(x_0,y_1,y_2)$,其實是關於$A,B$的不等式限制條件ios
咱們只要求出有沒有$(A,B)$知足全部$2*n$個限制條件就能夠了git
考慮一個限制條件$y_1\leq Ax_0^2+Bx_0\leq y_2$函數
把一個$x_0$除過去,能夠獲得$B$關於$A$的半平面兩個:spa
$B\geq -x_0A+\frac{y_1}{x_0}$code
$B\leq -x_0A+\frac{y_2}{x_0}$htm
實際上就是兩條平行線(不過這個性質沒什麼用)blog
顯然題目具備二分性,二分答案,每次對於前一部分的全部限制作半平面交便可
能夠先把全部半平面(包括四個外圍限制)排個序,而後每次二分求解的時候掃一遍提取出本次求解須要的
半平面交若是能夠剩下一個點(本題是能夠的),須要在判斷點是否在線的右邊的函數裏面修改條件,不能包括點在線上的狀況
半平面交模板參考這道題:全部線段有向,從a到b,半平面交求全部有向線段的左邊半平面的交,外圍框子是逆時針的
同一份半平面交裏面的全部點線關係都是一致的(都是左邊or右邊)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cassert> #include<cmath> #define eps 1e-18 #define inf 1e33 #define ll long long using namespace std; inline int read(){ int re=0,flag=1;char ch=getchar(); while(!isdigit(ch)){ if(ch=='-') flag=-1; ch=getchar(); } while(isdigit(ch)) re=(re<<1)+(re<<3)+ch-'0',ch=getchar(); return re*flag; } inline bool sign(long double x){ if(x>eps) return 1; if(x<-eps) return -1; return 0; } int n,m; struct node{ long double x,y; node(long double xx=0.0,long double yy=0.0){x=xx;y=yy;} inline friend node operator +(const node &a,const node &b){return node(a.x+b.x,a.y+b.y);} inline friend node operator -(const node &a,const node &b){return node(a.x-b.x,a.y-b.y);} inline friend node operator *(const node &a,const long double &b){return node(a.x*b,a.y*b);} inline friend long double operator *(const node &a,const node &b){return a.x*b.y-a.y*b.x;} inline friend long double operator /(const node &a,const node &b){return a.x*b.x+a.y*b.y;} inline friend long double slope(const node &a,const node &b){return atan2l(a.y-b.y,a.x-b.x);} }rt[300010]; struct seg{ node a,b;long double k;int id; seg(node aa=node(),node bb=node()){a=aa;b=bb;k=slope(aa,bb);id=0;} seg(node aa,node bb,long double kk){a=aa;b=bb;k=kk;id=0;} inline friend bool operator <(const seg &a,const seg &b){return a.k<b.k;} inline friend node cross(const seg &a,const seg &b){ long double v1=(a.a-b.b)*(a.b-b.b); long double v2=(a.a-b.a)*(a.b-b.a); return b.b+(b.a-b.b)*(v1/(v1-v2)); } inline friend bool right(const node &a,const seg &b){ return ((a-b.b)*(a-b.a))>eps; } }lis[300010],a[300010],q[300010]; inline bool solve(int lim){ int i,head=1,tail=0,flag,tot=0; for(i=1;i<=m;i++) if(lis[i].id<=lim) a[++tot]=lis[i]; for(i=1;i<=tot;i++){ flag=0; while((head<=tail)&&(!sign(a[i].k-q[tail].k))){ if(right(q[tail].a,a[i])) tail--; else{flag=1;break;} } if(flag) continue; while(head<tail&&right(rt[tail],a[i])) tail--; while(head<tail&&right(rt[head+1],a[i])) head++; q[++tail]=a[i]; if(head<tail) rt[tail]=cross(q[tail],q[tail-1]); } while(head<tail&&right(rt[tail],q[head])) tail--; while(head<tail&&right(rt[head+1],q[tail])) head++; return (tail-head>1); } const long double pi=acos(-1.0); int main(){ n=read();int i;long double x1,y1,y2; m=n<<1; for(i=1;i<=n;i++){ x1=read();y1=read();y2=read(); lis[i]=seg(node(0,y1/x1),node(1,y1/x1-x1)); lis[i+n]=seg(node(1,y2/x1-x1),node(0,y2/x1)); lis[i].id=lis[i+n].id=i; } lis[++m]=seg(node(-1e12,1e12),node(-1e12,-1e12),pi/2.0); lis[++m]=seg(node(1e12,1e12),node(-1e12,1e12),0); lis[++m]=seg(node(1e12,-1e12),node(1e12,1e12),-pi/2.0); lis[++m]=seg(node(-1e12,-1e12),node(1e12,-1e12),pi); sort(lis+1,lis+m+1); int l=1,r=n,mid; while(l<r){ mid=(l+r)>>1;mid++; if(solve(mid)) l=mid; else r=mid-1; } cout<<l<<'\n'; }