Submission #1323335

#TimeUsernameProblemLanguageResultExecution timeMemory
1323335lucas110550장애물 (IOI25_obstacles)C++20
58 / 100
89 ms18304 KiB
// Your solution code here
#include <bits/stdc++.h>
using namespace std;

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

// ---------- Fenwick (BIT) for counts + kth ----------
struct BIT {
    int n;
    vector<int> bit; // 1-based
    BIT() : n(0) {}
    BIT(int n_) { init(n_); }
    void init(int n_) {
        n = n_;
        bit.assign(n + 1, 0);
    }
    void add(int idx, int delta) {
        for (int i = idx + 1; i <= n; i += i & -i) bit[i] += delta;
    }
    int sumPrefix(int idx) const { // sum [0..idx], idx<0 => 0
        if (idx < 0) return 0;
        int s = 0;
        for (int i = idx + 1; i > 0; i -= i & -i) s += bit[i];
        return s;
    }
    // smallest pos such that prefix sum >= k (k is 1-based). returns 0-based pos.
    int find_kth(int k) const {
        int idx = 0;
        int bitmask = 1 << (31 - __builtin_clz(n)); // highest power of 2 <= n
        while (bitmask) {
            int nxt = idx + bitmask;
            if (nxt <= n && bit[nxt] < k) {
                idx = nxt;
                k -= bit[nxt];
            }
            bitmask >>= 1;
        }
        return idx; // 0-based position
    }
};

// ---------- Globals filled by initialize ----------
static DSU g_dsu;
static int gM = 0;

// segment tree for range max on H
struct SegMax {
    int n;          // original size
    int size;       // power-of-two
    vector<int> seg;
    void build(const vector<int>& a) {
        n = (int)a.size();
        size = 1;
        while (size < n) size <<= 1;
        seg.assign(2 * size, INT_MIN);
        for (int i = 0; i < n; i++) seg[size + i] = a[i];
        for (int i = size - 1; i >= 1; i--) seg[i] = max(seg[2 * i], seg[2 * i + 1]);
    }
    int range_max(int l, int r) const { // inclusive
        if (l > r) return INT_MIN;
        l += size; r += size;
        int res = INT_MIN;
        while (l <= r) {
            if (l & 1) res = max(res, seg[l++]);
            if (!(r & 1)) res = max(res, seg[r--]);
            l >>= 1; r >>= 1;
        }
        return res;
    }
};

static SegMax g_seg;

// ---------- Core algorithm ----------
void initialize(std::vector<int> T, std::vector<int> H) {
    int N = (int)T.size();
    int M = (int)H.size();
    gM = M;

    // prefix minima of temperatures
    vector<int> pref_min(N);
    int cur_min = T[0];
    for (int i = 0; i < N; i++) {
        cur_min = min(cur_min, T[i]);
        pref_min[i] = cur_min;
    }

    // depth[col] = largest row i such that min(T[0..i]) > H[col]
    vector<int> depth(M, -1);
    for (int j = 0; j < M; j++) {
        int h = H[j];
        int lo = 0, hi = N - 1, ans = -1;
        while (lo <= hi) {
            int mid = (lo + hi) >> 1;
            if (pref_min[mid] > h) {
                ans = mid;
                lo = mid + 1;
            } else {
                hi = mid - 1;
            }
        }
        depth[j] = ans;
    }

    // bucket columns by exact depth
    vector<vector<int>> cols_by_depth(N);
    for (int j = 0; j < M; j++) {
        int d = depth[j];
        if (d >= 0) cols_by_depth[d].push_back(j);
    }

    // segment tree for max(H) queries
    g_seg.build(H);

    // DSU over columns
    g_dsu.init(M);

    // BIT: active columns are those with depth >= current row i
    BIT bit(M);

    // Process rows from bottom to top; when at row i, activate columns with depth == i.
    for (int i = N - 1; i >= 0; i--) {
        for (int col : cols_by_depth[i]) {
            bit.add(col, 1);

            // ----- nearest active on the left -----
            int cnt_left = bit.sumPrefix(col - 1);
            if (cnt_left > 0) {
                int left = bit.find_kth(cnt_left); // rightmost active < col
                if (left + 1 <= col - 1) {
                    if (g_seg.range_max(left + 1, col - 1) < T[i]) {
                        g_dsu.unite(left, col);
                    }
                } else {
                    g_dsu.unite(left, col);
                }
            }

            // ----- nearest active on the right -----
            int total_active = bit.sumPrefix(M - 1);
            int cnt_up_to_col = bit.sumPrefix(col); // includes col
            if (total_active > cnt_up_to_col) {
                int right = bit.find_kth(cnt_up_to_col + 1); // leftmost active > col
                if (col + 1 <= right - 1) {
                    if (g_seg.range_max(col + 1, right - 1) < T[i]) {
                        g_dsu.unite(col, right);
                    }
                } else {
                    g_dsu.unite(col, right);
                }
            }
        }
    }
}

bool can_reach(int /*L*/, int /*R*/, int S, int D) {
    // L=0 and R=M-1 always in this version.
    return g_dsu.find(S) == g_dsu.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...