제출 #909983

#제출 시각아이디문제언어결과실행 시간메모리
909983AlcabelAbracadabra (CEOI22_abracadabra)C++17
100 / 100
881 ms41624 KiB
#include <bits/stdc++.h>
using namespace std;

mt19937 rnd(161);

struct Node {
    int val, priority, sz, maxVal;
    int left, right;
    Node() {
        left = right = -1;
    }
    Node(int _val) {
        val = _val, sz = 1, maxVal = val;
        priority = rnd();
        left = right = -1;
    }
};

const int maxn = 2e5;
Node treap[maxn];

int getSz(int root) {
    if (root == -1) { return 0; }
    return treap[root].sz;
}

int getMax(int root) {
    if (root == -1) { return 0; }
    return treap[root].maxVal;
}

void update(int root) {
    if (root == -1) { return; }
    treap[root].sz = getSz(treap[root].left) + getSz(treap[root].right) + 1;
    treap[root].maxVal = max(max(getMax(treap[root].left), getMax(treap[root].right)), treap[root].val);
}

int merge(int l, int r) {
    if (l == -1) { return r; }
    if (r == -1) { return l; }
    if (treap[l].priority > treap[r].priority) {
        treap[l].right = merge(treap[l].right, r);
        update(l);
        return l;
    }
    treap[r].left = merge(l, treap[r].left);
    update(r);
    return r;
}

pair<int, int> split(int root, int k) {
    if (root == -1) { return {-1, -1}; }
    int lsz = getSz(treap[root].left);
    if (lsz >= k) {
        auto [l, r] = split(treap[root].left, k);
        treap[root].left = r;
        update(root);
        return {l, root};
    }
    auto [l, r] = split(treap[root].right, k - lsz - 1);
    treap[root].right = l;
    update(root);
    return {root, r};
}

int getKth(int root, int k) {
    if (root == -1) { return 0; }
    while (root != -1) {
        int lsz = getSz(treap[root].left);
        if (lsz >= k) {
            root = treap[root].left;
        } else {
            k -= lsz;
            if (k == 1) {
                break;
            }
            --k;
            root = treap[root].right;
        }
    }
    assert(root != -1);
    return treap[root].val;
}

int getFirstGreater(int root, int x) {
    if (root == -1) { return 0; }
    int res = 0;
    while (root != -1) {
        if (getMax(treap[root].left) > x) {
            root = treap[root].left;
        } else {
            res += getSz(treap[root].left);
            if (treap[root].val > x) {
                break;
            }
            root = treap[root].right;
            ++res;
        }
    }
    return res;
}

void dfs(int root) {
    if (root == -1) { return; }
    dfs(treap[root].left);
    cerr << treap[root].val << ' ';
    dfs(treap[root].right);
}

struct Query {
    int t, pos, i;
    Query() {}
    Query(int _t, int _pos, int _i) {
        t = _t, pos = _pos, i = _i;
    }
    bool operator<(const Query& other) const {
        return t < other.t;
    }
    ~Query() {}
};

void solve() {
    int n, q;
    cin >> n >> q;
    int half = n / 2, root = -1;
    for (int i = 0; i < n; ++i) {
        int x;
        cin >> x;
        treap[i] = Node(x);
        root = merge(root, i);
    }
    /*cerr << "built:\n";
    dfs(root);
    cerr << '\n';*/
    vector<Query> queries(q);
    for (int i = 0; i < q; ++i) {
        cin >> queries[i].t >> queries[i].pos;
        queries[i].i = i;
    }
    sort(queries.begin(), queries.end());
    int t = 0;
    bool cycled = false;
    vector<int> ans(q);
    for (const Query& query : queries) {
        while (!cycled && t < query.t) {
            auto [lh, rh] = split(root, half);
            int firstL = getKth(lh, 1), firstR = getKth(rh, 1);
            if (firstR > getMax(lh)) {
                cycled = true;
                root = merge(lh, rh);
            } else {
                int turn = (firstL > firstR ? 1 : -1);
                root = -1;
                while (firstL != 0 && firstR != 0) {
                    if (turn == -1) {
                        // cut from left
                        int k = getFirstGreater(lh, firstR);
                        assert(k >= 1);
                        auto [start, fin] = split(lh, k);
                        root = merge(root, start);
                        firstL = getKth(fin, 1);
                        lh = fin;
                    } else {
                        // cut from right
                        int k = getFirstGreater(rh, firstL);
                        assert(k >= 1);
                        auto [start, fin] = split(rh, k);
                        root = merge(root, start);
                        firstR = getKth(fin, 1);
                        rh = fin;
                    }
                    turn = -turn;
                }
                if (firstL == 0) {
                    root = merge(root, rh);
                } else {
                    root = merge(root, lh);
                }
            }
            ++t;
            /*cerr << "t: " << t << '\n';
            dfs(root);
            cerr << '\n';*/
        }
        ans[query.i] = getKth(root, query.pos);
    }
    for (int i = 0; i < q; ++i) {
        cout << ans[i] << '\n';
    }
}

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

#ifdef LOCAL
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
    int T = 1;
    cin >> T;
    while (T--) {
        solve();
        cerr << "-----------\n";
        cout << "-----------\n";
    }
#else
    int T = 1;
    // cin >> T;
    while (T--) {
        solve();
    }
#endif

    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...