非线性字符串数据结构串讲
书接去年,今天作业不想写了,滚过来写总结。顺便保留我刚略微学会的串串。
声明:作者由于水平不高,所以有些定理不能严谨证明,所以若是初学者请移步别处。
1.Trie树
定义
Trie树又叫字典树,是非常显然的一种字符串数据结构。
具体来说,我们如果手上有很多字符串,我们可以通过建一个Trie树来做一些简单的操作。
其构建过程可以看一下图,非常显然,本质就是把字符串的相同部分压缩一下。
比如我们对
aa aba ba caaa cab cba cc建一个Trie就长这样。
构建
图来自OI wiki
然后构建这块也挺简单的
代码
int len,idx,cnt[N],tr[N][70]; ll getid(char c){ if(c>='A'&&c<='Z') return c-'A'; else if(c>='a'&&c<='z') return c-'a'+26; else return c-'0'+52; } void add(string s){ len=s.size(); s=' '+s; int p=0; for(int i=1;i<=len;i++){ int id=getid(s[i]); if(!tr[p][id]) tr[p][id]=++idx; p=tr[p][id]; cnt[p]++; } } ll ask(string s){ len=s.size(); s=' '+s; int p=0; for(int i=1;i<=len;i++){ int id=getid(s[i]); if(!tr[p][id]) return 0; p=tr[p][id]; } return cnt[p]; }空间这块,最坏情况每个字符串的每个字符都要新开一个节点,所以空间开即可。
上一道例题
AT_arc219_a [ARC219A] Similarity
AT_arc219_a [ARC219A] Similarity
正难则反
这个比较困难
所以就把S串01翻转,那么就是找出一个串串使得不能与任何一个S串相同。
那你给这些反串建出Trie后,找一个还没有被经过的节点即可。
例题结束
与异或相关
其实我们的Trie树不只能在字符串上用
因为在我们眼里数是有二进制的,二进制我们就可以想到01串。
我们就可以把数字当做01串建Trie树
当我们遇到一些神秘有关异或的题目时,
我们一想Trie树,二想线性基
比如来道题,给定你一个序列和x值,让你从这个序列中选一个元素,使之其与x的异或值最大。
考虑异或的性质,二进制位上不同为一,相同为0。
所以我们对序列建Trie树,把给定的x二进制分解,从高往低位的贪心的尽可能与x当前位不同。就行了。
来一道有意思的应用
P5283 [十二省联考 2019] 异或粽子
题解
2.AC自动机
AC自动机,由两部分构成Trie树和fail树。
AC自动机的本质上就是建出Trie树后连fail边。
这里我们给出fail边的定义。
在Trie树上,每一个节点表示一个字符串。
fail边指向这个节点所代表的字符串 最长的后缀 所代表的节点。
example:
图来自OI wiki
比如这个Trie树
给他建fail边就应该是这样的
由于根节点代表的是空串,空串是任何字符串的后缀。
所以当你实在在Trie树上找不到后缀时,就直接无脑连根结点