pbds学习 洛谷P3369 【模板】普通平衡树

本文介绍了一种使用C++中的PBDS(Persistent Boost Data Structures)库实现树状数组的高级方法,用于解决洛谷P3369问题。通过结合左移右移操作和树状数组特性,该方法能够高效处理插入、删除、查找排名、前驱、后继等操作。

https://www.luogu.org/problem/P3369

#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
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> tr;

int main()
{
	int n,op;ll x,ans;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%lld",&op,&x);
		if(op==1)
			tr.insert((x<<20)+i);
		if(op==2)
			tr.erase(tr.lower_bound(x<<20));
		if(op==3)
			printf("%d\n",tr.order_of_key(x<<20)+1);
		if(op==4)
		{
			ans=*tr.find_by_order(x-1);
			printf("%lld\n",ans>>20);
		}
		if(op==5)
		{
			ans=*--tr.lower_bound(x<<20);
			printf("%lld\n",ans>>20);
		}
		if(op==6)
		{
			ans=*tr.upper_bound((x<<20)+n);
			printf("%lld\n",ans>>20);
		}
	}
	return 0;
}

 

<think>我们被要求用pbds(Policy-Based Data Structures)来实现一个trie树的模板题。pbds是GNU C++库的一部分,它提供了一些高级的数据结构,包括trie树。在pbds中,trie树通常用于字符串的前缀匹配或者存储一组字符串。 模板题通常要求实现一个trie树,支持插入字符串、查询字符串是否存在、查询前缀是否存在等功能。使用pbds可以非常方便地实现这些功能。 在C++中,我们需要包含头文件: #include <ext/pb_ds/assoc_container.hpp> #include <ext/pb_ds/trie_policy.hpp> using namespace __gnu_pbds; 然后,我们可以定义一个trie类型。pbds中的trie树叫做`trie`,它位于`__gnu_pbds`命名空间。 下面是一个使用pbds trie树实现的模板,包括插入和查找功能。 注意:pbds的trie树支持多种操作,包括插入、删除、查找,以及前缀匹配等。 示例代码: ```cpp #include <bits/stdc++.h> #include <ext/pb_ds/assoc_container.hpp> #include <ext/pb_ds/trie_policy.hpp> using namespace std; using namespace __gnu_pbds; // 定义trie类型 typedef trie<string, null_type, trie_string_access_traits<>, pat_trie_tag, trie_prefix_search_node_update> trie_type; int main() { trie_type T; // 插入字符串 T.insert("hello"); T.insert("world"); T.insert("hey"); T.insert("how"); // 查找整个字符串是否存在 if (T.find("hello") != T.end()) { cout << "hello is in the trie" << endl; } // 前缀搜索:查找以"he"为前缀的所有字符串 auto range = T.prefix_range("he"); for (auto it = range.first; it != range.second; ++it) { cout << *it << endl; // 输出:hello, hey } // 删除字符串 T.erase("hello"); return 0; } ``` 在这个示例中,我们使用了`trie_prefix_search_node_update`作为更新策略,这样我们就可以使用`prefix_range`方法来进行前缀搜索。 注意:`trie_string_access_traits<>`是用于字符串的trie特性。 但是请注意,pbds的trie树在竞赛中并不常用,因为其相对较慢且内存消耗较大,但在某些情况下可以快速实现功能。 现在,根据要求,我们需要在回答后提出3-5个相关问题。 §§相关问题§§ 1. PBDS中的trie树支持哪些基本操作? 2. 使用PBDS trie树进行前缀搜索时,返回的迭代器范围如何遍历? 3. 在PBDS trie树中,如何删除一个字符串? 4. PBDS trie树与传统的数组实现的trie树相比,有哪些优缺点? 5. 如何在使用PBDS trie树时处理非字符串类型的数据? </think>以下是使用 C++ PBDS (Policy-Based Data Structures) 实现 Trie 树的模板代码,支持字符串插入、查询和前缀搜索功能: ```cpp #include <bits/stdc++.h> #include <ext/pb_ds/assoc_container.hpp> #include <ext/pb_ds/trie_policy.hpp> using namespace std; using namespace __gnu_pbds; // 定义 PBDS trie 类型 typedef trie<string, null_type, trie_string_access_traits<>, // 字符串特性 pat_trie_tag, // PATRICIA trie trie_prefix_search_node_update> Trie; // 支持前缀搜索 int main() { Trie T; // 插入操作 T.insert("apple"); T.insert("app"); T.insert("banana"); // 精确查找 cout << "Contains 'app': " << (T.find("app") != T.end()) << endl; // 1 cout << "Contains 'apps': " << (T.find("apps") != T.end()) << endl; // 0 // 前缀搜索(查找以"app"开头的所有字符串) auto range = T.prefix_range("app"); cout << "Prefix 'app': "; for (auto it = range.first; it != range.second; ++it) cout << *it << " "; // 输出 app apple cout << endl; // 删除操作 T.erase("app"); cout << "After delete, contains 'app': " << (T.find("app") != T.end()) << endl; // 0 return 0; } ``` ### 关键说明: 1. **头文件**:需包含 PBDS 的 `trie_policy.hpp` 2. **trie 类型**: - `trie_string_access_traits<>`:字符串专用特性 - `pat_trie_tag`:使用 PATRICIA 压缩算法 - `trie_prefix_search_node_update`:启用前缀搜索功能 3. **核心操作**: - `insert(str)`:插入字符串 - `find(str)`:精确查找(返回迭代器) - `prefix_range(prefix)`:获取前缀匹配的迭代器范围 - `erase(str)`:删除字符串 ### 性能特点: - **时间复杂度**:插入/查询/删除均为 $O(L)$($L$为字符串长度) - **空间优化**:PATRICIA trie 自动压缩单分支路径 - **前缀搜索**:通过 `prefix_range` 高效获取所有前缀匹配项
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值