BZOJ好像刷了十几道题了,虽然人这么弱,代码也丑,今天还是找几道有价值的整理一下算了。
1193: [HNOI2008]水平可见直线
Time Limit: 1 Sec Memory Limit: 162 MB
Description
在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入队。
然后根据对于当前队中最后一个元素i,找出其与i+1~n中交点最靠前(同样靠前就找斜率最大的)的点入队,直到不能放了为止。。。乱搞一通
#include <iostream> #include <string.h> #include <stdio.h> using namespace std; #define N 50005 int n,a[N][3]; bool b[N]; long long x1,y1,x2,y2; void Sort(int x,int y) { int l=x,r=y,mid=a[(x+y)/2][1],e; do { while (a[l][1]<mid) l++; while (a[r][1]>mid) r--; if (l<=r) { e=a[l][1];a[l][1]=a[r][1];a[r][1]=e; e=a[l][2];a[l][2]=a[r][2];a[r][2]=e; e=a[l][0];a[l][0]=a[r][0];a[r][0]=e; l++;r--; } } while (l<=r); if (l<y) Sort(l,y); if (x<r) Sort(x,r); return; } bool Cpr(long long x,long long y,long long z) { x1=a[z][2]-a[x][2];
y1=a[x][1]-a[z][1];
x2=a[z][2]-a[y][2];
y2=a[y][1]-a[z][1]; if (y1<0) { x1=-x1;
y1=-y1; } if (y2<0) { x2=-x2;
y2=-y2; } if (x1*y2<x2*y1)
return true; if (x1*y2==x2*y1&&a[x][1]>a[y][1])
return true; return false; } int main() { long long i,j,k,l,q,w,e,t; memset(a,0,sizeof(a));memset(b,0,sizeof(b)); scanf("%d",&n); for (i=1;i<=n;i++) { scanf("%d%d",&a[i][1],&a[i][2]); a[i][0]=i; } Sort(1,n); q=1; for (i=2;i<=n;i++) { if (a[q][1]<a[i][1]) { q++;
a[q][0]=a[i][0];
a[q][1]=a[i][1];
a[q][2]=a[i][2]; }else if (a[q][2]<a[i][2]) { a[q][0]=a[i][0];
a[q][1]=a[i][1];
a[q][2]=a[i][2]; } } n=q;
b[a[1][0]]=1; t=2; while (t<=n) { q=t; for (i=t+1;i<=n;i++) if (Cpr(i,q,t-1))
q=i; b[a[q][0]]=1;
t=q+1; } for (i=1;i<=N;i++) if (b[i])
printf("%d ",i); printf("\n"); return 0; }