这一次,我们来了解普通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普及版讲解的更多相关文章

  1. [您有新的未分配科技点] 无旋treap:从单点到区间(例题 BZOJ1500&NOI2005 维护数列 )

    1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MB Description Input 输入的第1 行包含两个数N 和M(M ≤20 ...

  2. [您有新的未分配科技点]博弈论进阶:似乎不那么恐惧了…… (SJ定理,简单的基础模型)

    这次,我们来继续学习博弈论的知识.今天我们会学习更多的基础模型,以及SJ定理的应用. 首先,我们来看博弈论在DAG上的应用.首先来看一个小例子:在一个有向无环图中,有一个棋子从某一个点开始一直向它的出 ...

  3. [您有新的未分配科技点]博弈论入门:被博弈论支配的恐惧(Nim游戏,SG函数)

    今天初步学习了一下博弈论……感觉真的是好精妙啊……希望这篇博客可以帮助到和我一样刚学习博弈论的同学们. 博弈论,又被称为对策论,被用于考虑游戏中个体的预测行为和实际行为,并研究他们的应用策略.(其实这 ...

  4. [您有新的未分配科技点]无旋treap:从好奇到入门(例题:bzoj3224 普通平衡树)

    今天我们来学习一种新的数据结构:无旋treap.它和splay一样支持区间操作,和treap一样简单易懂,同时还支持可持久化. 无旋treap的节点定义和treap一样,都要同时满足树性质和堆性质,我 ...

  5. [您有新的未分配科技点]数位DP:从板子到基础(例题 bzoj1026 windy数 bzoj3131 淘金)

    只会统计数位个数或者某种”符合简单规律”的数并不够……我们需要更多的套路和应用 数位dp中常用的思想是“分类讨论”思想.下面我们就看一道典型的分类讨论例题 1026: [SCOI2009]windy数 ...

  6. [您有新的未分配科技点]数位dp:从懵X到板子(例题:HDU2089 不要62)

    数位dp主要用来处理一系列需要数数的问题,一般套路为“求[l,r]区间内满足要求的数/数位的个数” 要求五花八门……比如“不出现某个数字序列”,“某种数的出现次数”等等…… 面对这种数数题,暴力的想法 ...

  7. [您有新的未分配科技点][BZOJ3545&BZOJ3551]克鲁斯卡尔重构树

    这次我们来搞一个很新奇的知识点:克鲁斯卡尔重构树.它也是一种图,是克鲁斯卡尔算法求最小生成树的升级版首先看下面一个问题:BZOJ3545 Peaks. 在Bytemountains有N座山峰,每座山峰 ...

  8. 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 ...

  9. Elasticsearch 学习之 分片未分配原因

    分片未分配的原因主要有: 1)INDEX_CREATED:由于创建索引的API导致未分配.2)CLUSTER_RECOVERED :由于完全集群恢复导致未分配.3)INDEX_REOPENED :由于 ...

随机推荐

  1. python2.7无法安装python-ldap、django-auth-ldap

    1.安装报错信息: error: Microsoft Visual C++ 9.0 is required. Get it from http://aka.ms/vcpython27 或者fatal ...

  2. Java的初始化与清理

    大家都知道,Java是站在巨人的肩上成功的,它是在C&C++的基础上进一步的开发,投入面向对象开发的怀抱.Java吸取了很多以前的教训,加入自己很多独创的方式.在程序语言发展初期,许多C程序员 ...

  3. SDN前瞻 网络的前世今生

    本文基于SDN导论的视频而成:SDN导论 目前网络层面流行的技术概念:虚拟中心:公有云私有云:数据中心等等. SDN主要的模拟器:Mininet OpenDaylight(Cisco) ONOS(AT ...

  4. HDU 3435 A new Graph Game(最小费用流:有向环权值最小覆盖)

    http://acm.hdu.edu.cn/showproblem.php?pid=3435 题意:有n个点和m条边,你可以删去任意条边,使得所有点在一个哈密顿路径上,路径的权值得最小. 思路: 费用 ...

  5. 创建maven或者Gradle项目的时候GroupId和ArtifactId以及Version是什么意思?

    GroupId 是项目组织的唯一标识符,在实际开发中对应JAVA的包的结构,就是main目录里java的目录结构,如 ‘com.itcast.demo’. ArtifactId是项目的唯一标识符,在实 ...

  6. Ubuntu16 nginx安装http_image_filter_module模块

    目录 配置image_filter 配置 重启nginx 如何安装呢? 安装image_filter模块依赖的库. 查看之前的配置 添加上图片模块[由于它是系统模块,不需要额外下载,直接添加就可以了] ...

  7. 何时使用MQ ?

    何时使用MQmq作为一种基础中间件在互联网项目中有着大量的使用. 一种技术的产生自然是为了解决某种需求,通常来说是以下场景: 需要跨进程通信:B系统需要A系统的输出作为输入参数.当A系统的输出能力远远 ...

  8. bzoj1058: [ZJOI2007]报表统计 stl xjbg

    小Q的妈妈是一个出纳,经常需要做一些统计报表的工作.今天是妈妈的生日,小Q希望可以帮妈妈分担一些工作,作为她的生日礼物之一.经过仔细观察,小Q发现统计一张报表实际上是维护一个可能为负数的整数数列,并且 ...

  9. POJ 3414 dfs 回溯

    题目链接:http://poj.org/problem?id=3414 题意:三个值A, B, C, A和B是两个杯子的容量,问最短操作数使A或者B里的水量是C.有三种操作. 思路:dfs.暴力 很简 ...

  10. easyui combotree 异步树 前端写法js

    简要说下使用场景: combotree下拉框第一次加载时,请求一个接口,页面上展示顶层节点们(可以理解为最顶层的节点,比如所有的一级公司): 当点击其中一个节点前面的小三角展开时,再次请求服务器接口( ...