“当树的轮廓开始浮现,应有的字样也随之而来。”
学习笔记补完计划
Trie
中文名字典树,也称前缀树,是AC 自动机的组成部分之二。(另一个是 KMP ),用于匹配字符串前缀。大概样子如下图所示:
对于很多个模式串 $s_i$ ,如果其前缀有相同的部分,则我们就不需要重新创立一些新的节点,而是从两个不同字符串开始不同的地方延申出另一个节点即可。
实现
插入
1 | inline void insert(char *s) |
查询
该代码主要查询到是当前字符串是否在模式串中做过前缀子串。
1 | inline bool query(char *s) |
例题
弱化版
如上,多了一个 REPEAT
操作。将每一个名字的最后一个字母的位置记为 $End[u]=id$ ,然后每次到达时判断 $vis[End[u]]$ 是否到达过,而判断是 REPEAT
还是 RIGHT
。
AC Code
1 |
|
加强版
多了大写字母和数字。所以在建树时需要多建一点(小心爆栈)。当然,如果不太清楚会有多少种情况也是可以用 map
的。(这道题 map
会炸,亲测),因为多组数据,所以要预处理,这道题甚至卡了 memset
,所以就需要手动赋值。本题不卡常。
AC Code
1 |
|
CF1312G
按题意建 trie 树,并进行 dp 。
AC Code
1 |
|
01-Trie
顾名思义,每一个结点至多有 $2$ 个儿子,一个表示 $1$ ,一个表示 $0$ 。可以用来处理很多与位运算有关的题。
实际上 $\text{01-Trie}$ 能够作为一种平衡树,维护平衡树能够做的很多操作。
最长异或路径
首先应该知道一些关于位运算的公式:
1 | x^0=x,x^x=0 |
那么,异或运算满足差分性,对于 $d(l,r)$ ,我们可以化成 $d(1,l)\ xor\ d(1,r)$ 来进行预处理以达到 $\mathcal O(1)$ 的复杂度来查询。
1 | 1^1=0,1^0=1,0^1=1,0^0=0 |
根据异或的性质,我们需要在所有结果中找到位数不相同最多且尽量在高位的两个,但是逐二比较的时间复杂度过高,必须更换形式:
01-trie 树可以解决这个问题。
我们将每一个异或值变成一个仅含 $01$ 的字符串并添加到 trie 树里(从高位往低位以满足答案偏大)。对于这些答案,如果有相异的值,则统计入答案,否则继续查找,这样把每一个值都查找一遍其对应值,最后取最大即可。
时间复杂度是线性的,但带有常数,约为 $\mathcal O(30n)$ 。
AC Code
1 |
|
可持久化 Trie
其思想和主席树是有类似的,对于原有的部分直接牵引,而无需新建结点来浪费空间。
建树步骤(插入字符串 $s$ ):
- 设当前树的根节点为 $rt$ ,令 $p=rt,i=0$ ;
- 建立新的节点 $q$ ,并执行 $rt’=q$ ;
- 若 $p\ne 0$ ,则有 $Trie[q][c]=Trie[p][c]$ ;
- 建立新的节点 $q’$ ,令 $Trie[q][s_i]=q’$ 。即除了 $s_i$ 的指针不同,$p$ 和 $q$ 保持一致;
- 令 $p=Trie[p][s_i],q=Trie[q][s_i],i=i+1$ ;
- 重复步骤 $3\sim 5$ 直到字符串遍历完成。
构建可持久化 $\text{Trie}$ 树所需的空间和时间复杂度都是字符串总长度的线性函数。
可持久化字典树
数据可能有些问题,我也不太清楚自己写对没有,而且感觉好像暴力了。
$\text{RE,TLE,MLE}$ 交替表演。
所以,题面可以给出一个思考,但代码和数据的可行度,不太高。
欢迎各种方式的 $\text{Hack}$ 。
最大异或和
对于查询,很明显有 $a[p]\ xor\ a[p+1]\ xor…\ xor\ a[N]\ xor\ x=s[p-1]\ xor\ s[N]\ xor\ x$ 的性质。
然后使用类似于 $\text{01-Trie}$ 的方法将所有的 $s$ 都插入到树中,查询其最大值,但是要满足于 $l\le p\le r$ 的条件,所以考虑可持久化。
余下的我也没学懂,贺过去的,想学的自己看题解吧。qwq
AC Code
1 |
|