POJ 1442 Black Box - (无旋Treap)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/rsy56640/article/details/88570996

题目链接:http://poj.org/problem?id=1442
无旋treap挺好用,参考:https://www.bilibili.com/video/av46204315/?p=2

#include <iostream>
#include <queue>
#include <stdlib.h>
#include <cstdio>

using namespace std;

#define maxn (30000 + 5)

inline int read_int() { int a; scanf("%d", &a); return a; }
inline void outd(int x) { printf("%d", x); }
inline void outdn(int x) { printf("%d\n", x); }
inline void outn() { printf("\n"); }

// refers to "https://www.bilibili.com/video/av46204315/?p=2"
////////////////////////////////////////////////////

struct treap_node {
    int
        left,  // 左子树
        right, // 右子树
        bst_v, // BST值
        pri_v, // 最小堆值(随机生成)
        size;  // 树大小,包括自己
};
treap_node treap[maxn]; // 0 是不用的
int root = 0;
int cur_no = 0;
int total_size = 0;

#define lc(root) treap[root].left
#define rc(root) treap[root].right
inline void update_size(int root) { treap[root].size = treap[lc(root)].size + treap[rc(root)].size + 1; }

// 将 root 划分为 left 和 right 两棵 treap
// 按照 bst_v 来分 BST,结果得到 left树 BST <= right树
void split(int root, int& left, int& right, int bst_v) {
    // 空树
    if (root == 0) {
        left = right = 0;
        return;
    }
    // root 和 其左子树应该划分给 left,
    // 剩下的右子树 再 split 分给 left右子树(左边的一部分) 和 right
    // 相当于 "不断地裁掉一节,然后接到左右treap上"
    if (treap[root].bst_v <= bst_v) {
        left = root;
        split(rc(root), rc(left), right, bst_v);
    }
    else {
        right = root;
        split(lc(root), left, lc(right), bst_v);
    }
    update_size(root);
}

// 按照最小堆 merge,把 left树 和 right树 merge 的结果写到 root
// 调用者保证 left树 BST <= right树
void merge(int& root, int left, int right) {
    // 空树
    if (left == 0 || right == 0) {
        root = left | right;
        return;
    }
    // 让 left 成为 root,并且连带其左子树(BST性质)
    // 然后 其右子树 和 right树 再次合并为 left 的右子树
    if (treap[left].pri_v < treap[right].pri_v) {
        root = left;
        merge(rc(root), rc(left), right);
    }
    else {
        root = right;
        merge(lc(root), left, lc(right));
    }
    update_size(root);
}

////////////////////////////////////////////////////

void insert(int& root, int bst_v) {
    total_size++;
    cur_no++;
    treap[cur_no].size = 1;
    treap[cur_no].bst_v = bst_v;
    treap[cur_no].pri_v = rand();
    int left, right;
    split(root, left, right, bst_v); // left树 <= bst_v,right树 > bst_v
    merge(left, left, cur_no);   	 // 保证 left树 <= right树,把新值加进去
    merge(root, left, right);        // 再合起来
}

void erase(int& root, int bst_v) {
    int left, right, victim;
    split(root, left, right, bst_v);
    split(left, left, victim, bst_v - 1); 	// victim树 里面都是 bst_v
    if (treap[victim].size > 0)
        total_size--;
    merge(victim, lc(victim), lc(victim)); 	// 去掉根这个值
    merge(left, left, victim);
    merge(root, left, right);
}

// 区间第K大
// 寻找中序遍历第K个
int Kth_element(int root, int K) {
    while (treap[lc(root)].size != K - 1) {
        if (treap[lc(root)].size >= K)
            root = lc(root);
        else {
            K -= treap[lc(root)].size + 1;
            root = rc(root);
        }
    }
    return treap[root].bst_v;
}

// 查询 bst_v 的排名
int get_rank(int& root, int bst_v) {
    int left, right;
    split(root, left, right, bst_v - 1); // left树 <= bst_v
    int answer = treap[left].size + 1;
    merge(root, left, right);
    return answer;
}

// 前驱,即满足 "小于bst_v" 的最大的数
int precursor(int& root, int bst_v) {
    int left, right;
    split(root, left, right, bst_v - 1); // left树 <= bst_v
    int answer = Kth_element(left, treap[left].size); // left树中的最大值
    merge(root, left, right);
    return answer;
}

// 后继,即满足 "大于bst_v" 的最小的数
int successor(int& root, int bst_v) {
    int left, right;
    split(root, left, right, bst_v); // right树 > bst_v
    int answer = Kth_element(right, 1); // right树中的最小值
    merge(root, left, right);
    return answer;
}

////////////////////////////////////////////////////

int main() {
    srand(19971206);
    int M, N, i = 0;
    queue<int> add, get;
    M = read_int();
    N = read_int();
    int temp;
    for (int i = 0; i < M; i++)
        add.push(read_int());
    for (int i = 0; i < N; i++)
        get.push(read_int());
    i = 0;
    while (!get.empty())
    {
        const int size = get.front();
        while (total_size < size)
        {
            insert(root, add.front());
            add.pop();
        }
        outdn(Kth_element(root, ++i));
        get.pop();
    }
    system("pause");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/rsy56640/article/details/88570996