Editorial for Classification Problem


Remember to use this editorial only when stuck, and not to copy-paste code from it. Please be respectful to the problem author and editorialist.

Submitting an official solution before solving the problem yourself is a bannable offence.
// #pragma GCC optimize("O3,unroll-loops")
// #pragma GCC target("avx2")
#include <bits/stdc++.h>

using namespace std;

int binarySearch(vector<pair<long double, pair<int, int>>>& array, int search)
{
    int start = 0;
    int end = array.size() - 1;

    while (start <= end)
    {
        int middle = start + (end - start) / 2;
        assert(array[middle].first != search);
        if (array[middle].first > search)
            end = middle - 1;
        if (array[middle].first < search)
            start = middle + 1;
    }

    if (start == array.size())
        return array[array.size() - 1].second.second;
    else
        return array[start].second.first;
}

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

    int n, q;
    cin >> n >> q;

    pair<int, int> parabola[n];
    for (int index = 0; index < n; index++)
        cin >> parabola[index].first >> parabola[index].second;

    pair<long double, int> order[n];
    for (int index = 0; index < n; index++)
        order[index] = {1.0l * parabola[index].first / 2, index};
    sort(order, order + n);

    vector<int> absOrder;
    for (int index = 0, nextIndex = 1; index < n; index = nextIndex++)
    {
        pair<int, int> max = {parabola[order[index].second].second, order[index].second};
        while (nextIndex < n && order[index].first == order[nextIndex].first)
        {
            if (parabola[order[nextIndex].second].second > max.first)
                max = {parabola[order[nextIndex].second].second, order[nextIndex].second};
            nextIndex++;
        }
        absOrder.emplace_back(max.second);
    }

    list<pair<long double, pair<int, int>>> intersection;
    for (int index = 1; index < absOrder.size(); index++)
    {
        long double intersectionPoint = 1.0l * (parabola[absOrder[index]].second - parabola[absOrder[index - 1]].second) / (parabola[absOrder[index - 1]].first - parabola[absOrder[index]].first);
        intersection.emplace_back(intersectionPoint, make_pair(absOrder[index - 1], absOrder[index]));
    }

    revise:
    {
        bool final = true;
        auto curr = intersection.begin();
        for (auto prev = intersection.begin()++; curr != intersection.end(); prev = curr++)
            if (prev -> first > curr -> first)
            {
                int leftparabola = prev -> second.first, rightparabola = curr -> second.second;
                long double intersectionPoint = 1.0l * (parabola[rightparabola].second - parabola[leftparabola].second) / (parabola[leftparabola].first - parabola[rightparabola].first);

                prev = intersection.erase(prev);
                curr = intersection.erase(prev);

                prev = intersection.emplace(curr, intersectionPoint, make_pair(leftparabola, rightparabola));
                curr = prev--;
                final = false;
            }
        if (!final)
            goto revise;
    };

    vector<pair<long double, pair<int, int>>> absIntersection;
    for (auto element : intersection)
        absIntersection.emplace_back(element);

    while (q--)
    {
        int x;
        cin >> x;

        if (absIntersection.empty())
            cout << absOrder.front() + 1 << '\n';
        else
            cout << binarySearch(absIntersection, x) + 1 << '\n';
    }
    return 0;
}