【pbds tree 入门 | 题解】P3369 【模板】普通平衡树 [pbds]

参考:

洛谷 langmouren

前导:

如果你是初学者,你就只需要知道 pbds 比 FHQ Treap 码量小很多

能起到一样的作用,好打好调,比 FHQ 稍微慢点,比赛还可以用。

怎么样?是不是动心了?

解析:

(1)编译环境

首先,我们需要添加此头文件:

#include<bits/extc++.h>
using namespace __gnu_pbds;

windos 环境添加之后会有编译错误,会跳转到这里:

不要怕,点这个:

然后到这里:

把 68 行的 ifdef 改成 ifndef,别忘了按 Ctrl s 保存!

就搞定啦,可以正常使用 pbds 了。

(2)了解 pbds tree

它封装了 hash、tree、trie、priority_queue 四种数据结构,我们先讲最常用的 tree。

定义格式:

tree<数据类型,无映射,排列方式,树的类型,更新方式> 变量名称;

数据类型:int、long long 等,一般使用 long long
无映射:使用 null_type
排列方式:less 从小到大 greater 从大到小,本题使用 less<long long>
树的类型:rd_tree、ov_tree、splay_tree,我下面有介绍,建议使用 rd_tree 即红黑树,因为它快
更新方式:除非你需要自写 update,否则使用 tree_order_statistics_node_update

关于一些平衡树知识拓展:

数据结构适用场景时间复杂度小 tips

rd_tree

红黑树

通用(如 STL)

均摊 O(log \ N)常数较大,最坏情况查询比 AVL 慢

ov_tree

AVL 树

高频查询、

低频修改

O(log \ N)删除插入慢

splay_tree

伸展树

频繁访问

同一节点

均摊

O(log \ N)

最坏 O(N)

时间不可控

说回 pbds tree,它的可用操作:

treap.insert(x); 			//插入 x
treap.erase(x); 			//删除 x
treap.order_of_key(x);		//返回 x的排名
treap.find_by_order(k); 	//返回第 k 小的值的迭代器
treap.lower_bound(x); 		//返回第一个大于等于 x 的元素的迭代器
treap.upper_bound(x); 		//返回第一个大于 x 的元素的迭代器

treap.join(b); 				//树的合并
treap.split(a, b); 			//树的分裂

(迭代器指针要想取得值,都要在前面加上 “ * ”

然而还有个问题,红黑树会自动去重,所以我们把数据哈希。

先左移 20 位,再加上当前 for 的 i。

也有数据会特意卡哈希,改左移位数或者用读入时间都可以避免被卡。

(3)本题代码

#include<bits/stdc++.h>
#include<bits/extc++.h>
using namespace std;
using namespace __gnu_pbds;

typedef long long LL;

tree<LL, null_type, less<LL>, rb_tree_tag, tree_order_statistics_node_update> treap;

int main() {
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++) {
		int opt; LL x;
		cin >> opt >> x;
		if (opt == 1) {
			treap.insert( (x << 20) + i );
		}
		else if (opt == 2) {
			treap.erase(treap.lower_bound(x << 20));
		}
		else if (opt == 3) {
			cout << ( treap.order_of_key(x << 20) + 1 ) << "\n";
		}
		else if (opt == 4) {
			cout << ( (*treap.find_by_order(x - 1)) >> 20 ) << "\n";
		}
		else if (opt == 5) {
			auto t = treap.lower_bound(x << 20);
			t--;
			cout << ( (*t) >> 20 ) << "\n";
		}
		else if (opt == 6) {
			cout << ( (*treap.upper_bound( (x << 20) + n )) >> 20 ) << "\n";
		}
	}
	return 0;
}

实测在洛谷上比 FHQ 慢 3/4 倍,校内 oj 慢 3 倍。

ps:pbds_tree 并不支持可持久化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值