Trie树

什么是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

posted @ 2020-08-23 20:50  千载煜  阅读(122)  评论(0编辑  收藏  举报