题目:
给出若干直线
y
=
k
x
+
b
y=kx+b
y=kx+b,当从上往下看时,求所有可见的直线
或者可以理解为一堆直线里 最上面的的那些直线
题解:
发现这些直线是下凸的,并且斜率递增
n
a
m
o
namo
namo求个下凸包即可,按照
k
k
k 从小到大,
b
b
b 从大到小的顺序 排序
设栈顶的两条直线为
q
[
t
a
i
l
−
1
]
q[tail-1]
q[tail−1] 和
q
[
t
a
i
l
]
q[tail]
q[tail],当前直线为
l
[
i
]
l[i]
l[i]
若
q
[
t
a
i
l
−
1
]
q[tail-1]
q[tail−1] 与
q
[
t
a
i
l
]
q[tail]
q[tail] 的交点为
x
1
x_1
x1,
q
[
t
a
i
l
]
q[tail]
q[tail] 与
l
[
i
]
l[i]
l[i] 的交点为
x
2
x_2
x2
若
x
1
>
=
x
2
x_1 >= x_2
x1>=x2,则可以弹栈了
特殊的,当斜率相等时,肯定截距越大越好
时间复杂度:
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
const int maxn = 2e5 + 5;
int n;
struct Line{
int k, b, id;
bool operator < (const Line &A) const {
return k==A.k ? b>A.b : k<A.k;
}
} l[maxn], q[maxn];
double find(Line x, Line y){
return 1.0 * (y.b - x.b) / (x.k - y.k);
}
signed main() {
scanf("%d", &n);
for(int i=1; i<=n; i++) scanf("%d%d", &l[i].k, &l[i].b), l[i].id = i;
sort(l+1, l+1+n);
int tail = 0;
for(int i=1; i<=n; i++){
if(l[i].k == l[i-1].k && i != 1) continue;
while(tail>1 && find(l[i], q[tail])<=find(q[tail-1], q[tail])) tail--;
q[++tail] = l[i];
}
vector <int> ans;
for(int i=1; i<=tail; i++) ans.push_back(q[i].id);
sort(ans.begin(), ans.end());
for(auto i : ans) printf("%d ", i);
}