题目大意
给你(n)条直线(y=kx+b),问你从(y)值为正无穷大处往下看能看到那些直线。
(1leq nleq 500000)
题解
如果对于两条直线(l_i,l_j),(k_i=k_j)且(b_i>b_j),那么(l_j)不可能被看见。
把直线按(k)从小到大排序。如果发生了下图的情况(即(l_1)与(l_3)的交点的(x)坐标比(l_2)与(l_3)的交点的(x)坐标小),则(l_2)就不可能被看见。我们可以用栈来维护当前可以看见的直线,如果栈顶那条直线不满足要求,就pop。
时间复杂度:每个点只会入栈一次,出栈一次,所以时间复杂度是(O(n))的。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
struct line
{
double k,b;
int id;
};
line a[500010];
line b[500010];
int cmp(line a,line b)
{
if(a.k!=b.k)
return a.k<b.k;
return a.b<b.b;
}
int q[500010];
int c[500010];
double cross(line a,line b)
{
return (b.b-a.b)/(a.k-b.k);
}
int main()
{
int n;
scanf("%d",&n);
int i;
for(i=1;i<=n;i++)
{
scanf("%lf%lf",&a[i].k,&a[i].b);
a[i].id=i;
}
sort(a+1,a+n+1,cmp);
int m=0;
for(i=1;i<=n;i++)
if(i==n||a[i].k!=a[i+1].k)
b[++m]=a[i];
int t=0;
for(i=1;i<=m;i++)
{
while(t>=2&&cross(b[i],b[q[t-1]])<=cross(b[q[t]],b[q[t-1]])+1e-9)
t--;
q[++t]=i;
}
for(i=1;i<=t;i++)
c[i]=b[q[i]].id;
sort(c+1,c+t+1);
for(i=1;i<=t;i++)
printf("%d ",c[i]);
return 0;
}