题意:
在xoy直角坐标平面上有n条直线L1,L2,…Ln,若在y值为正无穷大处往下看,能见到Li的某个子线段,则称Li为
可见的,否则Li为被覆盖的.
例如,对于直线:
L1:y=x; L2:y=-x; L3:y=0
则L1和L2是可见的,L3是被覆盖的.
给出n条直线,表示成y=Ax+B的形式(|A|,|B|<=500000),且n条直线两两不重合.求出所有可见的直线.
题解:根据题意我们可以想象出最后的图形是一个下凹形的图,如下图:
其中红色线段为可见的线段,我们需要寻找的也是这些红色线段属于哪几条线,我们可以得到斜率最小的和斜率最大的可以一直被看见,然后我们使用单调栈维护一个可以看的直线的栈。
首先我们对直线进行按照斜率排序(从小到大),如果斜率相同那么就按照B从大到小(因为斜率相同的情况下,B大的能够盖住B小的),然后我们发现如果新加进来的一条直线如果能够盖住栈顶的直线的话那么,他与栈顶元素的交点x坐标要小于栈顶两个直线的焦点,所以我们根据这个东西可以维护一下
a c c o d e : ac\ code: ac code:
/**************************************************************
Problem: 1007
User: ReJ
Language: C++
Result: Accepted
Time:264 ms
Memory:3664 kb
****************************************************************/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define met(a, b) memset(a, b, sizeof(a))
#define rep(i, a, b) for(int i = a; i <= b; i++)
#define per(i, a, b) for(int i = a; i >= b; i--)
#define fi first
#define se second
const int maxn = 1e5 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
struct Line {
double A, B;
int id;
void read(int _id) {
id = _id;
scanf("%lf%lf", &A, &B);
}
bool operator < (const Line & b) const {
return A == b.A ? B > b.B : A < b.A;
}
} line[maxn];
inline double cal(Line a, Line b) {
return (a.B - b.B) / (b.A - a.A);
}
int main() {
int n;
scanf("%d", &n);
rep(i, 1, n) line[i].read(i);
sort(line + 1, line + 1 + n);
int sta[maxn], top =0;
sta[++top] = 1;
rep(i, 1, n) {
if(fabs(line[i].A - line[i - 1].A) < eps)continue;
while(top > 1 && cal(line[i], line[sta[top]]) <= cal(line[sta[top]], line[sta[top - 1]])) top--;
sta[++top] = i;
}
bool vis[maxn];
met(vis, false);
rep(i, 1, top) vis[line[sta[i]].id] = true;
rep(i, 1, n) {
if(vis[i]) printf("%d ", i);
}
puts("");
return 0;
}