• 洛谷 P3369 【模板】普通平衡树 (Treap)


    题目链接:P3369 【模板】普通平衡树

    题意

    构造一种数据结构满足给出的 6 种操作。

    思路

    平衡树

    平衡树的模板题。

    先学习了一下 Treap。

    Treap 在插入结点时给该结点随机生成一个额外的权值,然后用该权值维护一个大根堆,如果某个结点不满足大根堆的性质,就通过旋转与父节点交换。

    对于删除某个结点,通过不断向下旋转直至变成叶子结点,然后直接删除即可。

    模板来自《算法竞赛进阶指南》

    代码

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e5 + 10;
    const int inf = 0x3f3f3f3f;
    
    struct Treap {
    	int l, r;
    	int val, dat;
    	int cnt, size;
    } a[maxn];
    int tot, root;
    int n;
    
    int new_node(int val) {
    	a[++tot].val = val;
    	a[tot].dat = rand();
    	a[tot].cnt = a[tot].size = 1;
    	return tot;
    }
    
    void update(int p) {
    	a[p].size = a[a[p].l].size + a[a[p].r].size + a[p].cnt;
    }
    
    void build() {
    	new_node(-inf), new_node(inf);
    	root = 1, a[1].r = 2;
    	update(root);
    }
    
    int get_rank(int p, int val) {
    	if (p == 0) return 0;
    	if (val == a[p].val) return a[a[p].l].size + 1;
    	if (val < a[p].val) return get_rank(a[p].l, val);
    	return get_rank(a[p].r, val) + a[a[p].l].size + a[p].cnt;
    }
    
    int get_val(int p, int rank) {
    	if (p == 0) return inf;
    	if (a[a[p].l].size >= rank) return get_val(a[p].l, rank);
    	if (a[a[p].l].size + a[p].cnt >= rank) return a[p].val;
    	return get_val(a[p].r, rank - a[a[p].l].size - a[p].cnt);
    }
    
    // 右旋
    void zig(int &p) {
    	int q = a[p].l;
    	a[p].l = a[q].r, a[q].r = p, p = q;
    	update(a[p].r), update(p);
    }
    
    // 左旋
    void zag(int &p) {
    	int q = a[p].r;
    	a[p].r = a[q].l, a[q].l = p, p = q;
    	update(a[p].l), update(p);
    }
    
    void add(int &p, int val) {
    	if (p == 0) {
    		p = new_node(val);
    		return;
    	}
    	if (val == a[p].val) {
    		a[p].cnt++;
    	} else if (val < a[p].val) {
    		add(a[p].l, val);
    		if (a[p].dat < a[a[p].l].dat) zig(p);
    	} else {
    		add(a[p].r, val);
    		if (a[p].dat < a[a[p].r].dat) zag(p);
    	}
    	update(p);
    }
    
    int get_pre(int val) {
    	int ans = 1; // a[1].val==-inf
    	int p = root;
    	while (p) {
    		if (val == a[p].val) {
    			if (a[p].l > 0) {
    				p = a[p].l;
    				while (a[p].r > 0) p = a[p].r;
    				ans = p;
    			}
    			break;
    		}
    		if (a[p].val < val && a[p].val > a[ans].val) ans = p;
    		p = val < a[p].val ? a[p].l : a[p].r;
    	}
    	return a[ans].val;
    }
    
    int get_next(int val) {
    	int ans = 2; // a[2].val==inf
    	int p = root;
    	while (p) {
    		if (val == a[p].val) {
    			if (a[p].r > 0) {
    				p = a[p].r;
    				while (a[p].l > 0) p = a[p].l;
    				ans = p;
    			}
    			break;
    		}
    		if (a[p].val > val && a[p].val < a[ans].val) ans = p;
    		p = val < a[p].val ? a[p].l : a[p].r;
    	}
    	return a[ans].val;
    }
    
    // 把非叶子结点旋转至叶子结点后直接删除
    void remove(int &p, int val) {
    	if (p == 0) return;
    	if (val == a[p].val) {
    		if (a[p].cnt > 1) {
    			a[p].cnt--, update(p);
    			return;
    		}
    		if (a[p].l || a[p].r) { // 不是叶子节点,向下旋转
    			if (a[p].r == 0 || a[a[p].l].dat > a[a[p].r].dat)
    				zig(p), remove(a[p].r, val);
    			else
    				zag(p), remove(a[p].l, val);
    			update(p);
    		}
    		else p = 0; // 叶子节点,删除
    		return;
    	}
    	val < a[p].val ? remove(a[p].l, val) : remove(a[p].r, val);
    	update(p);
    }
    
    int main() {
    	build();
    	cin >> n;
    	while (n--) {
    		int op, x;
            cin >> op >> x;
    
    		if(op == 1) {
    			add(root, x);
            } else if(op == 2) {
    			remove(root, x);
            } else if(op == 3) {
                cout << get_rank(root, x) - 1 << endl;
            } else if(op == 4) {
                cout << get_val(root, x + 1) << endl;
            } else if(op == 5) {
                cout << get_pre(x) << endl;
            } else {
                cout << get_next(x) << endl;
            }
    	}
        return 0;
    }
    
  • 相关阅读:
    elementui el-upload弹框确定是否上传文件 需要在上传文件前,可以进行弹窗控制是否上传 upload
    postman 下载地址
    axios 详解
    jQuery点击按钮 切换样式
    基于Vant框架的下拉刷新和上滑加载
    Core Animation一些Demo总结 (动态切换图片、大转盘、图片折叠、进度条等动画效果)
    鼠标悬停显示隐藏省略文字
    遮罩层
    二维码网站
    看图说话
  • 原文地址:https://www.cnblogs.com/wulitaotao/p/11588123.html
Copyright © 2020-2023  润新知