WARNING:以下代码未经测试,若发现错误,欢迎指出qwq~

Trie树(字典树)

一种简单的数据结构,可存储大量字符串,可在$O(len)$的时间内完成插入,删除,查找等操作。

下面是一个简单的例子,对于abc,abd,abcd,bcd这四个字符串建Trie树,如下图:

其中,红色节点为一个字符串的结尾。对于任意节点,从根节点到该节点路径上字符组成的字符串即为该节点表示的字符串。

基本操作

相关变量

1 int root,cnt,ch[1000010][26],son[1000010];
2 bool flag[1000010];
3 void init(){
4     memset(flag,false,sizeof(flag));
5     memset(son,0,sizeof(son));
6     memset(ch,0,sizeof(ch));
7     root=cnt=1;
8     return;
9 }

root即为根节点,cnt用于动态建树,ch[i][j]表示i节点的第j个子节点(表示字符char('a'+i))的编号,son[i]表示i节点的子节点数,flag[i]表示i节点是否为某个字符串的末尾。

插入

 1 void ins(int rt,int dep){
 2     if(dep==len){
 3         flag[rt]=true;
 4         return;
 5     }
 6     if(!ch[rt][s[dep]-'a']){
 7         ch[rt][s[dep]-'a']=++cnt;
 8         son[rt]++;
 9     }
10     ins(ch[rt][s[dep]-'a'],dep+1);
11     return;
12 }

删除

 1 bool del(int rt,int dep){
 2     if(dep==len){
 3         if(flag[rt]){
 4             flag[rt]=false;
 5             return true;
 6         }
 7         return false;
 8     }
 9     if(!ch[rt][s[dep]-'a'])
10         return false;
11     if(del(ch[rt][s[dep]-'a'],dep+1)){
12         if(!son[ch[rt][s[dep]-'a']]&&!flag[ch[rt][s[dep]-'a']]){
13             ch[rt][s[dep]-'a']=0;
14             son[rt]--;
15         }
16         return true;
17     }
18     return false;
19 }

查找

1 bool query(int rt,int dep){
2     if(dep==len)
3         return flag[rt];
4     if(!ch[rt][s[dep]-'a'])
5         return false;
6     return query(ch[rt][s[dep]-'a'],dep+1);
7 }

以上三个是Trie树的基本操作,下面来讲一下Trie树的其它运用。

拓展运用

求第k小字符串

存储以每个节点为根的子树中的末尾节点个数(size[i])即可。

 1 void kth(int rt,int dep,int k){
 2     if(k>size[rt]){
 3         puts("have no kth string");
 4         return;
 5     }
 6     for(int i=0;i<26;i++)
 7         if(k>size[ch[rt][i]])
 8             k-=size[ch[rt][i]];
 9         else if(ch[rt][i]){
10             putchar('a'+i);
11             kth(ch[rt][i],dep+1,k);
12         }
13     return;
14 }

最长公共前缀

用LCA求两个字符串对应的末尾节点的最近公共祖先即可,时间复杂度O(log2n)。

1 代码不贴了,懒~~~

最大异或值

将每个数转化为二进制,添加前缀0至相同位数,然后从最高位开始插入。查询时从最高位开始查询是否有与相应位置异或值为1的节点即可。

1 太水了,也不贴代码了~~~

可持久化Trie树

在做题过程中,我们常常会遇到求区间第k大字符串,区间与某数异或最大值之内的问题,我们便可以采用可持久化Trie树来解决这类问题。

依旧以abc,abd,abcd,bcd这四个字符串为例建可持久化Trie,如下图:

红色节点意义同上。

基本操作

相关变量

 1 int cnt=0,root[1000010],size[1000010],ch[1000010][26];
 2 bool flag[1000010];
 3 void init(){
 4     memset(flag,false,sizeof(flag));
 5     memset(root,0,sizeof(root));
 6     memset(size,0,sizeof(size));
 7     memset(ch,0,sizeof(ch));
 8     cnt=0;
 9     return;
10 }

意义同上。

插入

 1 void ins(int &now,int last,int dep){
 2     if(!now)
 3         now=++cnt;
 4     if(dep==len){
 5         flag[now]=true;
 6         size[now]=size[last]+1;
 7         return;
 8     }
 9     int sign=s[dep]-'a';
10     for(int i=0;i<26;i++)
11         if(i!=sign){
12             ch[now][i]=ch[last][i];
13             size[now]+=size[ch[last][i]];
14         }
15     ins(ch[now][sign],ch[last][sign],dep+1);
16     size[now]+=size[ch[now][sign]];
17     return;
18 }

区间第k小查询

 1 void kth(int rl,int rr,int dep,int k){
 2     if(k>size[rr]-size[rl]){
 3         puts("have no kth string");
 4         return;
 5     }
 6     for(int i=0;i<26;i++)
 7         if(k>size[ch[rr][i]]-size[ch[rl][i]])
 8             k-=size[ch[rr][i]]-size[ch[rl][i]];
 9         else if(size[ch[rr][i]]-size[ch[rl][i]]>0){
10             putchar('a'+i);
11             kth(ch[rl][i],ch[rr][i],dep+1,k);
12             return;
13         }
14     return;
15 }

区间最大异或值

