Treap 模板 poj1442&hdu4557

原理可以看hihocoder上面的讲解,很清楚,不多说了。

模板抄lrj训练指南上面的。

/**
Treap 实现 名次树
功能: 1.找到排名为k的元素
       2.值为x的元素的名次

初始化:Node* root = NULL;
*/
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;

struct Node {
    Node * ch[2];   // 0左子树 1右子树
    int r;          // 随机优先级
    int v;          // 值
    int s;          // 以s为根的子树的大小
    Node(int v):v(v)
    {
        ch[0] = ch[1] = NULL;
        r = rand();
        s = 1;
    }
    bool operator<(const Node& rhs) const { // 按随机优先级排序
        return r < rhs.r;
    }
    int cmp(int x) const
    {
        if (x == v) return -1;
        return x < v ? 0 : 1;
    }
    void maintain() // 更新
    {
        s = 1;
        if (ch[0] != NULL) s += ch[0]->s;
        if (ch[1] != NULL) s += ch[1]->s;
    }
} ;

void rotate(Node* &o, int d) // d=0 代表左转, d=1代表右转
{
    Node* k = o->ch[d^1];
    o->ch[d^1] = k->ch[d];
    k->ch[d] = o;
    o->maintain();
    k->maintain();
    o = k;
}

void insert(Node* &o, int x) // o是根 x是插入的值
{
    if (o == NULL) {
        o = new Node(x);
    } else {
        int d = (x < o->v ? 0 : 1); // 不用cmp函数因为可能有重复的值
        insert(o->ch[d], x);
        if ((o->ch[d]->r) > (o->r)) rotate(o, d^1);
    }
    o->maintain();
}

void remove(Node* &o, int x)
{
    int d = o->cmp(x);
    if (d == -1) {
        Node* u = o;
        if (o->ch[0] != NULL && o->ch[1] != NULL) {
            int d2 = ((o->ch[0]->r) > (o->ch[1]->r) ? 1 : 0);
            rotate(o, d2);
            remove(o->ch[d2], x);
        } else {
            if (o->ch[0] == NULL) o = o->ch[1];
            else o = o->ch[0];
            delete u;
        }
    } else {
        remove(o->ch[d], x);
    }
    if (o != NULL) o->maintain();
}

int find(Node* o, int x) // 因为remove和insert都没有查值存不存在 记得操作之前调用find
{
    while (o != NULL) {
        int d = o->cmp(x);
        if (d == -1) return 1;
        else o = o->ch[d];
    }
    return 0;
}

int kth(Node* &o, int k, int fg) // fg=1第k大的值 fg=0第k小的值 返回0表示没找到
{
    if (o == NULL || k <= 0 || k > o->s) return 0;
    int s = (o->ch[fg] == NULL ? 0 : o->ch[fg]->s);
    if (k == s+1) return o->v;
    else if (k <= s) return kth(o->ch[fg], k, fg);
    else return kth(o->ch[fg^1], k-s-1, fg);
}

int prv(Node* &o, int x) // 查找x前面的元素 (<x的最大值
{
    if (o == NULL) return -1;
    if (x <= o->v) return prv(o->ch[0], x);
    int ans = prv(o->ch[1], x);

    return ans == -1 ? o->v : ans;
}

int nxt(Node* &o, int x) // 查找x后面的元素 (>x的最大值
{
    if (o == NULL) return -1;
    if (x >= o->v) return nxt(o->ch[1], x);
    int ans = nxt(o->ch[0], x);
    return ans == -1 ? o->v : ans;
}

void mergeto(Node* &src, Node* &dest) // 合并两棵树 把src加到dest上 src和dest都是树的根
{
    if (src->ch[0] != NULL) mergeto(src->ch[0], dest);
    if (src->ch[0] != NULL) mergeto(src->ch[1], dest);
    insert(dest, src->v);
    delete src;
    src = NULL;
}

void print(Node* &o)
{
    if (o == NULL) return ;
    print(o->ch[0]);
    printf("%d ", o->v);
    print(o->ch[1]);
}

int main()
{
    Node* root = NULL;
    insert(root, 3);
    insert(root, 3);
    insert(root, 4);
    insert(root, 5);
    remove(root, 4);
    print(root);
    return 0;
}

例题:

上面hihocoder的例题,这个代码是照着讲解自己写的

//Treap.cpp

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

const int N = 100005;

struct Treap {
    int father, left, right;
    int key, weight;
    void init(int k, int w, int fa) {
        left = right = -1;
        father = fa, key = k, weight = w;
    }
} tp[N];
int root;
int treap_cnt;

