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];
}
};
应用
应用于字符长度不长,但数量极多的情况。
- 字符串的前缀数量。
记录下沿途的 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;
}
};
- 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;
}

浙公网安备 33010602011771号