POJ 1442 Black Box(treap树)

Posted AC_Arthur

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 1442 Black Box(treap树)相关的知识,希望对你有一定的参考价值。

题目链接:点击打开链接

思路:treap树模板题, 可以动态维护一个有序表, 支持在O(logN)的时间内完成插入、删除一个元素和查找第K大元素的任务。 当然, treap树能做到的还远远不止这些, 常常与其他数据结构嵌套。

treap树是一种平衡二叉搜索树, 既满足堆的条件, 又满足排序二叉树的条件。

细节参见代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <bitset>
#include <cstdlib>
#include <cmath>
#include <set>
#include <list>
#include <deque>
#include <map>
#include <queue>
#include <ctime>
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
typedef long double ld;
const ld eps = 1e-9, PI = 3.1415926535897932384626433832795;
const int mod = 1000000000 + 7;
const int INF = 0x3f3f3f3f;
const int seed = 131;
const ll INF64 = ll(1e18);
const int maxn = 3e4 + 10;
int T,n,m,a[maxn], cc, v;
struct treap {
    int root, treapcnt, key[maxn],priority[maxn],
    childs[maxn][2], cnt[maxn], _size[maxn];
    treap() {
        root = 0;
        treapcnt = 1;
        priority[0] = INF;
        _size[0] = 0;
    }
    void update(int x) {
        _size[x] = _size[childs[x][0]] + cnt[x] + _size[childs[x][1]];
    }
    void _rotate(int &x, int t) {
        int y = childs[x][t]; //为了维持平衡而做的旋转操作,它并不直观
        childs[x][t] = childs[y][1-t];
        childs[y][1-t] = x;
        update(x);
        update(y);
        x = y;
    }
    void _insert(int &x, int k) {
        if(x) { //x == 0 表示该结点为空, 反之非空
            if(key[x] == k) cnt[x]++; //cnt[x]表示结点x的值的个数,key[x]表示结点x的值
            else {
                int t = key[x] < k; //根据排序二叉树规则递归下去
                _insert(childs[x][t], k);
                if(priority[childs[x][t]] < priority[x]) { //根据堆排序规则
                    _rotate(x, t);
                }
            }
        }
        else {
            x = treapcnt++; //创建新的结点
            key[x] = k;
            cnt[x] = 1;
            priority[x] = rand(); //如果优先级是随机的,那么可以证明treap的期望深度是logN
            childs[x][0] = childs[x][1] = 0; //0表示为空
        }
        update(x);
    }
    void _erase(int &x, int k) {
        if(key[x] == k) {
            if(cnt[x] > 1) --cnt[x];
            else {
                if(childs[x][0] == 0 && childs[x][1] == 0) {
                    x = 0; return ; //x设为0表示空
                }
                int t = priority[childs[x][0]] > priority[childs[x][1]];
                _rotate(x, t);  //直到把该结点旋转到叶子再删除
                _erase(x, k);
            }
        }
        else _erase(childs[x][key[x]<k], k);

        update(x);
    }
    int _getKth(int &x, int k) {
        if(k <= _size[childs[x][0]]) return _getKth(childs[x][0], k); //size[x]表示以x为根的子树的值得个数
        k -= _size[childs[x][0]] + cnt[x];  //如果在右边,那么将要找右边的第k-size小的数
        if(k <= 0) return key[x];
        return _getKth(childs[x][1], k);
    }
    void insert(int k) {
        _insert(root, k);
    }
    void erase(int k) {
        _erase(root, k);
    }
    int getKth(int k) {
        return _getKth(root, k);
    }

};
int main() {
    while(~scanf("%d%d",&n,&m)) {

        treap g;
        for(int i = 1; i <= n; i++) {
            scanf("%d",&a[i]);
        }
        cc = 1;
        for(int i = 1; i <= m; i++) {
            scanf("%d",&v);
            while(v >= cc) g.insert(a[cc++]);
            printf("%d\n", g.getKth(i));
        }
    }
    return 0;
}



以上是关于POJ 1442 Black Box(treap树)的主要内容,如果未能解决你的问题,请参考以下文章

POJ-1442 Black Box(手写堆优化)

Black Box POJ - 1442

POJ 1442 Black Box(优先队列)

POJ 1442(treap || 优先队列)

A - Black Box 优先队列

poj1442(treap求第k大)