【计算几何】洛谷 P3194 [HNOI2008] 水平可见直线

正无穷处向下看时,你只能看到在每个 x 位置上 y 值最大的那条直线,所以维护上凸包即可求解。

#include <bits/stdc++.h>

// from: cpp.json
#define INF 8e18
#define int long long
using namespace std;

#define LD long double

struct Line {
    LD A, B;
    int idx;
};

LD intersectX(const Line &l1, const Line &l2) {
    return (l2.B - l1.B) / (l1.A - l2.A);
}

void solve() {
    int n;
    cin >> n;

    vector<Line> ls(n);
    for (int i = 0; i < n; i++) {
        cin >> ls[i].A >> ls[i].B;
        ls[i].idx = i + 1;
    }

    ranges::sort(ls, [&](auto &l1, auto &l2) {
        if (l1.A != l2.A) {
            return l1.A < l2.A;
        }
        return l1.B > l2.B;
    });

    vector<Line> hull;
    vector<LD> xs;
    for (auto &L : ls) {
        if (!hull.empty() && fabsl(L.A - hull.back().A) < 1e-18) {
            continue;
        }
        while (!hull.empty()) {
            LD x = intersectX(hull.back(), L);
            if (x <= xs.back()) {
                hull.pop_back();
                xs.pop_back();
            } else {
                break;
            }
        }
        LD start = hull.empty() ? -INF : intersectX(hull.back(), L);
        hull.push_back(L);
        xs.push_back(start);
    }

    vector<int> ans;
    for (auto &l : hull) {
        ans.push_back(l.idx);
    }
    ranges::sort(ans);

    for (auto id : ans) {
        cout << id << ' ';
    }
    cout << '\n';
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    solve();

    return 0;
}
posted @ 2025-07-26 08:59  カガリ  阅读(42)  评论(0)    收藏  举报