Submission #1273668

#TimeUsernameProblemLanguageResultExecution timeMemory
1273668lucas110550Obstacles for a Llama (IOI25_obstacles)C++20
83 / 100
185 ms20352 KiB
#include <bits/stdc++.h>
using namespace std;

// ---------- DSU ----------
struct DSU {
        vector<int> p, sz;
        DSU(int n = 0) { init(n); }
        void init(int n) {
                p.resize(n);
                sz.assign(n, 1);
                iota(p.begin(), p.end(), 0);
        }
        int find(int x) {
                return p[x] == x ? x : p[x] = find(p[x]);
        }
        void unite(int a, int b) {
                a = find(a);
                b = find(b);
                if (a == b) return;
                if (sz[a] < sz[b]) swap(a, b);
                p[b] = a;
                sz[a] += sz[b];
        }
};

// ---------- Segment Tree for range maximum ----------
struct SegTree {
        int n;
        vector<int> seg;
        SegTree() {}
        explicit SegTree(const vector<int>& a) { build(a); }
        void build(const vector<int>& a) {
                n = (int)a.size();
                seg.assign(4 * n, 0);
                build(1, 0, n - 1, a);
        }
        void build(int node, int l, int r, const vector<int>& a) {
                if (l == r) {
                        seg[node] = a[l];
                        return;
                }
                int mid = (l + r) >> 1;
                build(node << 1, l, mid, a);
                build(node << 1 | 1, mid + 1, r, a);
                seg[node] = max(seg[node << 1], seg[node << 1 | 1]);
        }
        int query(int L, int R) const { return query(1, 0, n - 1, L, R); }
        int query(int node, int l, int r, int L, int R) const {
                if (R < l || r < L) return INT_MIN;
                if (L <= l && r <= R) return seg[node];
                int mid = (l + r) >> 1;
                return max(query(node << 1, l, mid, L, R),
                                   query(node << 1 | 1, mid + 1, r, L, R));
        }
};

// ---------- Global data ----------
vector<int> T, H;
vector<int> depth;                // max continuous prefix where column stays free
vector<int> col2int;            // column -> interval id (or -1)
vector<int> prefMaxT;      // prefix maximum of T
struct Interval {
        int left, right;
        int maxDepth;   // max depth among its columns
        int Tval;          // prefixMaxT[maxDepth]
        int id;
};
vector<Interval> intervals;
DSU dsu;
SegTree seg;

// ---------- Helper to compute depth ----------
void computeDepth() {
        int N = T.size(), M = H.size();
        depth.assign(M, N - 1);
        // rows sorted by temperature (value, index)
        vector<pair<int, int>> rows;
        rows.reserve(N);
        for (int i = 0; i < N; ++i) rows.emplace_back(T[i], i);
        sort(rows.begin(), rows.end());                         // ascending by temperature

        // columns sorted by humidity
        vector<int> colIdx(M);
        iota(colIdx.begin(), colIdx.end(), 0);
        sort(colIdx.begin(), colIdx.end(),
                 [&](int a, int b) { return H[a] < H[b]; });

        const int INF = INT_MAX;
        int rp = 0;
        int curMin = INF;
        for (int idx : colIdx) {
                while (rp < N && rows[rp].first <= H[idx]) {
                        curMin = min(curMin, rows[rp].second);
                        ++rp;
                }
                if (curMin == INF) depth[idx] = N - 1;
                else depth[idx] = curMin - 1;
        }
}

// ---------- Helper to build intervals on row 0 ----------
void buildIntervals() {
        int M = H.size();
        intervals.clear();
        col2int.assign(M, -1);
        int i = 0;
        while (i < M) {
                if (T[0] > H[i]) {
                        int start = i;
                        int maxH = H[i];
                        int maxDepth = depth[i];
                        ++i;
                        while (i < M && T[0] > H[i]) {
                                maxH = max(maxH, H[i]);
                                maxDepth = max(maxDepth, depth[i]);
                                ++i;
                        }
                        Interval it;
                        it.left = start;
                        it.right = i - 1;
                        it.maxDepth = maxDepth;
                        it.Tval = 0; // will be set later after prefixMaxT known
                        it.id = intervals.size();
                        intervals.push_back(it);
                        int id = it.id;
                        for (int j = start; j <= i - 1; ++j) col2int[j] = id;
                } else {
                        ++i;
                }
        }
        int K = intervals.size();
        for (int id = 0; id < K; ++id) {
                intervals[id].Tval = prefMaxT[intervals[id].maxDepth];
        }
}

// ---------- Main initialization ----------
void initialize(vector<int> T_, vector<int> H_) {
        T.swap(T_);
        H.swap(H_);
        int N = T.size();
        int M = H.size();

        // prefix maximum of temperatures
        prefMaxT.assign(N, 0);
        prefMaxT[0] = T[0];
        for (int i = 1; i < N; ++i) prefMaxT[i] = max(prefMaxT[i - 1], T[i]);

        // compute depth for each column
        computeDepth();

        // build intervals on the first row
        buildIntervals();

        // initialise DSU and segment tree
        int K = intervals.size();
        dsu.init(K);
        seg = SegTree(H);

        // sort interval ids by decreasing Tval (break ties by left coordinate)
        vector<int> order(K);
        iota(order.begin(), order.end(), 0);
        sort(order.begin(), order.end(),
                 [&](int a, int b) {
                         if (intervals[a].Tval != intervals[b].Tval)
                                 return intervals[a].Tval > intervals[b].Tval;
                         return intervals[a].left < intervals[b].left;
                 });

        // active set ordered by left endpoint
        set<pair<int, int>> active; // (left, interval id)

        for (int idx : order) {
                const Interval &cur = intervals[idx];
                int curT = cur.Tval;

                // locate where this interval would be inserted
                auto itSucc = active.lower_bound({cur.left, -1});

                // predecessor (the greatest left < cur.left)
                if (itSucc != active.begin()) {
                        auto itPrev = prev(itSucc);
                        int pid = itPrev->second;
                        const Interval &p = intervals[pid];
                        int regionMax = seg.query(p.left, cur.right);
                        if (regionMax < curT) dsu.unite(pid, idx);
                }

                // successor (the smallest left >= cur.left)
                if (itSucc != active.end()) {
                        int sid = itSucc->second;
                        const Interval &s = intervals[sid];
                        int regionMax = seg.query(cur.left, s.right);
                        if (regionMax < curT) dsu.unite(idx, sid);
                }

                active.insert({cur.left, idx});
        }
}

// ---------- Query ----------
bool can_reach(int L, int R, int S, int D) {
        // For the sub‑problem L=0,R=M-1, we can ignore L,R.
        int idS = col2int[S];
        int idD = col2int[D];
        if (idS == -1 || idD == -1) return false; // should not happen for valid queries
        if (idS == idD) return true;
        return dsu.find(idS) == dsu.find(idD);
}
#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...