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

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; }