BZOJ 1007 [HNOI2008]水平可见直线
没想到自己竟然会做计算几何。。不过这确实是一道水题。
观察发现最后的可见直线是一个凸包。把所有直线按斜率排序,开一个栈存直线,计算当前直线和前一条的交点,若x坐标小于前一个交点则弹栈。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#define INF 1e18
typedef long long LL;
const int maxn=1e5+299;
using namespace std;
int n,r,sta[maxn],ans[maxn];
double k,b;
struct edge{
int id;
double k,b,x,y;
friend bool operator < (const edge&A,const edge&B) {
return (A.k<B.k)||(A.k==B.k&&A.b>B.b);
}
edge(){}
edge(int id,double k,double b):id(id),k(k),b(b){}
}e[maxn];
double cal(int i,int j) {
return (e[i].b-e[j].b)/(e[j].k-e[i].k);
}
void init() {
scanf("%d",&n);
for(int i=1;i<=n;i++) {
scanf("%lf%lf",&k,&b);
e[i]=edge(i,k,b);
}
}
void work() {
sort(e+1,e+n+1);
for(int i=1;i<=n;i++) {
if(r&&e[i].k==e[sta[r]].k) continue;
double xx=cal(sta[r],i);
while(r) {
if(xx>e[sta[r]].x) break;
r--;
xx=cal(sta[r],i);
}
sta[++r]=i;
if(r!=1) e[i].x=xx;
else e[i].x=-INF;
}
for(int i=1;i<=r;i++) ans[e[sta[i]].id]=1;
for(int i=1;i<=n;i++) if(ans[i]) printf("%d ",i);
}
int main()
{
init();
work();
return 0;
}