什么是Trie
我们现在有很多很多的单词,想要记录下来并对它们进行各种神奇的操作(比如求最长前缀以及字符串匹配什么的),这时候我们就要用(trie)来记录。
煮个栗子:
我们现在要记录下(qwqwqwq) ,(qwqwqaq) ,(qqqqq)这三个单词,建出来的(trie)就长这样
显然这棵(trie)要支持插入,那么怎么插入呢?
插入操作
在上面的(qwqwqwq)和(qwqwqaq)中可以看出来它们共用了(qwqwq)这个部分。新插入字符串也是如此。从根开始遍历,不断寻找当前点中和下一个要插入的字符相同的儿子,如果没有就新建。然后跳到这个儿子上,重复此过程。插入完所有字符后,在当前所在的点打上结尾标记(就像上图中蓝色的那样)
在写代码的时候,用(ch[i][j])表示节点编号为(i),表示的字符为(j)的子节点的编号
代码:
void add()//这里已经在主函数里输入当前要插入的字符串ms
{
int len=strlen(ms);
int now=1;
for(int i=0;i<len;i++)//挨个字符插入
{
int ch=ms[i]-'a';
if(!trie[now][ch])
trie[now][ch]=++cnt;//找不到就新建
now=trie[now][ch];//寻找表示字符相同的子节点
}
en[now]++;//en[i]记录以i节点为结尾的字符串的个数
}
关于查询因题而异
板子题
Trie的一些应用
1.字符串排序
直接从左到右遍历就好了
2.词频统计
找一下最大的(en[i])
3.(AC)自动机((NOIP)不考)
(trie)上(kmp)
4.求给出的所有串中某个前缀的出现次数
01 Trie
顾名思义,01 (trie)上的点代表的字符只有0和1,插入的方式和上面的是一样的。
这个东西在处理异或问题时十分管用。
煮个栗子
假设现在给你(n)个数,这(n)个数两两异或,求最大的异或值。
暴力(O(n^2))。
考虑一个数与其他数的最大异或值,可以采用贪心的思想每次都走与这个数当前位相反的(如果没有就只能走相同的了)。
不过这玩意大概是省选才会考的
今年(Day 2 T2)就是对树进行操作再加(01 trie)
插入:
insert(int x){
int now=0;
for(int i=31;i>=0;i--)
{
int v=(x&(1<<i))>>i;
if(!ch[now][v]){
ch[now][v]=++cnt;
}
now=ch[now][v];
}
en[now]++;
}
板子题:最大异或路径
某鸽子咕咕咕了好久.jpg