int new_treap(int k, int w, int fa = -1)
{
    tp[treap_cnt].init(k, w, fa);
    return treap_cnt++;
}

void left_rotate(int a) // 左旋 把节点A的右儿子节点B转到A的父亲节点
{
    int b = tp[a].right;
    tp[b].father = tp[a].father;
    if (tp[tp[a].father].left == a) { // 判断a是父节点的左儿子还是右儿子 并用b替换
        tp[tp[a].father].left = b;
    } else {
        tp[tp[a].father].right = b;
    }
    tp[a].right = tp[b].left;
    if (tp[b].left != -1) tp[tp[b].left].father = a;
    tp[b].left = a;
    tp[a].father = b;
}

void right_rotate(int a) // 右旋 把节点A的左儿子节点B转到A的父亲节点
{
    int b = tp[a].left;
    tp[b].father = tp[a].father;
    if (tp[tp[a].father].left == a) tp[tp[a].father].left = b;
    else tp[tp[a].father].right = b;
    tp[a].left = tp[b].right;
    if (tp[b].right != -1) tp[tp[b].right].father = a;
    tp[b].right = a;
    tp[a].father = b;
}

int insert(int a, int key)
{
    if (key < tp[a].key) {
        if (tp[a].left == -1) {
            tp[a].left = new_treap(key, rand(), a);
            return tp[a].left;
        } else {
            return insert(tp[a].left, key);
        }
    } else {
        if (tp[a].right == -1) {
            tp[a].right = new_treap(key, rand(), a);
            return tp[a].right;
        } else {
            return insert(tp[a].right, key);
        }
    }
}

void rotate(int a) // 维持小顶堆
{
    int fa = tp[a].father;
    while (fa != -1) {
        if (tp[a].weight < tp[fa].weight) {
            if (a == tp[fa].left) right_rotate(fa);
            else left_rotate(fa);
            fa = tp[a].father;
        } else {
            break;
        }
    }
    if (fa == -1) root = a;
}

int find(int a, int key)
{
    int cur = a, pre = -1;
    while (cur != -1) {
        if (tp[cur].key > key) {
            pre = cur;
            cur = tp[cur].left;
        } else if (tp[cur].key < key) {
            pre = cur;
            cur = tp[cur].right;
        } else {
            return key;
        }
    }
    while (pre != -1) {
        if (tp[pre].key < key) return tp[pre].key;
        pre = tp[pre].father;
    }
    return -2;
}

void print(int a)
{
    if (a == -1) return;
    print(tp[a].left);
    printf("%d(%d) ", a, tp[a].key);
    print(tp[a].right);
}

int main(int argc, char const *argv[])
{
    //freopen("in", "r", stdin);
    root = -1;
    treap_cnt = 0;
    int n;
    char op[2];
    int k;
    scanf("%d", &n);
    while (n--) {
        scanf("%s%d", op, &k);
        if (*op == ‘I‘) {
            if (root == -1) root = new_treap(k, rand());
            else rotate(insert(root, k));
        } else {
            printf("%d\n", find(root, k));
        }
    }
    return 0;
}

poj1442,直接套模板,比较简单

/**
Treap 实现 名次树
功能: 1.找到排名为k的元素
       2.值为x的元素的名次
*/
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;

struct Node {
    Node * ch[2];   // 0左子树 1右子树
    int r;          // 随机优先级
    int v;          // 值
    int s;          // 以s为根的子树的大小
    Node(int v):v(v)
    {
        ch[0] = ch[1] = NULL;
        r = rand();
        s = 1;
    }
    bool operator<(const Node& rhs) const { // 按随机优先级排序
        return r < rhs.r;
    }
    int cmp(int x) const
    {
        if (x == v) return -1;
        return x < v ? 0 : 1;
    }
    void maintain() // 更新
    {
        s = 1;
        if (ch[0] != NULL) s += ch[0]->s;
        if (ch[1] != NULL) s += ch[1]->s;
    }
} ;

void rotate(Node* &o, int d) // d=0 代表左转, d=1代表右转
{
    Node* k = o->ch[d^1];
    o->ch[d^1] = k->ch[d];
    k->ch[d] = o;
    o->maintain();
    k->maintain();
    o = k;
}

void insert(Node* &o, int x) // o是根 x是插入的值
{
    if (o == NULL) {
        o = new Node(x);
    } else {
        int d = (x < o->v ? 0 : 1); // 不用cmp函数因为可能有重复的值
        insert(o->ch[d], x);
        if ((o->ch[d]->r) > (o->r)) rotate(o, d^1);
    }
    o->maintain();
}

