bzoj 1007[HNOI2008]水平可见直线 - 半平面交
1007: [HNOI2008]水平可见直线
Time Limit: 1 Sec Memory Limit: 162 MBDescription
在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条直线两两不重合.求出所有可见的直线.
Input
第一行为N(0 < N < 50000),接下来的N行输入Ai,Bi
Output
从小到大输出可见直线的编号,两两中间用空格隔开,最后一个数字后面也必须有个空格
Sample Input
3
-1 0
1 0
0 0
-1 0
1 0
0 0
Sample Output
1 2
可以想象最终在上面的图形是一个半凸包
所以只需要按照斜率排序
将前面的直线都推到一个栈里
如果新加入的直线和栈顶直线交点在之前交点的左面
那么凸包栈顶的直线就被覆盖了,弹出就可以了
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define LL long long 6 7 using namespace std; 8 9 const int MAXN = 5e4 + 10; 10 11 int N; 12 int top = 0; 13 int ans[MAXN]; 14 int sta[MAXN]; 15 double x[MAXN]; 16 17 struct line { 18 double k; 19 double b; 20 int id; 21 } l[MAXN]; 22 23 bool cmp(line a, line b) 24 { 25 if(a.k == b.k) { 26 return a.b > b.b; 27 } 28 return a.k < b.k; 29 } 30 31 inline LL read() 32 { 33 LL x = 0, w = 1; char ch = 0; 34 while(ch < '0' || ch > '9') { 35 if(ch == '-') { 36 w = -1; 37 } 38 ch = getchar(); 39 } 40 while(ch >= '0' && ch <= '9') { 41 x = x * 10 + ch - '0'; 42 ch = getchar(); 43 } 44 return x * w; 45 } 46 47 double intersaction(int a, int b) 48 { 49 return (l[b].b - l[a].b) / (l[a].k - l[b].k); 50 } 51 int main() 52 { 53 N = read(); 54 for(int i = 1; i <= N; i++) { 55 scanf("%lf%lf", &l[i].k, &l[i].b); 56 l[i].id = i; 57 } 58 sort(l + 1, l + N + 1, cmp); 59 sta[0] = 1; 60 top = 1; 61 for(int i = 2; i <= N; i++) { 62 if(l[i].k == l[sta[top - 1]].k) { 63 continue; 64 } 65 while(intersaction(i, sta[top - 1]) <= intersaction(sta[top - 1], sta[top - 2]) && top > 1) { 66 top--; 67 } 68 top++; 69 sta[top - 1] = i; 70 } 71 for(int i = 0; i < top; i++) { 72 ans[l[sta[i]].id] = 1; 73 } 74 for(int i = 1; i <= N; i++) { 75 if(ans[i]) { 76 printf("%d ", i); 77 } 78 } 79 return 0; 80 }