제출 #1256886

#제출 시각아이디문제언어결과실행 시간메모리
1256886christhegamechangerObstacles for a Llama (IOI25_obstacles)C++17
24 / 100
281 ms14920 KiB
#include <bits/stdc++.h>
using namespace std;

namespace Obstacles {

struct SegTree {
    int n;
    vector<int> mn, mx;
    void build(const vector<int>& a, int id, int l, int r) {
        if (l == r) {
            mn[id] = mx[id] = a[l];
            return;
        }
        int m = (l + r) >> 1;
        build(a, id<<1, l, m);
        build(a, id<<1|1, m+1, r);
        mn[id] = min(mn[id<<1], mn[id<<1|1]);
        mx[id] = max(mx[id<<1], mx[id<<1|1]);
    }
    void init(const vector<int>& a) {
        n = (int)a.size();
        mn.assign(4*n, INT_MAX);
        mx.assign(4*n, INT_MIN);
        if (n) build(a, 1, 0, n-1);
    }
    int qmin(int id, int l, int r, int ql, int qr) const {
        if (qr < l || r < ql) return INT_MAX;
        if (ql <= l && r <= qr) return mn[id];
        int m = (l + r) >> 1;
        return min(qmin(id<<1, l, m, ql, qr), qmin(id<<1|1, m+1, r, ql, qr));
    }
    int qmin(int l, int r) const {
        if (l > r) return INT_MAX;
        return qmin(1, 0, n-1, l, r);
    }
    // first index in [ql,qr] with H[idx] >= t, or -1 if none
    int first_ge(int id, int l, int r, int ql, int qr, int t) const {
        if (qr < l || r < ql || mx[id] < t) return -1;
        if (l == r) return l;
        int m = (l + r) >> 1;
        int left = first_ge(id<<1, l, m, ql, qr, t);
        if (left != -1) return left;
        return first_ge(id<<1|1, m+1, r, ql, qr, t);
    }
    int first_ge(int l, int r, int t) const {
        if (l > r) return -1;
        return first_ge(1, 0, n-1, l, r, t);
    }
    // last index in [ql,qr] with H[idx] >= t, or -1 if none
    int last_ge(int id, int l, int r, int ql, int qr, int t) const {
        if (qr < l || r < ql || mx[id] < t) return -1;
        if (l == r) return l;
        int m = (l + r) >> 1;
        int right = last_ge(id<<1|1, m+1, r, ql, qr, t);
        if (right != -1) return right;
        return last_ge(id<<1, l, m, ql, qr, t);
    }
    int last_ge(int l, int r, int t) const {
        if (l > r) return -1;
        return last_ge(1, 0, n-1, l, r, t);
    }
};

int N, M;
vector<int> Trow, Hcol;
vector<int> prefMinT, prefMaxT;
SegTree segH;

inline int last_r_with_prefMin_gt(int h) {
    // largest r s.t. prefMinT[r] > h ; returns -1 if none
    int lo = 0, hi = N - 1, ans = -1;
    while (lo <= hi) {
        int mid = (lo + hi) >> 1;
        if (prefMinT[mid] > h) { ans = mid; lo = mid + 1; }
        else hi = mid - 1;
    }
    return ans;
}

inline pair<int,int> component_bounds(int L, int R, int S, int t) {
    // contiguous block around S inside [L,R] with H < t
    int left_bar = segH.last_ge(L, S, t);             // last barrier >= t to the left
    int right_bar = segH.first_ge(S, R, t);           // first barrier >= t to the right
    int Lb = max(L, left_bar + 1);
    int Rb = min(R, (right_bar == -1 ? R : right_bar - 1));
    return {Lb, Rb};
}

} // namespace Obstacles

using Obstacles::Trow; using Obstacles::Hcol;
using Obstacles::prefMinT; using Obstacles::prefMaxT;
using Obstacles::segH; using Obstacles::component_bounds;
using Obstacles::last_r_with_prefMin_gt;
using Obstacles::N; using Obstacles::M;

void initialize(vector<int> T, vector<int> H) {
    Trow = move(T);
    Hcol = move(H);
    N = (int)Trow.size();
    M = (int)Hcol.size();

    // prefix min / max of T
    prefMinT.assign(N, 0);
    prefMaxT.assign(N, 0);
    for (int i = 0; i < N; ++i) {
        if (i == 0) {
            prefMinT[i] = Trow[i];
            prefMaxT[i] = Trow[i];
        } else {
            prefMinT[i] = min(prefMinT[i-1], Trow[i]);
            prefMaxT[i] = max(prefMaxT[i-1], Trow[i]);
        }
    }
    // segment tree on H
    segH.init(Hcol);
}

bool can_reach(int L, int R, int S, int D) {
    // Start cell must be valid
    if (!(Trow[0] > Hcol[S])) return false;

    int tcur = Trow[0];

    auto seg = component_bounds(L, R, S, tcur);
    int Lb = seg.first, Rb = seg.second;

    if (Lb > Rb) return false;          // empty component
    if (D >= Lb && D <= Rb) return true;

    // Monotone expansion; tcur strictly increases while D is outside
    while (true) {
        // Best (smallest) humidity we can touch now
        int hmin = segH.qmin(Lb, Rb);
        int rmax = last_r_with_prefMin_gt(hmin);
        if (rmax < 0) return false;     // cannot go down at all
        int tnew = prefMaxT[rmax];
        if (tnew <= tcur) return false; // no further expansion possible
        tcur = tnew;

        seg = component_bounds(L, R, S, tcur);
        Lb = seg.first; Rb = seg.second;
        if (Lb > Rb) return false;
        if (D >= Lb && D <= Rb) return true;
    }
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...