Trie 字典树重温

详解


引入


为了解决一类字符串前缀问题,应该用什么数据结构快速支持?

 

详解


可以把多个字符串的同一前缀利用起来。如 abc,abcd,就只利用好 abc。

但是有若干个字符串,我们不妨把每个字母拆开,就能都利用了。比如 abc,abcd,a,就利用好 a,b,c,d。

如何利用?遍历这 4 个字母就能做到遍历 3 个字符串。考虑把这个字母拆成链的形式,方便遍历,即 a->b->c,若干条链即可上树,组成一颗 26 叉树。

类比二叉树的 ch[u][0/1],我们定 tr[u][x] 表示 u 结点往下一个结点指向第 x 个儿子。其中 x 就是字符串不同字符数量。

然后不断 insert,就完成建树。查询同理。

 

insert:当前结点能往下走我就走,发现没有结点给我走,我就创建一个结点。

query: 当前结点能往下走我就走,发现没有结点给我走,我就真的走不动了。

注意,由定义可知 tr 的第一维是结点数量。也就是是字母最大长度总和,而非字母最大长度

 

板子


P8306 【模板】字典树 - 洛谷

int get(char c)
{
	if (c>='a' && c<='z') return c-'a'+1;
	if (c>='0' && c<='9') return 26+c-'0'+1;
	return 36+c-'A'+1;
}
void insert(char *s)
{
	int p=0, n=strlen(s+1);
	for (int i=1; i<=n; i++)
	{
		int x=get(s[i]);
		if (!tr[p][x]) tr[p][x]=++idx;
		p=tr[p][x], cnt[p]++;
	}
}
int query(char *s)
{
	int p=0, n=strlen(s+1);
	for (int i=1; i<=n; i++)
	{
		int x=get(s[i]);
		if (!tr[p][x]) return 0;
		p=tr[p][x];
	}
	return cnt[p];
}

 

01 Trie


Trie 是解决异或问题的有力数据结构。可以方便的维护异或对。

我们把数字拆成二进制数,就能组成 {0, 1} 字符集的 Trie 树了。

下面给出一些好题。

 

[维护异或极值] P10471


暴力:枚举每个 a[i],枚举每个 a[i]。我们考虑加速找 j 的过程,即考虑快速找到最大的 a[j],使得 a[i]^a[j] 取最大。

先考虑拆位,然后把二进制结果从高到低挂到 trie 上。(注意二进制结果位数应该一致。本题需要补成 31 位)

这里要优先考虑高位,因为由于贪心去考虑(具体在下面),高位压过低位。

然后贪心的想:a 当前位是 0,就往 Trie 的右边走(右边是 1),如果无法往右边走,就只能往左边走了;a 当前位是 1,就往 Trie 的左边走(左边是 0),如果无法往左边走,就只能往右边走了。

这样能使异或结果尽可能大。我们把路径上的 01 乘上其权重,加起来就是 a[j] 了。

记录详情 - 洛谷 | 计算机科学教育新生态

 

[维护异或极值] P4551


因为是异或,且都是边权而无点权,有 dis(u, v)=dis(u, root)^dis(v, root)

dis[u] 表示 u 到跟的距离,对于每个 dis[u] 只要找出最大的 dis[v] 即可。同上题。

记录详情 - 洛谷 | 计算机科学教育新生态

 

01Trie 本质


位运算 之 小 trick - cn是大帅哥886 - 博客园

异或 => 异或前缀和 => 5726. 连续子序列 - AcWing题库,看看这题的题解,非常之精巧的一题。

 

 

例题


[trie应用] AT_abc403_e


AT_abc403_e [ABC403E] Forbidden Prefix - 洛谷

每次加入 y,沿路 y标记 +1,顺便更新答案。没有经过 x 标记就 +1.

x 的前缀不重复加入,每次加入了 x 就现在末尾打 x标记,下次经过了就不往下走。

顺便把之前经过的所有 y 的标记减去 x所在结点的y标记值,并减去对答案的贡献。

 

(当然这题也可以维护一颗子树,更容易理解些)

1.字典树是由链组成的,所以沿路减去贡献不用记录 fa,直接再重新重头遍历一遍即可。

2.在字典树中,不想访问 x 往后的结点(也可以理解为不包含某个前缀),直接在此处打标记即可。

3.需要区分是沿路打标记,还是末尾打标记。沿路打标记:统计子树和,末尾打标记:处理一类前缀问题。

 

posted @ 2025-05-17 15:42  cn是大帅哥886  阅读(12)  评论(0)    收藏  举报