• 【luogu P3369】普通平衡树(Treap 做法)


    普通平衡树

    题目链接:luogu P3369

    题目大意

    平衡树模板题,要求维护一些操作。
    插入一个数,删除一个数,查询一个数的排名,查询排名一直的数,找前驱后继。

    思路

    写 fhq Treap 之前突然发现自己剪贴板里面有个半年前写完的 Treap 没写题解,又发现没有一道 Treap 的题解,然后就过来补题解了。

    有旋 Treap 其实旋转和 splay 差不多,但只是旋转的条件和 splay 不一样,splay 是看你询问的点,而 Treap 是直接用随机数给每个点一个优先级,然后维护一个以这个优先级为关键字的大根堆。

    那其实就只有旋转和点的操作会不同,其它的操作和其他一般的平衡树都挺像的。

    具体实现看代码吧。

    代码

    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    
    using namespace std;
    
    int n, root, op, x, tot, way, new_root;
    int key[100001], size[100001], sum[100001], son[100001][2], rd[100001];
    
    void get_size(int x) {
    	size[x] = size[son[x][0]] + size[son[x][1]] + sum[x];
    	
    	return ;
    }
    
    void turn(int &root, int way) {//旋转
    	new_root = son[root][way ^ 1];
    	son[root][way ^ 1] = son[new_root][way];
    	son[new_root][way] = root;
    	get_size(root);
    	get_size(new_root);
    	root = new_root;
    	
    	return ;
    }
    
    void push_num(int &root, int x) {
    	if (!root) {
    		root = ++tot;
    		key[root] = x;
    		size[root] = 1;
    		sum[root] = 1;
    		rd[root] = rand();//随机给一个用来比较的值
    		
    		return ;
    	}
    	
    	if (x == key[root]) {
    		size[root]++;
    		sum[root]++;
    		
    		return ;
    	}
    	
    	way = x > key[root];
    	push_num(son[root][way], x);
    	if (rd[root] < rd[son[root][way]])//如果不符合就要转
    		turn(root, way ^ 1);
    	
    	get_size(root);
    	
    	return ;
    }
    
    void delete_num(int &root, int x) {//转到最上面再删
    	if (!root) return ;
    	
    	if (key[root] != x) {
    		way = x > key[root];
    		delete_num(son[root][way], x);
    		
    		get_size(root);
    		
    		return ;
    	}
    	
    	if (!son[root][0] && !son[root][1]) {
    		sum[root]--;
    		size[root]--;
    		
    		if (sum[root] == 0) root = 0;
    		
    		get_size(root);
    		
    		return ;
    	}
    	if (son[root][0] && !son[root][1]) {
    		turn(root, 1);
    		delete_num(son[root][1], x);
    		
    		get_size(root);
    		
    		return ;
    	}
    	if (!son[root][0] && son[root][1]) {
    		turn(root, 0);
    		delete_num(son[root][0], x);
    		
    		get_size(root);
    		
    		return ;
    	}
    	if (son[root][0] && son[root][1]) {
    		way = (rd[son[root][0]] < rd[son[root][1]]) ^ 1;
    		turn(root, way);
    		delete_num(son[root][way], x);
    		
    		get_size(root);
    		
    		return ;
    	}
    	
    	return ;
    }
    
    int find_num(int root, int x) {//像普通平衡树的做法(后面都跟一般的平衡树差不多)
    	if (!root) return 0;
    	
    	if (x == key[root]) return size[son[root][0]] + 1;
    	
    	if (x < key[root]) return find_num(son[root][0], x);
    	
    	if (x > key[root]) return size[son[root][0]] + sum[root] + find_num(son[root][1], x);
    }
    
    int find_key(int root, int x) {
    	if (!root) return 0;
    	
    	if (x <= size[son[root][0]]) return find_key(son[root][0], x);
    	
    	if (x <= size[son[root][0]] + sum[root]) return key[root];
    	
    	if (x > size[son[root][0]] + sum[root]) return find_key(son[root][1], x - size[son[root][0]] - sum[root]);
    }
    
    int pre(int root, int x) {
    	if (!root) return -2147483647;
    	
    	if (x <= key[root]) return pre(son[root][0], x);
    	
    	if (x > key[root]) return max(pre(son[root][1], x), key[root]);
    }
    
    int suf(int root, int x) {
    	if (!root) return 2147483647;
    	
    	if (x >= key[root]) return suf(son[root][1], x);
    	
    	if (x < key[root]) return min(suf(son[root][0], x), key[root]);
    }
    
    int main() {
    	srand(114514);
    	
    	scanf("%d", &n);
    	for (int i = 1; i <= n; i++) {
    		scanf("%d %d", &op, &x);
    		
    		if (op == 1) {
    			push_num(root, x);
    			continue;
    		}
    		if (op == 2) {
    			delete_num(root, x);
    			continue;
    		}
    		if (op == 3) {
    			printf("%d
    ", find_num(root, x));
    			continue;
    		}
    		if (op == 4) {
    			printf("%d
    ", find_key(root, x));
    			continue;
    		}
    		if (op == 5) {
    			printf("%d
    ", pre(root, x));
    			continue;
    		}
    		if (op == 6) {
    			printf("%d
    ", suf(root, x));
    			continue;
    		}
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    LeetCode T98.Validate Binary Search Tree/验证二叉搜索树
    LeetCode T45.Jump Game Ⅱ/跳跃游戏Ⅱ
    LeetCode T53.Maximum Subarray/最大子序和
    LeetCode T3.Longest Substring Without Repeating Characters/无重复最长子串
    LeetCode T21.Merge Two Sorted Lists/合并两个有序链表
    LeetCode T202.Happy Number/寻找快乐数
    LeetCode T1095.Find in Mountain Array/山脉数组中查找目标值
    XCTF-WEB—i-got-id-200:perl网页文件+ARGV上传造成任意文件读取
    思维导图爆破
    UNCTF2020-Reverse:re_checkin
  • 原文地址:https://www.cnblogs.com/Sakura-TJH/p/luogu_P3369_Treap.html
Copyright © 2020-2023  润新知