Trie树

Trie

定义

字典树,英文名 trie。顾名思义,就是一个像字典一样的树。

引入

这棵树包含了:

aa
aba
ba
caaa
cab
cba
ac

这几个单词。

如何维护

定义 son[i][j] 为在 i 号节点,往下边权为 j 的下一个节点。

struct trie {
	int son[100000][26],cnt;
	int back[100000];
	void insert(string s) {  // 插入字符串
		int p=0;
		for (int i=0;i<s.size();i++) {
			int c=s[i]-'a';
			if (!son[p][c]) son[p][c]=++cnt;
			p=son[p][c];
		}
		back[p]++;
	}
	bool find(string s) {  // 查找字符串
		int p=0;
		for (int i=0;i<s.size();i++) {
			int c=s[i]-'a';
			if (!son[p][c]) return 0;
			p=son[p][c];
		}
		return back[p];
	}
};

应用

应用于字符长度不长,但数量极多的情况。

  1. 字符串的前缀数量。

记录下沿途的 back 总和,就是答案。

struct trie {
	int son[100000][26],cnt;
	int back[100000];
	void insert(string s) {  // 插入字符串
		int p=0;
		for (int i=0;i<s.size();i++) {
			int c=s[i]-'a';
			if (!son[p][c]) son[p][c]=++cnt;  // 如果没有,就添加结点
			p=son[p][c];
		}
		back[p]++;
	}
	bool find(string s) {  // 查找字符串前缀数量
		int p=0;
		int ans=0;
		for (int i=0;i<s.size();i++) {
			int c=s[i]-'a';
			if (!son[p][c]) return ans;
			p=son[p][c];
			ans=ans+back[p];
		}
		return ans;
	}
};
  1. 01字符串

如果是关于二进制,便可以直接转换为二进制。

例题:

给定 N 个整数 \(A_1,A_2,A_3,···,A_n\) 中选出两个进行异或计算,得到的结果最大是多少?

我们可以先枚举其中一个数,从高位开始,每一次如果能异或后得到一,便优先选择,最终取 n 个方案的最大值。

CODE:

#include<bits/stdc++.h>
using namespace std;
/*!@#$%^&*!@#$%^&*~~优美的分界线~~*&^%$#@!*&^%$#@!*/
const int N=100005;
int n,A[N];
int tot,ch[N*32][2];
/*!@#$%^&*!@#$%^&*~~优美的分界线~~*&^%$#@!*&^%$#@!*/
void ins(int x) {
	int p=0;
	for(int i=30;i>=0;i--) {
		int j=(x>>i)&1;
		if(ch[p][j]==0) ch[p][j]=++tot;
		p=ch[p][j];
	}
}
int find(int x){
	int p=0,ans=0;
	for(int i=30;i>=0;i--) {
		int j=(x>>i)&1;
		int k=j?0:1;
		if(ch[p][k]==0) p=ch[p][j];
		else p=ch[p][k],ans+=(1<<i);
	}
	return ans;
}
/*!@#$%^&*!@#$%^&*~~优美的分界线~~*&^%$#@!*&^%$#@!*/
signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++) {
		cin>>A[i];
		ins(A[i]);
	}
	int ans=0;
	for(int i=1;i<=n;i++)
		ans=max(ans,find(A[i]));
	cout<<ans;
	return 0;
}
posted @ 2025-10-22 21:30  hjm0703  阅读(6)  评论(0)    收藏  举报