제출 #1208491

#제출 시각아이디문제언어결과실행 시간메모리
1208491vasforTri (CEOI09_tri)C++20
20 / 100
553 ms108424 KiB
#include <bits/stdc++.h>

using namespace std;

using ll = long long;
using pll = pair<long long, long long>;

struct pt {
    int x = 0;
    int y = 0;

    pt operator-(const pt& o) const {
        return {x - o.x, y - o.y};
    }

    ll vector_mul(const pt& o) const {
        return 1ll * x * o.y - 1ll * o.x * y;
    }
};

pll intersect_lines(pt L1, pt L2) {
    // f(t) = x + t * y
    // x1 + t * y1 == x2 + t * t2
    // t = (x2 - x1) / (y1 - y2)
    ll u = L2.x - L1.x;
    ll v = L1.y - L2.y;
    if (v < 0) u = -u, v = -v;
    return {u, v};
}

bool cmp(pll p1, pll p2) {
    return p1.first * p2.second < p2.first * p1.second;
}

struct CHT {
    vector<pt> st;

    CHT() = default;

    CHT(vector<pt> a) {
        sort(a.begin(), a.end(), [&](pt p1, pt p2) {
            if (p1.y != p2.y) return p1.y < p2.y;
            else return p1.x < p2.x;
        });
        for (auto p : a) {
            if (!st.empty() && st.back().y == p.y) {
                st.back().x = p.x;
                continue;
            }
            while ((int) st.size() >= 2) {
                pt L1 = st[(int) st.size() - 2];
                pt L2 = st[(int) st.size() - 1];
                auto x1 = intersect_lines(L1, L2);
                auto x2 = intersect_lines(L2, p);
                if (cmp(x1, x2)) break;
                else st.pop_back();
            }
            st.push_back(p);
        }
    }

    ll get_max(int p, int q) {
        // p * x + q * y -> max
        // p > 0
        // p * (x + (q / p) * y) -> max
        // arg = q / p
        assert(p > 0);
        pll x0 = {q, p};
        int bl = 0, br = (int) st.size(), bm;
        while (br - bl > 1) {
            bm = bl + (br - bl) / 2;
            pll x = intersect_lines(st[bm], st[bm + 1]);
            if (cmp(x0, x)) br = bm;
            else bl = bm;
        }
        ll max_value = -5e18;
        for (int di = -2; di <= 2; ++di) {
            int i = bl + di;
            if (i < 0 || i >= (int) st.size()) continue;
            ll tmp_value = 1ll * p * st[i].x + 1ll * q * st[i].y;
            if (tmp_value > max_value) {
                max_value = tmp_value;
            }
        }
        return max_value;
    }
};

struct RangeTree {
    int n = 0;
    vector<vector<pt>> pts;
    vector<CHT> cht_xy_pos, cht_xy_neg, cht_yx_pos, cht_yx_neg;

    RangeTree(const vector<pt>& a): n(a.size()), pts(4 * n), 
        cht_xy_pos(4 * n), cht_xy_neg(4 * n), cht_yx_pos(4 * n), cht_yx_neg(4 * n)
    {
        build(a, 1, 0, n - 1);
    }

    void build(const vector<pt>& a, int v, int tl, int tr) {
        if (tl == tr) {
            pts[v].push_back(a[tl]);
        } else {
            int tm = tl + (tr - tl) / 2;
            build(a, v << 1, tl, tm);
            build(a, v << 1 | 1, tm + 1, tr);

            {
                pts[v] = pts[v << 1];
                copy(pts[v << 1 | 1].begin(), pts[v << 1 | 1].end(), back_inserter(pts[v]));
            }
        }
        cht_xy_pos[v] = CHT(pts[v]);
        
        for (auto& p : pts[v]) p.x = -p.x, p.y = -p.y;
        cht_xy_neg[v] = CHT(pts[v]);
        for (auto& p : pts[v]) p.x = -p.x, p.y = -p.y;

        for (auto& p : pts[v]) swap(p.x, p.y);

        cht_yx_pos[v] = CHT(pts[v]);
        
        for (auto& p : pts[v]) p.x = -p.x, p.y = -p.y;
        cht_yx_neg[v] = CHT(pts[v]);
        for (auto& p : pts[v]) p.x = -p.x, p.y = -p.y;
        
        for (auto& p : pts[v]) swap(p.x, p.y);
    }

    ll get_max(int v, int tl, int tr, int l, int r, int p, int q) {
        if (l <= tl && tr <= r) {
            if (p > 0) return cht_xy_pos[v].get_max(p, q);
            else if (p < 0) return cht_xy_neg[v].get_max(-p, -q);
            else {
                if (q > 0) return cht_yx_pos[v].get_max(q, p);
                else {
                    assert(q < 0);
                    return cht_yx_neg[v].get_max(-q, -p);
                }
            }
        } else {
            int tm = tl + (tr - tl) / 2;
            ll res = -5e18;
            if (l <= tm) {
                ll tmp = get_max(v << 1, tl, tm, l, r, p, q);
                if (tmp > res) res = tmp;
            }
            if (r > tm) {
                ll tmp = get_max(v << 1 | 1, tm + 1, tr, l, r, p, q);
                if (tmp > res) res = tmp;
            }
            return res;
        }
    }

    ll get_max(int l, int r, int p, int q) {
        // px + qy -> max
        return get_max(1, 0, n - 1, l, r, p, q);
    }
};

int main() {

#ifdef LOCAL
    freopen("input.txt", "r", stdin);
#endif

    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    int n, m;
    cin >> n >> m;

    vector<pt> a(n);
    for (auto& p : a) cin >> p.x >> p.y;
    sort(a.begin(), a.end(), [&](pt p1, pt p2) {
        return p1.vector_mul(p2) > 0;
    });

    RangeTree rt(a);

    for (int it = 0; it < m; ++it) {
        pt l, r;
        cin >> l.x >> l.y;
        cin >> r.x >> r.y;
        if (l.vector_mul(r) < 0) swap(l, r);
        int ql, qr;
        if (l.vector_mul(a.back()) > 0) {
            int bl = -1, br = (int) a.size() - 1, bm;
            while (br - bl > 1) {
                bm = bl + (br - bl) / 2;
                if (l.vector_mul(a[bm]) > 0) br = bm;
                else bl = bm;
            }
            ql = br;
        }
        if (a.front().vector_mul(r) > 0) {
            int bl = 0, br = (int) a.size(), bm;
            while (br - bl > 1) {
                bm = bl + (br - bl) / 2;
                if (a[bm].vector_mul(r) > 0) bl = bm;
                else br = bm;
            }
            qr = bl;
        }
        if (ql <= qr) {
            pt v = r - l;
            ll tmp = rt.get_max(ql, qr, -v.y, v.x);
            ll C = v.vector_mul(l);
            cout << (tmp > C ? "Y" : "N") << "\n";
        } else {
            cout << "N\n";
        }
    }

    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...