• 【BZOJ1007】【HNOI2008】水平可见直线 几何 单调栈


    题目大意

      给你(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;
    }
    
  • 相关阅读:
    深入理解TCP协议及其源代码
    Socket与系统调用深度分析
    构建调试Linux内核网络代码的环境MenuOS系统
    基于java的socket简单聊天编程
    ping命令研究报告
    什么是JMM?
    ssm框架整合,个人学习记录
    Intellij idea兼容 Eclipse 快捷键 (仅个人学习回顾,防止遗忘)
    java基础随记 持续完善中
    win10 安装Ubuntu子系统 整合排坑
  • 原文地址:https://www.cnblogs.com/ywwyww/p/8510701.html
Copyright © 2020-2023  润新知