[您有新的未分配科技点]可,可,可持久化!?------0-1Trie和可持久化Trie普及版讲解
这一次,我们来了解普通Trie树的变种:0-1Trie以及在其基础上产生的可持久化Trie(其实,普通的Trie也可以可持久化,只是不太常见)
先简单介绍一下0-1Trie:一个0-1Trie节点只有两个子节点,分别代表0和1;从根节点开始,第一层代表限制的最高位,依次往下直到最底层,代表二进制第0位。
0-1Trie上的一条链所表示的数字,就是Trie树中的一个数字。0-1Trie除了节点和插入方式与普通的Trie树略有不同之外,其他操作都是和Trie树完全一样的。在维护这个节点插入过的数的个数size之后,0-1Trie甚至可以做一些平衡树的题……
下面给2道比较简单的例题:
bzoj3689 异或之 http://www.lydsy.com/JudgeOnline/problem.php?id=3689
bzoj3224 普通平衡树 http://www.lydsy.com/JudgeOnline/problem.php?id=3224
值得注意的是,0-1Trie无法处理负权值,因此,我们可以给每个数加上一个大的修正值delta,使得所有值都成为非负的。最后我们在减去delta即可。
下面给出0-1Trie版的普通平衡树代码,很短,但是的确可以AC:
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const int inf=0x7fffffff,delta=;
LL bin[];
struct Trie
{
Trie *ch[];int size;
Trie(){size=;ch[]=ch[]=NULL;}
}*null=new Trie(),*root;
inline Trie* newTrie(){Trie *o=new Trie();o->ch[]=o->ch[]=null;return o;}
inline void insert(int x)
{
Trie *rt=root;
for(int i=;~i;i--)
{
int d=(x&bin[i])>>i;
if(rt->ch[d]==null)rt->ch[d]=newTrie();
rt=rt->ch[d],rt->size++;
}
}
inline void del(int x)
{
Trie *rt=root;
for(int i=;~i;i--)
rt=rt->ch[(x&bin[i])>>i],rt->size--;
}
inline int getrank(int x)
{
Trie *rt=root;int ret=;
for(int i=;~i;i--)
{
if((x&bin[i])>>i)ret+=rt->ch[]->size;
rt=rt->ch[(x&bin[i])>>i];
}
return ret;
}
inline int getval(int rank)
{
Trie *rt=root;int ret=;
for(int i=;~i;i--)
{
if(rt->ch[]->size>=rank)rt=rt->ch[];
else rank-=rt->ch[]->size,ret|=bin[i],rt=rt->ch[];
}
return ret;
}
int main()
{
bin[]=;for(int i=;i<=;i++)bin[i]=bin[i-]<<;
root=newTrie();null->ch[]=null->ch[]=null;
int m,opt,x;scanf("%d",&m);
while(m--)
{
scanf("%d%d",&opt,&x);
switch(opt)
{
case :insert(x+delta);break;
case :del(x+delta);break;
case :printf("%d\n",getrank(x+delta)+);break;
case :printf("%d\n",getval(x)-delta);break;
case :printf("%d\n",getval(getrank(x+delta))-delta);break;
case :printf("%d\n",getval(getrank(x+delta+)+)-delta);break;
}
}
}
接下来,我们在0-1Trie的基础上,介绍可持久化Trie。
可持久化Trie树和前面两种可持久化数据结构一样,也是通过复制节点来实现可持久化操作。
在插入的时候,我们也是复制路径上的节点,由于可持久化Trie和主席树一样具有区间可减性,所以我们直接像主席树那样区间相减即可。
具体代码,长得和之前的可持久化Treap差不多……下面给出插入的代码(可能比较丑……)
//bin[i]数组为预处理的2的i次方
void insert(Trie *&o,Trie *old,int val,int i)
{
if(i<)return;
int d=((val&bin[i])==bin[i]);//判断当前为是0还是1
o->ch[d]=newTrie();o->ch[d^]=old->ch[d^];
o->ch[d]->size=old->ch[d]->size+;
insert(o->ch[d],old->ch[d],val,i-);
}
可持久化Trie树经常用来处理与异或有关的k小问题。一般来说,我们都是把0-1Trie可持久化来维护数字运算,很少有把字符串的Trie可持久化的题目。
这里再给出两道可持久化Trie的基础题:
bzoj4103[Thu Summer Camp 2015]异或运算 http://www.lydsy.com/JudgeOnline/problem.php?id=4103
我的题解:http://www.cnblogs.com/LadyLex/p/7281945.html
bzoj3166[Heoi2013]Alo http://www.lydsy.com/JudgeOnline/problem.php?id=3166
我的题解:http://www.cnblogs.com/LadyLex/p/7281860.html
可持久化Trie是一种和主席树同样优秀的数据结构,无疑是一种新的解题思路。希望大家能从我的博客中有所收获:)
[您有新的未分配科技点]可,可,可持久化!?------0-1Trie和可持久化Trie普及版讲解的更多相关文章
- [您有新的未分配科技点] 无旋treap:从单点到区间(例题 BZOJ1500&NOI2005 维护数列 )
1500: [NOI2005]维修数列 Time Limit: 10 Sec Memory Limit: 64 MB Description Input 输入的第1 行包含两个数N 和M(M ≤20 ...
- [您有新的未分配科技点]博弈论进阶:似乎不那么恐惧了…… (SJ定理,简单的基础模型)
这次,我们来继续学习博弈论的知识.今天我们会学习更多的基础模型,以及SJ定理的应用. 首先,我们来看博弈论在DAG上的应用.首先来看一个小例子:在一个有向无环图中,有一个棋子从某一个点开始一直向它的出 ...
- [您有新的未分配科技点]博弈论入门:被博弈论支配的恐惧(Nim游戏,SG函数)
今天初步学习了一下博弈论……感觉真的是好精妙啊……希望这篇博客可以帮助到和我一样刚学习博弈论的同学们. 博弈论,又被称为对策论,被用于考虑游戏中个体的预测行为和实际行为,并研究他们的应用策略.(其实这 ...
- [您有新的未分配科技点]无旋treap:从好奇到入门(例题:bzoj3224 普通平衡树)
今天我们来学习一种新的数据结构:无旋treap.它和splay一样支持区间操作,和treap一样简单易懂,同时还支持可持久化. 无旋treap的节点定义和treap一样,都要同时满足树性质和堆性质,我 ...
- [您有新的未分配科技点]数位DP:从板子到基础(例题 bzoj1026 windy数 bzoj3131 淘金)
只会统计数位个数或者某种”符合简单规律”的数并不够……我们需要更多的套路和应用 数位dp中常用的思想是“分类讨论”思想.下面我们就看一道典型的分类讨论例题 1026: [SCOI2009]windy数 ...
- [您有新的未分配科技点]数位dp:从懵X到板子(例题:HDU2089 不要62)
数位dp主要用来处理一系列需要数数的问题,一般套路为“求[l,r]区间内满足要求的数/数位的个数” 要求五花八门……比如“不出现某个数字序列”,“某种数的出现次数”等等…… 面对这种数数题,暴力的想法 ...
- [您有新的未分配科技点][BZOJ3545&BZOJ3551]克鲁斯卡尔重构树
这次我们来搞一个很新奇的知识点:克鲁斯卡尔重构树.它也是一种图,是克鲁斯卡尔算法求最小生成树的升级版首先看下面一个问题:BZOJ3545 Peaks. 在Bytemountains有N座山峰,每座山峰 ...
- Prism5.0新内容 What's New in Prism Library 5.0 for WPF(英汉对照版)
Prism 5.0 includes guidance in several new areas, resulting in new code in the Prism Library for WPF ...
- Elasticsearch 学习之 分片未分配原因
分片未分配的原因主要有: 1)INDEX_CREATED:由于创建索引的API导致未分配.2)CLUSTER_RECOVERED :由于完全集群恢复导致未分配.3)INDEX_REOPENED :由于 ...
随机推荐
- Fiddler 手机无法上网问题
一.Fiddler版本升级后需要升级netframework 二.每一个域名点击需要授权 出现此页面依次点击显示详细信息和访问此网站. 有时候网站白板,可能是cdn域名没有授权的原因,可以直接在url ...
- 利用ansible进行自动化构建etcd集群
上一篇进行了手动安装etcd集群,此篇利用自动化工具ansible为三个节点构建etcd集群 环境: master:192.168.101.14,node1:192.168.101.15,node2: ...
- 20145325张梓靖 《Java程序设计》第16周课程总结
20145325张梓靖 <Java程序设计>第16周课程总结 实验报告链接汇总 实验一 "Java开发环境的熟悉" 实验二 "Java面向对象程序设计&quo ...
- ubuntu18.04系统安装+基本环境配置【原创】
平台信息:PC:ubuntu18.04.i5.七彩虹GTX1060显卡.固态硬盘.机械硬盘 作者:庄泽彬(欢迎转载,请注明作者) 说明:在原本的电脑买一个独立显卡,装上去之后,出了各种问题,虽然后面勉 ...
- package 'orocos-bfl' not found
-- ==> add_subdirectory(bp_fusion) -- checking for module 'orocos-bfl' -- package 'orocos-bfl' no ...
- nil 作比较时应该加上双引号 "
> type(X) nil > type(X)==nil false > type(X)=="nil" true >
- python 字典的合并
d1 = {, } d2 = {, } d = d1.copy() d.update(d2) print(d)
- JavaScript变量: 变量命名原则
变量的命名相对而言没有太多的技术含量,今天整理有关于变量命名相关的原则,主要是想告诉大家,虽然命名没有技术含量,但对于个人编码,或者说一个团队的再次开发及阅读是相当有用的.良好的书写规范可以让你的Ja ...
- 缓存cache(5.2新:redis): gem faker (6600✨) 命令行工具curl(系统内置,可在git上看到文档)
⚠️本章节记录缓存的一些方法的用法案例,配合这篇博客一起阅读:https://i.cnblogs.com/EditPosts.aspx?postid=8776632 前置种子 https://git ...
- 素数对猜想之python3实现
题目 让我们定义dn为:dn=pn+1−pn,其中pi是第i个素数.显然有d1=1,且对于n>1有dn是偶数.“素数对猜想”认为“存在无穷多对相邻且差为 ...