제출 #1327117

#제출 시각아이디문제언어결과실행 시간메모리
1327117ritaQueue (CEOI06_queue)C++20
100 / 100
314 ms12128 KiB
#include <iostream>
#include <map>
#include <random>
#include <initializer_list>

using namespace std;

// --- 全局配置与类型 ---
const int MAXN = 1000000 + 5; // 由于会不断拆分区间,建议空间开大
using ll = long long;

// --- 随机权值生成 ---
random_device rd;
mt19937 rng(rd());

// --- Treap 结构体 ---
struct Node {
    ll L, R;        // 区间左、右端点
    int lc, rc, fa; // 左右孩子、父节点
    ll tsz;         // 子树覆盖的总长度
    uint32_t pir;   // 优先级
} nd[MAXN];

int root, cnt;
map<ll, int> leftmap;

// --- 核心辅助函数 ---
inline void pull(int u) {
    if (!u) return;
    nd[u].tsz = (nd[u].R - nd[u].L + 1);
    if (nd[u].lc) {
        nd[u].tsz += nd[nd[u].lc].tsz;
        nd[nd[u].lc].fa = u;
    }
    if (nd[u].rc) {
        nd[u].tsz += nd[nd[u].rc].tsz;
        nd[nd[u].rc].fa = u;
    }
}

// 基础 merge (2个节点)
int merge_tree(int a, int b) {
    if (!a || !b) {
        int res = a | b;
        if (res) nd[res].fa = 0;
        return res;
    }
    if (nd[a].pir < nd[b].pir) {
        nd[a].rc = merge_tree(nd[a].rc, b);
        pull(a); nd[a].fa = 0;
        return a;
    } else {
        nd[b].lc = merge_tree(a, nd[b].lc);
        pull(b); nd[b].fa = 0;
        return b;
    }
}

// 列表重载
int merge_tree(std::initializer_list<int> nodes) {
    int res = 0;
    for (int node : nodes) {
        res = merge_tree(res, node);
    }
    return res;
}

// 严格按照逻辑:分离出包含第k个位置的整个区间块u
void split_tree(int u, ll k, int &a, int &b) {
    if (!u) { a = b = 0; return; }
    ll lsz = nd[nd[u].lc].tsz;
    ll own = nd[u].R - nd[u].L + 1;
    if (k <= lsz) {
        split_tree(nd[u].lc, k, a, nd[u].lc);
        if (nd[u].lc) nd[nd[u].lc].fa = u;
        pull(u); b = u; nd[b].fa = 0;
    } else if (k > lsz + own) {
        split_tree(nd[u].rc, k - lsz - own, nd[u].rc, b);
        if (nd[u].rc) nd[nd[u].rc].fa = u;
        pull(u); a = u; nd[a].fa = 0;
    } else {
        a = nd[u].lc; b = nd[u].rc;
        if (a) nd[a].fa = 0;
        if (b) nd[b].fa = 0;
        nd[u].lc = nd[u].rc = 0;
        pull(u); nd[u].fa = 0;
    }
}

// --- 查询函数 ---
int get_node(ll lable) {
    auto it = leftmap.upper_bound(lable);
    return (--it)->second;
}

ll block_index(int u) {
    ll res = (nd[u].lc ? nd[nd[u].lc].tsz : 0);
    int curr = u;
    while (nd[curr].fa) {
        int p = nd[curr].fa;
        if (nd[p].rc == curr) {
            res += nd[p].tsz - nd[curr].tsz;
        }
        curr = p;
    }
    return res + 1;
}

ll kth(ll k) {
    int u = root;
    while (u) {
        ll lsz = (nd[u].lc ? nd[nd[u].lc].tsz : 0);
        ll own = nd[u].R - nd[u].L + 1;
        if (k <= lsz) u = nd[u].lc;
        else if (k <= lsz + own) return nd[u].L + (k - lsz - 1);
        else { k -= (lsz + own); u = nd[u].rc; }
    }
    return -1;
}

// --- 主程序 ---
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    nd[++cnt] = {1, 1000000000, 0, 0, 0, 1000000000, (uint32_t)rng()};
    root = cnt;
    leftmap[1] = root;

    int n, q;
    if (!(cin >> n)) return 0;
    for (int i = 1; i <= n; ++i) {
        ll A, B; cin >> A >> B;
        if (A == B) continue;

        // --- 第一阶段:提取 A 所在的节点 ---
        int targetBlockA = get_node(A);
        ll posA = block_index(targetBlockA);
        
        int treeLeftA = 0, treeRightA = 0;
        split_tree(root, posA, treeLeftA, treeRightA); // 分离大树

        ll oldL = nd[targetBlockA].L, oldR = nd[targetBlockA].R;
        leftmap.erase(oldL); 

        int blockLeftA = 0, blockRightA = 0, nodeA = targetBlockA;
        if (oldL < A) {
            blockLeftA = ++cnt;
            nd[blockLeftA] = {oldL, A - 1, 0, 0, 0, 0, (uint32_t)rng()};
            pull(blockLeftA);
            leftmap[oldL] = blockLeftA;
        }
        if (oldR > A) {
            blockRightA = ++cnt;
            nd[blockRightA] = {A + 1, oldR, 0, 0, 0, 0, (uint32_t)rng()};
            pull(blockRightA);
            leftmap[A + 1] = blockRightA;
        }
        nd[nodeA].L = nd[nodeA].R = A;
        nd[nodeA].lc = nd[nodeA].rc = 0;
        pull(nodeA);

        // 重新合并除去 A 以外的树
        root = merge_tree({treeLeftA, blockLeftA, blockRightA, treeRightA});

        // --- 第二阶段:寻找 B 并在其前方插入 A ---
        int targetBlockB = get_node(B);
        ll posB = block_index(targetBlockB);
        
        int treeLeftB = 0, treeRightB = 0;
        split_tree(root, posB, treeLeftB, treeRightB); // 再次分离大树

        ll bL = nd[targetBlockB].L;
        leftmap.erase(bL);

        int blockLeftB = 0, blockB_Start = targetBlockB;
        if (bL < B) {
            blockLeftB = ++cnt;
            nd[blockLeftB] = {bL, B - 1, 0, 0, 0, 0, (uint32_t)rng()};
            pull(blockLeftB);
            leftmap[bL] = blockLeftB;
        }
        nd[blockB_Start].L = B; // 修改原节点左端点为 B
        pull(blockB_Start);

        leftmap[A] = nodeA;
        leftmap[B] = blockB_Start;

        // 最终合并:LeftTree + B前的碎片 + 孤立的A + 以B开头的剩余部分 + RightTree
        root = merge_tree({treeLeftB, blockLeftB, nodeA, blockB_Start, treeRightB});
    }

    if (!(cin >> q)) return 0;
    while (q--) {
        char type; ll x;
        cin >> type >> x;
        if (type == 'P') {
            int u = get_node(x);
            cout << block_index(u) + (x - nd[u].L) << "\n";
        } else if (type == 'L') {
            cout << kth(x) << "\n";
        }
    }

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