列表

详情


NC20066. [HNOI2008]水平可见直线

描述

在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条直线两两不重合.求出所有可见的直线.

输入描述

第一行为N(0 < N < 50000),接下来的N行输入Ai,Bi

输出描述

从小到大输出可见直线的编号,两两中间用空格隔开,最后一个数字后面也必须有个空格

示例1

输入:

3
-1 0
1 0
0 0

输出:

1 2

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 36ms, 内存消耗: 11488K, 提交时间: 2019-08-18 12:45:07

#include<bits/stdc++.h>
//CLOCKS_PER_SEC
#define se second
#define fi first
#define ll long long
#define Pii pair<int,int>
#define Pli pair<ll,int>
#define ull unsigned long long
#define ALL(x) x.begin(),x.end()
#define pb push_back
#define mp make_pair
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
const int N=1e5+10;
const int INF=0x3f3f3f3f;
const int mod=1e9+7;
using namespace std;
typedef double db;
const db eps=1e-6;
const db pi=acos(-1);
int sign(db k){
    if (k>eps) return 1; else if (k<-eps) return -1; return 0;
}
int cmp(db k1,db k2){return sign(k1-k2);}
int inmid(db k1,db k2,db k3){return sign(k1-k3)*sign(k2-k3)<=0;}// k3 在 [k1,k2] 内
struct point{
    db x,y;
    point (db x=0, db y=0):x(x),y(y){}
    point operator + (const point &k1) const{return (point){k1.x+x,k1.y+y};}
    point operator - (const point &k1) const{return (point){x-k1.x,y-k1.y};}
    point operator * (db k1) const{return (point){x*k1,y*k1};}
    point operator / (db k1) const{return (point){x/k1,y/k1};}
    int operator == (const point &k1) const{return cmp(x,k1.x)==0&&cmp(y,k1.y)==0;}
    // 逆时针旋转  k1为弧度
    point turn(db k1){return (point){x*cos(k1)-y*sin(k1),x*sin(k1)+y*cos(k1)};}
    point turn90(){return (point){-y,x};}
    bool operator < (const point k1) const{
        int a=cmp(x,k1.x);
        if (a==-1) return 1; else if (a==1) return 0; else return cmp(y,k1.y)==-1;
    }
    db abs(){return sqrt(x*x+y*y);}
    db abs2(){return x*x+y*y;}
    db dis(point k1){return ((*this)-k1).abs();}
    point unit(){db w=abs(); return (point){x/w,y/w};}
    void scan(){double k1,k2; scanf("%lf%lf",&k1,&k2); x=k1; y=k2;}
    void print(){printf("%.11lf %.11lf",x,y);}
    db getw(){return atan2(y,x);} //极角
    point getdel(){if (sign(x)==-1||(sign(x)==0&&sign(y)==-1)) return (*this)*(-1); else return (*this);}
    int getP() const{return sign(y)==1||(sign(y)==0&&sign(x)==-1);}
};
int inmid(point k1,point k2,point k3){return inmid(k1.x,k2.x,k3.x)&&inmid(k1.y,k2.y,k3.y);}//判断k3在k1和k2组成的矩形里面
db cross(point k1,point k2){return k1.x*k2.y-k1.y*k2.x;}
db dot(point k1,point k2){return k1.x*k2.x+k1.y*k2.y;}
db rad(point k1,point k2){return atan2(cross(k1,k2),dot(k1,k2));}//有方向
int clockwise(point k1,point k2,point k3){// k1 k2 k3 逆时针 1 顺时针 -1 否则 0
    return sign(cross(k2-k1,k3-k1));
}
int onS(point k1,point k2,point q){return inmid(k1,k2,q)&&sign(cross(k1-q,k2-k1))==0;}

db area(vector<point> A){ // 多边形用 vector<point> 表示 , 逆时针输入返回正,否则为负
    db ans=0;
    for (int i=0;i<A.size();i++) ans+=cross(A[i],A[(i+1)%A.size()]);
    return ans/2;
}
int intersect(db l1,db r1,db l2,db r2){
    if (l1>r1) swap(l1,r1); if (l2>r2) swap(l2,r2); return cmp(r1,l2)!=-1&&cmp(r2,l1)!=-1;
}

point getLL(point k1,point k2,point k3,point k4){
    db w1=cross(k1-k3,k4-k3),w2=cross(k4-k3,k2-k3); return (k1*w2+k2*w1)/(w1+w2);
}
int checkSS(point k1,point k2,point k3,point k4){//线段和线段  若将两个<=改成< 则为非严格相交
    return intersect(k1.x,k2.x,k3.x,k4.x)&&intersect(k1.y,k2.y,k3.y,k4.y)&&
    sign(cross(k3-k1,k4-k1))*sign(cross(k3-k2,k4-k2))<0&&
    sign(cross(k1-k3,k2-k3))*sign(cross(k1-k4,k2-k4))<0;
}
struct li{
    db k, b;
    int id;
    point x, y;
    bool operator < (const li &oth) const{
        if(k == oth.k){
            return b > oth.b;
        }
        return k < oth.k;
    }
}p[N];
li sta[N];

bool check(li x, li y, li z){
    point a = getLL(x.x, x.y, z.x, z.y);
    point l1 = y.x, l2 = y.y;
    point vec = l2 - l1;
    l1 = l1 - vec*100000;
    l2 = l2 + vec*100000;
    if(l1.x < l2.x) swap(l1, l2);
    if(onS(l1, l2, a) || clockwise(a, l1, l2) == 1) return 1;
    return 0;
}
int main(){
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i){
        scanf("%lf%lf", &p[i].k, &p[i].b);
        p[i].id = i;
        p[i].x = point(0, p[i].b);
        if(p[i].k)p[i].y = point(1.0*p[i].k, p[i].k*p[i].k+p[i].b);
        else p[i].y = point(1, p[i].b);
    }
    sort(p+1, p+1+n);
    int top = 1;
    sta[top] = p[1];
    for(int i = 2; i <= n; ++i){
        if(p[i].k == p[i-1].k) continue;
        while(top >= 2 && check(sta[top], sta[top-1], p[i])) top--;
        sta[++top] = p[i];
    }
    vector<int>ans;
    for(int i = 1; i <= top; ++i) ans.pb(sta[i].id);
    sort(ALL(ans));
    for(auto i : ans){
        printf("%d ", i);
    }
    return 0;
}

C++ 解法, 执行用时: 41ms, 内存消耗: 920K, 提交时间: 2021-10-09 20:34:51

#include <map>
#include <set>
#include <cmath>
#include <stack>
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long

struct Line
{
    int a, b, id;
} line[50010];

bool cmp(Line x, Line y)
{
    return x.a != y.a ? x.a > y.a : x.b > y.b;
}

int top, ans[50010], st[50010];

double calc(int x, int y)
{
    return (double)(line[x].b - line[y].b) /
           (double)(line[y].a - line[x].a);
}

int main()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> line[i].a >> line[i].b;
        line[i].id = i;
    }
    sort(line + 1, line + n + 1, cmp);

    for (int i = 1; i <= n; i++)
    {
        if (line[i].a == line[i - 1].a && i != 1)
            continue;
        while (top > 1 && calc(st[top], i) >= calc(st[top], st[top - 1]))
            top--;
        st[++top] = i;
        ans[top] = line[i].id;
    }
    sort(ans + 1, ans + top + 1);
    for (int i = 1; i <= top; i++)
        cout << ans[i] << ' ';
}

上一题