제출 #1232770

#제출 시각아이디문제언어결과실행 시간메모리
1232770ProtonDecay314Abracadabra (CEOI22_abracadabra)C++20
100 / 100
836 ms32680 KiB
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef vector<ll> vll;
typedef vector<vll> vvll;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<vvi> v3i;
typedef vector<v3i> v4i;
typedef vector<bool> vb;
typedef vector<vb> vvb;
typedef pair<int, int> pi;
typedef pair<ll, ll> pll;
#define INF(dt) numeric_limits<dt>::max()
#define NINF(dt) numeric_limits<dt>::min()
#define pb push_back

struct Random {
    mt19937 rnd;

    Random(): rnd(random_device{}()) {
        rnd.seed(chrono::system_clock::now().time_since_epoch().count());
    }

    int rand_int(int l, int r) {
        return uniform_int_distribution(l, r)(rnd);
    }
};

Random rnd;

/*
Range max treap
*/
struct Treap {
    Treap* lt, *rt;
    int sz, mx, v, pr;

    Treap(int a_v): lt(nullptr), rt(nullptr), sz(1), mx(a_v), v(a_v), pr(rnd.rand_int(0, numeric_limits<int>::max())) {};
};

inline int treap_sz(Treap* tr) {
    return (tr == nullptr ? 0 : tr->sz);
}

inline Treap* treap_pull(Treap* tr) {
    if(tr == nullptr) return tr;
    tr->sz = treap_sz(tr->lt) + treap_sz(tr->rt) + 1;

    tr->mx = tr->v;

    if(tr->lt != nullptr) tr->mx = max(tr->mx, tr->lt->mx);
    if(tr->rt != nullptr) tr->mx = max(tr->mx, tr->rt->mx);
    return tr;
} 

inline Treap* treap_merge(Treap* t1, Treap* t2) {
    if(t1 == nullptr) return t2;
    if(t2 == nullptr) return t1;

    if(t1->pr < t2->pr) {
        // make t2 the right child of t1
        t1->rt = treap_merge(t1->rt, t2);
        treap_pull(t1);
        return t1;
    } else {
        // make t1 the left child of t2
        t2->lt = treap_merge(t1, t2->lt);
        treap_pull(t2);
        return t2;
    }
}

inline pair<Treap*, Treap*> treap_split(Treap* tr, int sz) {
    if(tr == nullptr) return {nullptr, nullptr};

    int lsz = treap_sz(tr->lt);
    if(lsz + 1 == sz) {
        Treap* tmp = tr->rt;
        tr->rt = nullptr;
        treap_pull(tr);
        return {tr, tmp};
    } else if(lsz >= sz) {
        auto [l, r] = treap_split(tr->lt, sz);
        tr->lt = r;
        treap_pull(tr);
        return {l, tr};
    } else {
        auto [l, r] = treap_split(tr->rt, sz - lsz - 1);
        tr->rt = l;
        treap_pull(tr);
        return {tr, r};
    }
}

inline int leftmost_treap_item(Treap* tr) {
    if(tr == nullptr) return -1;
    if(tr->lt == nullptr) return tr->v;
    return leftmost_treap_item(tr->lt);
}

inline int _strict_upper_bound(Treap* tr, int v) {
    if(tr->lt == nullptr) return (tr->v > v ? 1 : 1 + _strict_upper_bound(tr->rt, v));

    if(tr->lt->mx > v) return _strict_upper_bound(tr->lt, v);
    else if(tr->v > v) return treap_sz(tr->lt) + 1;
    else return treap_sz(tr->lt) + 1 + _strict_upper_bound(tr->rt, v);
}

inline int strict_upper_bound(Treap* tr, int v) {
    if(tr == nullptr) return 0;
    if(tr->mx <= v) return 0;
    return _strict_upper_bound(tr, v);
}

inline int find_item(Treap* tr, int i) {
    assert(tr != nullptr);
    int lsz = treap_sz(tr->lt);

    if(lsz == i - 1) return tr->v;
    if(lsz >= i) return find_item(tr->lt, i);
    return find_item(tr->rt, i - lsz - 1);
}

Treap* treapify(const vi& a) {
    Treap* res = nullptr;
    for(int v : a) {
        res = treap_merge(res, new Treap(v));
    }

    return res;
}

struct query {
    int qt, qi, i;
};

typedef vector<query> vq;

pair<bool, Treap*> shuffle_tr(Treap* tr) {
    int n = treap_sz(tr);

    auto [l, r] = treap_split(tr, n >> 1);

    bool done_shuffling = l->mx < leftmost_treap_item(r);

    if(done_shuffling) return {done_shuffling, treap_merge(l, r)};

    Treap* res = nullptr;

    while(l != nullptr && r != nullptr) {
        int lv = leftmost_treap_item(l), rv = leftmost_treap_item(r);

        if(lv < rv) {
            // slice off from the left

            int lsp_sz = strict_upper_bound(l, rv) - 1;

            if(lsp_sz == -1) {
                // we're essentially done!
                res = treap_merge(res, l);
                l = nullptr;
                break;
            } else {
                auto [tmpl, tmpr] = treap_split(l, lsp_sz);
                res = treap_merge(res, tmpl);
                l = tmpr;
            }
        } else {
            // slice off from the right

            int rsp_sz = strict_upper_bound(r, lv) - 1;

            if(rsp_sz == -1) {
                // we're essentially done!
                res = treap_merge(res, r);
                r = nullptr;
                break;
            } else {
                auto [tmpl, tmpr] = treap_split(r, rsp_sz);
                res = treap_merge(res, tmpl);
                r = tmpr;
            }
        }
    }

    if(l != nullptr) {
        res = treap_merge(res, l);
    }

    if(r != nullptr) {
        res = treap_merge(res, r);
    }

    return {false, res};
}

void _inorder_traverse(Treap* tr) {
    if(tr == nullptr) return;

    _inorder_traverse(tr->lt);
    cerr << tr->v << " ";
    _inorder_traverse(tr->rt);
}

void inorder_traverse(Treap* tr) {
    _inorder_traverse(tr);
    cerr << endl;
}

int main() {
    ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);

    int n, q;
    cin >> n >> q;

    vi a(n, 0);
    for(int& v : a) cin >> v;

    Treap* tr = treapify(a);

    // inorder_traverse(tr);

    // for(int i = 0 ; i < n; i++) {
    //     cerr << find_item(tr, i + 1) << " ";
    // }
    // cerr << endl;

    vq qs(q, {0, 0, 0});

    vi res(q, 0);

    for(int i = 0; i < q; i++) {
        cin >> qs[i].qt >> qs[i].qi;
        qs[i].i = i;
    }

    sort(qs.begin(), qs.end(), [](query q1, query q2) {return q1.qt < q2.qt;});

    int cur_qi = 0;
    int cur_t = 0;

    while(true) {
        while(cur_qi < q && qs[cur_qi].qt == cur_t) {
            res[qs[cur_qi].i] = find_item(tr, qs[cur_qi].qi);
            cur_qi++;
        }

        if(cur_qi == q) break;

        auto [is_done, new_tr] = shuffle_tr(tr);
        if(is_done) break;
        tr = new_tr;
        cur_t++;
    }

    while(cur_qi < q) {
        res[qs[cur_qi].i] = find_item(tr, qs[cur_qi].qi);
        cur_qi++;
    }

    for(int i = 0; i < q; i++) {
        cout << res[i] << "\n";
    }
    cout << flush;

    return 0;
}

/*
1, 3, 6, 10, 15, 2, 5, 9, 14, 17
*/
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...