Soluție HackerRank pentru Geometry Queries, subdomeniul Geometry, în C++14. Include cerința formatată, exemple, explicația pașilor și cod sursă.

  • Problemă: Geometry Queries
  • Domeniu: Geometry
  • Limbaj: C++14

Challenge: Geometry Queries

Scor cont: 100.0 / 100

Submission status: Accepted

Submission score: 1.0

Submission ID: 464814878

Limbaj: cpp14

Link challenge: https://www.hackerrank.com/challenges/geometry-queries/problem

Cerință

There are N lines. Each line has an index between 1 and N. The slope of each line is negative, i.e. it goes from upper-left to lower-right.

There are Q queries. Each of them is in the format `L R x y`, and you should output whether there is any line with index between L and R and the point (x, y) is under it. If there is, then the answer is `YES`, otherwise `NO`.

As you know, any line splits an infinite plane into two regions. The point (x,y) is under the line if that point is at the same region with point (-∞, -∞). If the point lies on the line it does not count.

Input Format
The first line contains N, the number of lines. The following N lines each contains two integers m and n that describes the line mx + n = y.

The next line contains Q, the number of queries. Each subsequent line contains 4 integers L, R, x, y.

Output Format
For each query, output one line containing either `YES` or `NO`.

Constraints
1 ≤ N ≤ 10^5 (Number of lines)
1 ≤ Q ≤ 10^5 (Number of queries)
-10^9 ≤ x ≤ 10^9
-10^9 ≤ y ≤ 10^9
-10^9 ≤ m < 0
-10^9 ≤ n ≤ 10^9
1 ≤ L ≤ R ≤ N

Sample Input

2
-1 3
-2 -4
3
1 2 0 0
1 1 0 0
2 2 0 0

Sample Output

YES
YES
NO

Explanation
The image shows the two lines of the sample input.

<a href="http://hizliresim.com/JEYqEQ">

Ilustrație pentru problemă

</a>

<sub>Time Limits: C/C++ 1 sec, Java/C# 2 sec, other languages follow standard TL given in [Environment](https://hackerrank.com/environment)</sub>

Cod sursă

#include <bits/stdc++.h>
using namespace std;

struct Line {
    long long m, b; // y = m*x + b
};

static inline __int128 eval128(const Line& l, long long x) {
    return (__int128)l.m * x + l.b;
}

// Given sorted by slope increasing and unique slope, build upper hull.
static vector<Line> buildHull(const vector<Line>& lines) {
    vector<Line> hull;
    hull.reserve(lines.size());
    auto bad = [&](const Line& a, const Line& b, const Line& c) -> bool {
        // x_inter(a,b) >= x_inter(b,c)
        // (a.b - b.b)/(b.m-a.m) >= (b.b - c.b)/(c.m-b.m)
        // denominators > 0 (strictly increasing slopes)
        __int128 left = (__int128)(a.b - b.b) * (c.m - b.m);
        __int128 right = (__int128)(b.b - c.b) * (b.m - a.m);
        return left >= right;
    };

    for (const Line& ln : lines) {
        while (hull.size() >= 2 && bad(hull[hull.size() - 2], hull[hull.size() - 1], ln)) {
            hull.pop_back();
        }
        hull.push_back(ln);
    }
    return hull;
}

// Merge two slope-sorted hull vectors, deduplicate same slope by higher intercept.
static vector<Line> mergeBySlope(const vector<Line>& A, const vector<Line>& B) {
    vector<Line> tmp;
    tmp.reserve(A.size() + B.size());
    size_t i = 0, j = 0;
    while (i < A.size() || j < B.size()) {
        Line pick;
        if (j == B.size() || (i < A.size() && A[i].m < B[j].m)) {
            pick = A[i++];
        } else if (i == A.size() || B[j].m < A[i].m) {
            pick = B[j++];
        } else {
            // equal slope, keep bigger intercept
            pick = (A[i].b >= B[j].b) ? A[i] : B[j];
            ++i;
            ++j;
        }
        if (!tmp.empty() && tmp.back().m == pick.m) {
            if (pick.b > tmp.back().b) tmp.back().b = pick.b;
        } else {
            tmp.push_back(pick);
        }
    }
    return tmp;
}

static __int128 queryHull(const vector<Line>& hull, long long x) {
    int l = 0, r = (int)hull.size() - 1;
    while (l < r) {
        int mid = (l + r) >> 1;
        if (eval128(hull[mid], x) <= eval128(hull[mid + 1], x)) l = mid + 1;
        else r = mid;
    }
    return eval128(hull[l], x);
}

int n;
vector<Line> arr;
vector<vector<Line>> seg;

void build(int idx, int l, int r) {
    if (l == r) {
        seg[idx] = {arr[l]};
        return;
    }
    int mid = (l + r) >> 1;
    build(idx << 1, l, mid);
    build(idx << 1 | 1, mid + 1, r);
    vector<Line> merged = mergeBySlope(seg[idx << 1], seg[idx << 1 | 1]);
    seg[idx] = buildHull(merged);
}

__int128 negInf() {
    return -((__int128)1 << 120);
}

__int128 query(int idx, int l, int r, int ql, int qr, long long x) {
    if (qr < l || r < ql) return negInf();
    if (ql <= l && r <= qr) return queryHull(seg[idx], x);
    int mid = (l + r) >> 1;
    __int128 a = query(idx << 1, l, mid, ql, qr, x);
    __int128 b = query(idx << 1 | 1, mid + 1, r, ql, qr, x);
    return (a > b ? a : b);
}

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

    cin >> n;
    arr.resize(n + 1);
    for (int i = 1; i <= n; ++i) {
        cin >> arr[i].m >> arr[i].b;
    }

    seg.assign(4 * (n + 5), {});
    build(1, 1, n);

    int q;
    cin >> q;
    while (q--) {
        int L, R;
        long long x, y;
        cin >> L >> R >> x >> y;
        __int128 mx = query(1, 1, n, L, R, x);
        if (mx > (__int128)y) cout << "YES\n";
        else cout << "NO\n";
    }
    return 0;
}
HackerRank Geometry – Geometry Queries