卧薪尝胆,厚积薄发。
HNOI2008 水平可见直线
Date: Sun Dec 09 15:40:59 CST 2018 In Category: NoCategory

Description:

给出 $n$ 条直线,求哪些直线存在一部分没有被任何其他直线覆盖。
$1\leqslant n\leqslant 50000$

Solution:

像求凸包那样维护一个斜率单调的栈,如果栈顶和栈顶第二个的交点在当前线段下方,那么说明这个栈顶肯定看不到,于是不停弹栈,最后在栈中的就是可以看到的。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<vector>
#include<cctype>
#include<cstring>
using namespace std;
int n;
#define MAXN 50010
struct line
{
double k,b;
vector<int> id;
}l_[MAXN],l[MAXN];
bool cmp_k(line a,line b){return a.k < b.k;}
line stack[MAXN];
int top = 0;
struct point
{
double x,y;
};
point intersection(line x,line y)
{
point res;
res.x = (x.b - y.b) / (y.k - x.k);
res.y = res.x * x.k + x.b;
return res;
}
bool under(point k,line l)
{
return (k.x * l.k + l.b >= k.y - 1e-8);
}
int ans[MAXN];
bool equal(double a,double b){return fabs(a - b) <= 1e-10;}
int main()
{
scanf("%d",&n);
for(int i = 1;i <= n;++i)scanf("%lf%lf",&l_[i].k,&l_[i].b);
for(int i = 1;i <= n;++i)l_[i].id.push_back(i);
sort(l_ + 1,l_ + 1 + n,cmp_k);
int cnt = 0;
for(int i = 1;i <= n;++i)
{
if(cnt == 0)l[++cnt] = l_[i];
else if(!equal(l[cnt].k,l_[i].k))l[++cnt] = l_[i];
else if(equal(l_[i].b,l[cnt].b))l[cnt].id.push_back(l_[i].id[0]);
else if(l_[i].b > l[cnt].b)l[cnt] = l_[i];
}
for(int i = 1;i <= n;++i)
{
while(top >= 2 && under(intersection(stack[top],stack[top - 1]),l[i]))--top;
stack[++top] = l[i];
}
int tot = 0;
for(int i = 1;i <= top;++i)
for(int j = 0;j < stack[i].id.size();++j)ans[++tot] = stack[i].id[j];
sort(ans + 1,ans + 1 + tot);
for(int i = 1;i <= tot;++i)printf("%d ",ans[i]);cout << endl;
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