题目
http://www.lydsy.com/JudgeOnline/problem.php?id=2732
题解
根据题意设出方程
y=ax2+bx(a<0,b>0)
,那么对于一条线段,通过它的条件就是
{ ax2+bx≥y1 ax2+bx≤y2
变形
{ b≥y1x−ax b≤y2x−ax
建立关于
a
和
就是看最多前多少个方程能被满足,很显然可行性是满足单调性的,所以二分答案,然后
O(log2N)
来判断是否可行。可行就是半平面交之后队列里至少有两个元素。
这样的话,总的时间复杂度是
O(N(log2N)2)
,OJ上会T。
考虑半平面交算法,我记得书上有句话“算法的瓶颈在于排序”,那么我们发现我们进行了很多重复的排序,可以直接在最开始先排好,每次扫描的时候只把“原来的序号<=二分的答案”这样的半平面进行半平面交就行了。
复杂度
O(Nlog2N)
代码
//半平面交
#include <cstdio>
#include <algorithm>
#include <cmath>
#define maxn 300000
#define inf 1e10
using namespace std;
struct point{double x,y;};
struct vec
{
point a, b;
double th;
int id;
double operator*(vec v)
{
double x1=b.x-a.x, y1=b.y-a.y, x2=v.b.x-v.a.x, y2=v.b.y-v.a.y;
return x1*y2-x2*y1;
}
void calcth(){th=atan2(b.y-a.y,b.x-a.x);}
}seg[maxn], q[maxn];
int N, cnt;
bool in(point p, vec v)
{return (vec){v.a,p}*v<0;}
bool cmp(vec v1, vec v2)
{return v1.th==v2.th?in(v1.a,v2):v1.th<v2.th;}
point cross(vec v1, vec v2)
{
double k1, k2, b1, b2, x, y;
k1=(v1.b.y-v1.a.y)/(v1.b.x-v1.a.x);
k2=(v2.b.y-v2.a.y)/(v2.b.x-v2.a.x);
b1=-k1*v1.a.x+v1.a.y;
b2=-k2*v2.a.x+v2.a.y;
if(v1.b.x==v1.a.x)x=v1.a.x,y=k2*x+b2;
else if(v2.b.x==v2.a.x)x=v2.a.x,y=k1*x+b1;
else x=(b2-b1)/(k1-k2),y=k1*x+b1;
return (point){x,y};
}
void input()
{
int i, j;
double x, y1, y2;
scanf("%d",&N);
for(i=2;i<=N+1;i++)
{
scanf("%lf%lf%lf",&x,&y1,&y2);
seg[i<<1]=(vec){(point){1,y1/x-x},(point){2,y1/x-2*x}};
seg[(i<<1)+1]=(vec){(point){2,y2/x-2*x},(point){1,y2/x-x}};
seg[i<<1].id=seg[(i<<1)+1].id=i-1;
}
seg[0]=(vec){(point){0,0},(point){0,inf}};
seg[1]=(vec){(point){0,inf},(point){-inf,inf}};
seg[2]=(vec){(point){-inf,inf},(point){-inf,0}};
seg[3]=(vec){(point){-inf,0},(point){0,0}};
for(i=0;i<=(N+1<<1)+1;i++)seg[i].calcth();
}
bool hpi(int n)
{
if(n==0)return true;
int i, l, r;
l=0,r=-1;
for(i=0;i<=cnt and l>=r;i++)if(seg[i].id<=n)q[++r]=seg[i];
for(i++;i<=cnt;i++)
{
if(seg[i].id>n)continue;
while(l<r and !in(cross(q[r],q[r-1]),seg[i]))r--;
while(l<r and !in(cross(q[l],q[l+1]),seg[i]))l++;
q[++r]=seg[i];
}
while(l<r and !in(cross(q[r],q[r-1]),q[l]))r--;
while(l<r and !in(cross(q[l],q[l+1]),q[r]))l++;
return l<r;
}
int bins()
{
int l, r, mid, i;
sort(seg,seg+(N+1<<1)+2,cmp);
for(i=1;i<=(N+1<<1)+1;i++)if(seg[i].th!=seg[i-1].th)seg[++cnt]=seg[i];
l=0,r=N,mid=l+r+1>>1;
while(l<r)
{
if(hpi(mid))l=mid;
else r=mid-1;
mid=l+r+1>>1;
}
return l;
}
int main()
{
input();
printf("%d\n",bins());
return 0;
}