1 好吧,还是懒得打~~~

转载于:https://www.cnblogs.com/gzez181027/p/Trie.html

Trie可持久化Trie相关推荐

  1. BZOJ3166 [Heoi2013]Alo 【可持久化trie树 + 二分 + ST表】

    题目 Welcome to ALO ( Arithmetic and Logistic Online).这是一个VR MMORPG , 如名字所见,到处充满了数学的谜题. 现在你拥有n颗宝石,每颗宝石 ...

  2. [您有新的未分配科技点]可,可,可持久化!?------0-1Trie和可持久化Trie普及版讲解...

    这一次,我们来了解普通Trie树的变种:0-1Trie以及在其基础上产生的可持久化Trie(其实,普通的Trie也可以可持久化,只是不太常见) 先简单介绍一下0-1Trie:一个0-1Trie节点只有 ...

  3. 【bzoj3261】最大异或和 可持久化Trie树

    题目描述 给定一个非负整数序列 {a},初始长度为 N.        有M个操作,有以下两种操作类型: 1.A x:添加操作,表示在序列末尾添加一个数 x,序列的长度 N+1. 2.Q l r x: ...

  4. 可持久化Trie+堆优化 OR Trie树上求XOR第K大 ---- P5283 [十二省联考2019]异或粽子

    题目大意 题目大意: 考虑先做个 prefix xor 前缀异或bi=⨁j=1iaj(1≤i≤n)b_i=\bigoplus_{j=1}^{i}a_j(1\leq i \leq n)bi​=j=1⨁i ...

  5. P4735 最大异或和(可持久化trie树、求最大区间异或和)

    P4735 最大异或和 我们维护一个前缀异或和:s[i]=a[1]xora[2]xor-a[i−1]xora[i]s[i] = a[1] \ xor\ a[2]\ xor\ - a[i-1] \ xo ...

  6. BZOJ 3261 最大异或和 可持久化Trie树

    题目大意:给定一个序列,提供下列操作: 1.在数组结尾插入一个数 2.给定l,r,x,求一个l<=p<=r,使x^a[p]^a[p+1]^...^a[n]最大 首先我们能够维护前缀和 然后 ...

  7. 省选专练(学习)可持久化Trie树(BZOJ3261)

    这个似乎也不是好难啊 但是可持久化Trie还是可以干许多线性基不能干的事. 什么是可持久化Trie? 顾名思义:是一种可以持久化的Trie树 他的建树方式和键值式线段树方式类似 也支持版本的减法 查询 ...

  8. BZOJ3261 最大异或和 解题报告(可持久化Trie树)

    本题链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3261 题目描述 给定一个非负整数序列{a},初始长度为N. 有M个操作,有以下两种操作类 ...

  9. [BZOJ3261] 最大异或和 (异或前缀和,可持久化Trie)

    Description 给定一个非负整数序列{a},初始长度为N. 有M个操作,有以下两种操作类型: 1.Ax:添加操作,表示在序列末尾添加一个数x,序列的长度N+1. 2.Q l r x:询问操作, ...

最新文章

  1. 如何完全卸载VS2010
  2. 装饰器,生成器,迭代器
  3. python opencv cv.applyColorMap()函数(颜色映射)ColormapTypes【将Intel Realsense D435深度图的黑白图映射为彩色图】
  4. windows git 更改为unix模式换行符决解方法
  5. ddr3服务器内存条维修,详解服务器中内存故障的优质解决方案
  6. Scrapy 爬虫框架四 —— 动态网页及其 Splash 渲染
  7. Linux RAID磁盘阵列
  8. js已知文件路径得到file对象_Node之文件流与文件路径操作
  9. 20170917软件工程师在线笔试之员工点外卖问题
  10. 编译OpenJDK12:globalDefinitions_visCPP.hpp(46): fatal error C1083:inttypes.h No such file or directory
  11. Jeecg-Boot前后端分离版
  12. Power BI能否做帕累托分析
  13. 计算机科学导论填空题,计算机科学导论习题
  14. 从这三个维度说一说,如何做一名具有产品思维的UI设计师?
  15. At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger
  16. python中count方法
  17. 第八届蓝桥杯(国赛)——瓷砖样式
  18. 使用Java导出Excel表格并由浏览器直接下载——基于POI框架
  19. Kindle 通过邮箱发送电子书
  20. leetcode数据库题目1-123题(20-08-14)(1)

热门文章

  1. html兼容webki,评IE10对HTML5的完美支持
  2. java 8 兼容_甲骨文限制 Java 9 到 Java 8 的向后兼容性
  3. python 串口_如何使用Python开发串口通讯上位机(一)
  4. 电脑如何测网速_物联网卡的网速到底怎么样呢
  5. 【Pytorch神经网络理论篇】 06 神经元+神经网络模型+全连接网络模型
  6. 计算机语言恢复,win10系统找回消失不见语言栏的恢复方法
  7. 二、Web服务器——ServletHTTPRequest笔记
  8. LeetCode MySQL 1322. 广告效果
  9. 计算机应用基础一级考试题库,2018一级结构工程师《计算机应用基础》题库及答案(一)...
  10. 怎样切换git账号密码错误_git中多账号切换问题的解决方案(转)