void remove(Node* &o, int x)
{
    int d = o->cmp(x);
    if (d == -1) {
        Node* u = o;
        if (o->ch[0] != NULL && o->ch[1] != NULL) {
            int d2 = ((o->ch[0]->r) > (o->ch[1]->r) ? 1 : 0);
            rotate(o, d2);
            remove(o->ch[d2], x);
        } else {
            if (o->ch[0] == NULL) o = o->ch[1];
            else o = o->ch[0];
            delete u;
        }
    } else {
        remove(o->ch[d], x);
    }
    if (o != NULL) o->maintain();
}

int find(Node* &o, int x) // 因为remove和insert都没有查值存不存在 记得操作之前调用find
{
    while (o != NULL) {
        int d = o->cmp(x);
        if (d == -1) return 1; // exist
        else o = o->ch[d];
    }
    return 0;   // not exist
}

int kth(Node* &o, int k, int fg) // fg=1第k大的值 fg=0第k小的值 返回0表示没找到
{
    if (o == NULL || k <= 0 || k > o->s) return 0;
    int s = (o->ch[fg] == NULL ? 0 : o->ch[fg]->s);
    if (k == s+1) return o->v;
    else if (k <= s) return kth(o->ch[fg], k, fg);
    else return kth(o->ch[fg^1], k-s-1, fg);
}

void mergeto(Node* &src, Node* &dest)
{
    if (src->ch[0] != NULL) mergeto(src->ch[0], dest);
    if (src->ch[0] != NULL) mergeto(src->ch[1], dest);
    insert(dest, src->v);
    delete src;
    src = NULL;
}

const int N = 30005;
int a[N];
int main()
{
    //freopen("in", "r", stdin);
    int m, n;
    while (~scanf("%d%d", &m, &n)) {
        Node* root = NULL;
        for (int i = 1; i <= m; ++i) {
            scanf("%d", a+i);
        }
        int x = 0, u, cnt = 0;
        for (int i = 0; i < n; ++i) {
            scanf("%d", &u);
            while (cnt < u) {
                insert(root, a[++cnt]);
            }
            printf("%d\n", kth(root, ++x, 0));
        }
    }
    return 0;
}

hdu4557

每个结点加了一个元素t,排序查找都要考虑t

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
using namespace std;

struct Node {
    Node * ch[2];   // 0左子树 1右子树
    int r;          // 随机优先级
    int v;          // 值
    int t;
    int s;          // 以s为根的子树的大小
    Node(int v, int t):v(v), t(t)
    {
        ch[0] = ch[1] = NULL;
        r = rand();
        s = 1;
    }
    bool operator<(const Node& rhs) const { // 按随机优先级排序
        if (r == rhs.r) return t < rhs.t;
        return r < rhs.r;
    }
    int cmp(int x, int y) const
    {
        if (x == v && y == t) return -1;
        if (x == v) return y < t ? 0 : 1;
        return x < v ? 0 : 1;
    }
    void maintain() // 更新
    {
        s = 1;
        if (ch[0] != NULL) s += ch[0]->s;
        if (ch[1] != NULL) s += ch[1]->s;
    }
} ;

void rotate(Node* &o, int d) // d=0 代表左转, d=1代表右转
{
    Node* k = o->ch[d^1];
    o->ch[d^1] = k->ch[d];
    k->ch[d] = o;
    o->maintain();
    k->maintain();
    o = k;
}

void insert(Node* &o, int x, int y) // o是根 x是插入的值
{
    if (o == NULL) {
        o = new Node(x, y);
    } else {
        int d = o->cmp(x, y);
        insert(o->ch[d], x, y);
        if ((o->ch[d]->r) > (o->r)) rotate(o, d^1);
    }
    o->maintain();
}

void remove(Node* &o, int x, int y)
{
    int d = o->cmp(x, y);
    if (d == -1) {
        Node* u = o;
        if (o->ch[0] != NULL && o->ch[1] != NULL) {
            int d2 = ((o->ch[0]->r) > (o->ch[1]->r) ? 1 : 0);
            rotate(o, d2);
            remove(o->ch[d2], x, y);
        } else {
            if (o->ch[0] == NULL) o = o->ch[1];
            else o = o->ch[0];
            delete u;
        }
    } else {
        remove(o->ch[d], x, y);
    }
    if (o != NULL) o->maintain();
}

