trie树
在蓝桥杯中我们需要掌握两种trie树:
字符字典树和01trie树,
其中字符字典树主要用于处理单一字符串面向多个字符串的匹配问题
而01trie树主要用于处理异或最大值的相关问题。
字符字典树
01trie树
01trie树由数组实现,其基本构成如下:
cpp
int son[32*N][32];
int idx;
//其中son用于存储每个节点的儿子节点的编号,
//idx用于动态创立儿子节点son的第二位坐标为0表示为左儿子,
//第二位坐标为1表示为右儿子。
void insert(long long x){
int now=0;
for (int i=31;i>=0;i--){
int k=(x>>i)&1;
if (!son[now][k])
son[now][k]=++idx;
now=son[now][k];
}
}
long long query(long long x){
int now=0;
long long res=0;
for (int i=31;i>=0;i--){
int k=(x>>i)&1;
if (son[now][!k]){
res+=(long long )(1)<<i;
now=son[now][!k];
}
else{
now=son[now][k];
}
}
return res;
}
代码模板
cpp
//不记录每个节点度数的写法
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e5+7;
long long a[N];
int son[35*N][35];
int n;
int idx;
void insert(long long x){
int now=0;
for (int i=31;i>=0;i--){
int k=(x>>i)&1;
if (!son[now][k])
son[now][k]=++idx;
now=son[now][k];
}
}
long long query(long long x){
int now=0;
long long res=0;
for (int i=31;i>=0;i--){
int k=(x>>i)&1;
if (son[now][!k]){
res+=(long long )(1)<<i;
now=son[now][!k];
}
else{
now=son[now][k];
}
}
return res;
}
long long ans=0;
int main(){
cin>>n;
for (int i=1;i<=n;i++){
scanf("%lld",&a[i]);
insert(a[i]);
}
for (int i=1;i<=n;i++){
ans=max(ans,query(a[i]));
}
cout<<ans<<endl;
return 0;
}
cpp
//记录每个节点度数的写法
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<set>
using namespace std;
int n;
const int N=1e5+7;
long long a[N];
set<int > f[N];
int idx;
int son[N*35][2];
int degree[N*35];
void build(long long x,int cnt){
int now=0;
for (int i=31;i>=0;i--){
int k=(x>>i)&1;
if (!son[now][k]){
son[now][k]=++idx;
}
now=son[now][k];
degree[now]+=cnt;
}
}
long long query(long long x){
int now=0;
long long res=0;
for (int i=31;i>=0;i--){
int k=(x>>i)&1;
if (son[now][!k]&&(degree[son[now][!k]]>0)){
now=son[now][!k];
res+=1<<i;
}
else{
now=son[now][k];
}
}
return res;
}
long long ans;
int main(){
cin>>n;
for (int i=0;i<n;i++){
scanf("%lld",&a[i]);
build(a[i],1);
}
for (int i=0;i<n;i++){
int x;
scanf("%d",&x);
if (x==-1)
continue;
f[i].insert(x);
f[x].insert(i);
}
for (int i=0;i<n;i++){
for (set<int>::iterator j=f[i].begin();j!=f[i].end();j++){
build(a[*j],-1);
}
long long k=query(a[i]);
ans=max(ans,k);
for (set<int>::iterator j=f[i].begin();j!=f[i].end();j++){
build(a[*j],1);
}
}
cout<<ans<<endl;
return 0;
}
例题
(1.lgU395507 最大异或对(01Trie))[https://www.luogu.com.cn/problem/U395507\]
该题解答即为上述模板中不记录每个节点度数的写法。
(2.P13874 [蓝桥杯 2024 省 Java/Python A] 最大异或结点)[https://www.luogu.com.cn/problem/P13874\]
该题解答即为上述模板中记录每个节点度数的写法。