【BZOJ1007】【HNOI2008】水平可见直线

Description

  
​  传送门
  
  
  
     
  

Solution

  
​  感觉有点套路,反正我想不到。
  
  首先对于斜率相同的直线,显然除了截距最大的一条,其他都是不可见的,直接删去。
  
  观察答案的上表面,它其实是一个由所有可见直线围成的下凸包。
  
  如果将剩余直线按斜率递增作为第一关键字、截距递减按第二关键字排序,并逐个加入,维护下凸包。
  
  类似普通下凸包,我们开一个栈\(s\)表示当前凸包由哪一些直线组成。
  
  新加入一条直线时,首先它在当前局面一定会作为凸包的一部分。但是它的加入导致哪一些直线被覆盖了呢?考虑栈尾直线是否被覆盖,它被覆盖的情况如下:
  
%E3%80%90BZOJ1007%E3%80%91.bmp
  
  即当新直线与\(S_{t-1}\)的交点的\(x\)坐标小于等于\(S_{t-1}\)\(S_{t}\)交点的\(x\)坐标时,\(S_t\)会被覆盖。所以我们不断将被覆盖的直线从队尾弹出,最后加入新直线。
  
  
  
  
  

Code

  

#include <cstdio>
#include <algorithm>
using namespace std;
const int N=50005;
int n;
struct Line{int k,b,id;}a[N];
int sta[N],top;
bool cmp(const Line &u,const Line &v){
    if(u.k!=v.k) return u.k<v.k;
    return u.b>v.b;
}
bool cmp2(const int &u,const int &v){return a[u].id<a[v].id;}
double inter(int i,int j){
    return 1.0*(a[j].b-a[i].b)/(a[i].k-a[j].k); 
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d%d",&a[i].k,&a[i].b),a[i].id=i;
    sort(a+1,a+1+n,cmp);
    int tn=n;
    n=0;
    for(int i=1,j;i<=tn;){
        j=i;    
        a[++n]=a[i];
        for(i++;i<=tn&&a[i].k==a[j].k;i++);
    }
    for(int i=1;i<=n;i++){
        while(top>1&&inter(sta[top-1],i)<=inter(sta[top-1],sta[top]))
            top--;
        sta[++top]=i;                           
    }
    sort(sta+1,sta+1+top,cmp2);
    for(int i=1;i<=top;i++) printf("%d ",a[sta[i]].id);
    return 0;
}

转载于:https://www.cnblogs.com/RogerDTZ/p/9255812.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值