洛谷P3194 [HNOI2008]水平可见直线(计算几何+单调栈)
原题链接
思路:
答案是最上面的一些直线,借助于求凸包的思想,单调栈维护答案,即不被其他直线覆盖的点。
1.排序:第一关键字斜率,第二关键字截距。斜率从小到大,截距从大到小。因为相同斜率的话,截距小的会被截距大的覆盖。
2.单调栈维护:考虑何时弹出栈顶元素。假设栈内有的直线为
l
i
n
e
1
,
l
i
n
e
2
line1,line2
line1,line2,新添加的直线为
l
i
n
e
3
line3
line3.看
l
i
n
e
2
line2
line2在哪种情况下被覆盖。
当A在B的左边时,从上向下看,
l
i
n
e
2
line2
line2被覆盖,弹出栈。
很像凸包的思想。
代码:
struct node{
int a,b,id;
}line[maxn],stk[maxn];
int n,top;
bool cmp(node a,node b){
if(a.a==b.a) return a.b>b.b;
return a.a<b.a;
}
bool cmp1(node a,node b){
return a.id<b.id;
}
double cul(node a,node b){
return 1.0*(b.b-a.b)/(a.a-b.a);
}
int main(){
n=read;
for(int i=1;i<=n;i++){
line[i].a=read,line[i].b=read,line[i].id=i;
}
sort(line+1,line+1+n,cmp);
stk[++top]=line[1];
for(int i=2;i<=n;i++){
if(line[i].a==line[i-1].a) continue;
while(top>1&&cul(line[i],stk[top])<=cul(stk[top],stk[top-1])) top--;
stk[++top]=line[i];
}
sort(stk+1,stk+1+top,cmp1);
for(int i=1;i<=top;i++) cout<<stk[i].id<<" ";
return 0;
}