Submission #1320118

#TimeUsernameProblemLanguageResultExecution timeMemory
1320118lucas110550Obstacles for a Llama (IOI25_obstacles)C++20
83 / 100
140 ms39440 KiB
#include <vector>
#include <algorithm>
#include <set>
#include <cmath>

using namespace std;

vector<int> T, H;
int N, M;
vector<int> pref_min, pref_max;
vector<int> depth;
vector<vector<int>> st;
vector<int> log2_;
vector<int> parent;
vector<int> sz;

int find(int x) {
    if (parent[x] != x) parent[x] = find(parent[x]);
    return parent[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);
    parent[b] = a;
    sz[a] += sz[b];
}

void init_sparse() {
    log2_.resize(M + 1);
    for (int i = 2; i <= M; ++i) log2_[i] = log2_[i / 2] + 1;
    int K = log2_[M] + 1;
    st.assign(K, vector<int>(M));
    for (int i = 0; i < M; ++i) st[0][i] = H[i];
    for (int k = 1; k < K; ++k) {
        int len = 1 << k;
        for (int i = 0; i + len <= M; ++i) {
            st[k][i] = max(st[k - 1][i], st[k - 1][i + (1 << (k - 1))]);
        }
    }
}

int get_max(int l, int r) {
    int k = log2_[r - l + 1];
    return max(st[k][l], st[k][r - (1 << k) + 1]);
}

void initialize(vector<int> _T, vector<int> _H) {
    T = _T;
    H = _H;
    N = T.size();
    M = H.size();

    // prefix min and max of T
    pref_min.resize(N);
    pref_max.resize(N);
    pref_min[0] = pref_max[0] = T[0];
    for (int i = 1; i < N; ++i) {
        pref_min[i] = min(pref_min[i - 1], T[i]);
        pref_max[i] = max(pref_max[i - 1], T[i]);
    }

    // depth[j] = first row where prefix_min <= H[j] (or N)
    depth.assign(M, N);
    vector<pair<int, int>> cols(M);
    for (int j = 0; j < M; ++j) cols[j] = {H[j], j};
    sort(cols.begin(), cols.end(), greater<pair<int, int>>()); // descending by H
    int ptr = 0;
    for (int i = 0; i < N; ++i) {
        int cur_min = pref_min[i];
        while (ptr < M && cols[ptr].first >= cur_min) {
            depth[cols[ptr].second] = i;
            ++ptr;
        }
    }

    // range maximum queries on H
    init_sparse();

    // DSU initialization
    parent.resize(M);
    sz.assign(M, 1);
    for (int i = 0; i < M; ++i) parent[i] = i;

    // process only columns that are free on row 0 (depth > 0)
    vector<pair<int, int>> good; // (key, index)
    for (int j = 0; j < M; ++j) {
        if (depth[j] > 0) {
            int L = depth[j] - 1;
            int key = pref_max[L];
            good.emplace_back(key, j);
        }
    }

    // sort by key descending
    sort(good.begin(), good.end(), greater<pair<int, int>>());

    set<int> active; // set of indices already processed (good columns)
    for (auto& p : good) {
        int key = p.first;
        int idx = p.second;
        auto it = active.lower_bound(idx);

        // try to connect with the nearest column on the left
        if (it != active.begin()) {
            int left = *prev(it);
            int mx = get_max(left, idx);
            if (mx < key) unite(idx, left);
        }

        // try to connect with the nearest column on the right
        if (it != active.end()) {
            int right = *it;
            int mx = get_max(idx, right);
            if (mx < key) unite(idx, right);
        }

        active.insert(idx);
    }
}

bool can_reach(int L, int R, int S, int D) {
    // constraints guarantee L = 0, R = M-1, so the whole grid is available.
    return find(S) == find(D);
}
#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...