trie树
Posted KaaaterinaX
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了trie树相关的知识,希望对你有一定的参考价值。
这dp实在是d不动了,那我先学几个数据结构!
Trie树可以用于快速存储和查找字符串集合。
而且代码非常简短,以下是一个最基础的trie树结构。
随便揪一张图片:
基础题的代码实现:
Shortest Prefixes
const int maxn=2e4+7;
int s[maxn][26];//s[i]['a'-'a']=v,i为当前节点编号,s[i]['a']为‘a’的子节点的编号
int idx=0;
int cnt[maxn];//每个节点出现了多少次
void insert(string x)
int p=0;
for(int i=0;i<x.size();i++)
if(!s[p][x[i]-'a'])
s[p][x[i]-'a']=++idx;
p=s[p][x[i]-'a'];
cnt[p]++;
void query(string x)
int p=0;
string ans;
for(int i=0;i<x.size();i++)
ans+=x[i];
p=s[p][x[i]-'a'];
if(cnt[p]==1)
break;
cout<<x<<' '<<ans<<endl;
string x[2000];
int main()
//建立字典树
string a;
int id=0;
while(cin>>a)
insert(a);
x[++id]=a;
// if(id==12)
// break;
//
for(int i=1;i<=id;i++)
query(x[i]);
(字典树结构是真的简单易懂,但是题目可以出得很有意思)
比如说这个题:
3485. 最大异或和
(好久之前的acwing每日一题╮( ̄▽ ̄"")╭)
其实学了字典树之后这个题超级简单的!
基本思路就是求出异或前缀和,在滑动窗口内查询异或最大值即可。建树的时候加一个删除操作就行。
ac代码:
//可以删除元素的trie树
const int maxn=1e5+7;
ll a[maxn];
ll sum[maxn];//异或前缀和
int s[31*maxn][2];
int cnt[31*maxn];//数每个节点的cnt,方便删除
int idx=0;
void build(ll x)
//进行二进制拆分,构造字典树
//从高位到低位
int p=0;
for(int i=32;i>=0;i--)
int t=(x>>i)&1;
if(!s[p][t])
s[p][t]=++idx;
p=s[p][t];
cnt[p]++;
//删除操作
void elim(ll x)
int p=0;
for(int i=32;i>=0;i--)
int t=(x>>i)&1;
p=s[p][t];
cnt[p]--;
ll query(ll x)
int p=0;
int ans=0;
for(int i=32;i>=0;i--)
ll t=(x>>i)&1;
if(t==1)
//要找该位为0的
if(cnt[s[p][0]]!=0)
p=s[p][0];
ans+=1<<i;
else
p=s[p][1];
else
//要找该位为1的
if(cnt[s[p][1]]!=0)
p=s[p][1];
ans+=1<<i;
else
p=s[p][0];
return ans;
int main()
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
sum[i]=sum[i-1]^a[i];
//滑动窗口
ll res=0;
for(int i=0;i<=m;i++)
//必须要将sum[0]加入字典树
build(sum[i]);
res=max(res,query(sum[i]));
int l=0;
int r=m+1;
while(r<=n)
build(sum[r]);
if(r-l>m)
elim(sum[l]);//左边界不再符合条件,窗口向右滑动
l++;
res=max(res,query(sum[r]));
r++;
cout<<res<<endl;
以上是关于trie树的主要内容,如果未能解决你的问题,请参考以下文章
Immediate Decodability[UVA644](Trie树入门)