POJ 1442 Black Box(treap树)

来源:互联网 发布:点赞数据库设计 编辑:程序博客网 时间:2024/06/07 00:41

题目链接:点击打开链接

思路: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;}



0 0
原创粉丝点击