int nxt(Node* &o, int x, int &res) // 查找x后面的元素 (>=x的最小值
{
    if (o == NULL) return -1;
    if (o->v < x) return nxt(o->ch[1], x, res);
    res = o->v;
    int ans = nxt(o->ch[0], x, res);
    return ans == -1 ? o->t : ans;
}

void print(Node* &o)
{
    if (o == NULL) return ;
    print(o->ch[0]);
    printf("%d ", o->v);
    print(o->ch[1]);
}

int main()
{
freopen("in", "r", stdin);
    int T;
    cin >> T;
    int cas = 0;
    while (T--) {
        printf("Case #%d:\n", ++cas);
        int n;
        cin >> n;
        char op[10];
        string name;
        int abi, res;
        Node* root = NULL;
        map<int, string> mp;
        for (int i = 0; i < n; ++i) {
            scanf("%s", op);
            if (*op == ‘A‘) {
                cin >> name;
                scanf("%d",  &abi);
                mp[i] = name;
                insert(root, abi, i);
                printf("%d\n", root->s);
            } else {
                scanf("%d", &abi);
                int ans = nxt(root, abi, res);
                if (ans == -1) printf("WAIT...\n");
                else {
                    cout << mp[ans] << endl;
                    remove(root, res, ans);
                }
            }//printf("debug:"); print(root); printf("\n");
        }
    }
}

时间: 2024-10-12 19:38:27

Treap 模板 poj1442&hdu4557的相关文章

BZOJ 1588: Treap 模板

1588: [HNOI2002]营业额统计 Time Limit: 5 Sec  Memory Limit: 162 MBSubmit: 12171  Solved: 4352 Description 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额.分析营业情况是一项相当复杂的工作.由于节假日,大减价或者是其他情况的时候,营业额会出现一定的波动,当然一定的波

Treap模板

平衡树总是有用的,set由于过度封装没有办法实现找比x小的元素有多少个,这就显得很不方便了,所以封装了个Treap,万一以后用的着呢- -0 #pragma warning(disable:4996) #include <iostream> #include <cstring> #include <vector> #include <cstdio> #include <string> #include <algorithm> usin

【Treap模板详细注释】BZOJ3224-普通平衡树

模板题:D错因见注释 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 const int INF=0x7fffffff; 8 struct treap 9 { 10 treap* lson; 11 treap* rson; 12 int key;/

人生第一发treap模板

bzoj3224 模板参(chao)考(xi)了hzwer神犇,ORZ //treap #include<cstdio> #include<iostream> #include<cstdlib> using namespace std; struct node { int l,r,v,w,rnd,size; }; node tr[100011]; int num=0,root=0,size=0; void update(int k) { tr[k].size=tr[tr

POJ1442-查询第K大-Treap模板题

模板题,以后要学splay,大概看一下treap就好了. 1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 5 using namespace std; 6 7 const int maxn = 3e5+10; 8 int num[maxn],st[maxn]; 9 10 struct Treap{ 11 int size; 12 int key,fix; 13 Treap *ch[2];

BZOJ1208: [HNOI2004]宠物收养所 平衡树 Treap 模板题

Description 最近,阿Q开了一间宠物收养所.收养所提供两种服务:收养被 主人遗弃的宠物和让新的主人领养这些宠物.每个领养者都希望领养到自己满意的宠物,阿Q根据领养者的要求通过他自己发明的一个特殊的公式,得出该领养者希 望领养的宠物的特点值a(a是一个正整数,a<2^31),而他也给每个处在收养所的宠物一个特点值.这样他就能够很方便的处理整个领养宠物的过程 了,宠物收养所总是会有两种情况发生:被遗弃的宠物过多或者是想要收养宠物的人太多,而宠物太少. 1. 被遗弃的宠物过多时,假若到来一个

POJ 3481 Double Queue(Treap模板题)

Double Queue Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 15786   Accepted: 6998 Description The new founded Balkan Investment Group Bank (BIG-Bank) opened a new office in Bucharest, equipped with a modern computing environment provid

[临时]NULL00 Treap模板 已去除宏

1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <time.h> 4 5 struct node_t 6 { 7 node_t* left;//左节点 8 node_t* right;//右节点 9 int priority;//优先级 10 int key;//存储的关键字 11 }; 12 13 struct treap_t 14 { 15 node_t* root; 16 }; 17 18 //左旋转 1

BZOJ 3224 普通平衡树(treap模板题)

3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 14301  Solved: 6208 [Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作: 1. 插入x数 2. 删除x数(若有多个相同的数,因只删除一个) 3. 查询x数的排名(若有多个相同的数,因输出最小的排名) 4. 查询排名为x的数 5. 求x的前