trie树是什么?
这是一种数据结构,典型的空间换时间,用它存储字符串可以便于之后的各种操作,如图。
这就是一棵可以用于存储二进制数的trie树(相当于把二进制数当成字符存进去),我们可以发现从根节点可以引出0和1两个儿子,每个儿子又可以引出0和1两个儿子,以此类推......
如果题中给的是字符串,就相当于从根节点引出26个儿子,它们对应26个字母,再从每个儿子引出26个儿子......。
举个例子,用trie树存aid,app,map,mad这四个单词。如图所示。
那么怎么建立trie树呢?
代码如下,含解释
void add(string x)
{
int l=x.size(),p=0;//p是当前位置
for(int i=0;i<l;i++)
{
int v=x[i]-'0'+1;
if(trie[p][v]==0) trie[p][v]=++t;//不存在结点,新建节点
p=trie[p][v];//跳到下一个节点
}
}
建立之后,就可以进行各种操作了,这部分代码也类似建立,大同小异。
这里给出一道洛谷上的模板题
题面
XS中学化学竞赛组教练是一个酷爱炉石的人。
他会一边搓炉石一边点名以至于有一天他连续点到了某个同学两次,然后正好被路过的校长发现了然后就是一顿欧拉欧拉欧拉(详情请见已结束比赛 CON900)。
输入格式
第一行一个整数 nn,表示班上人数。
接下来 nn 行,每行一个字符串表示其名字(互不相同,且只含小写字母,长度不超过 5050)。
第 n+2n+2 行一个整数 mm,表示教练报的名字个数。
接下来 mm 行,每行一个字符串表示教练报的名字(只含小写字母,且长度不超过 5050)。
输出格式
对于每个教练报的名字,输出一行。
如果该名字正确且是第一次出现,输出
OK
,如果该名字错误,输出WRONG
,如果该名字正确但不是第一次出现,输出REPEAT
。
思路
显然,每个人的把名字存到trie树里,再对每一次点名搜索,判断是否重复或错误。
附AC代码
#include<bits/stdc++.h>
using namespace std;
int n,m,k[500005][28],cnt,mark[500005];
string a[100005],b[100005];
void add(string s)
{
int u=0,l=s.size();
for(int i=0;i<l;i++)
{
int x=s[i]-'a'+1;
if(k[u][x]==0) k[u][x]=++cnt;
u=k[u][x];
}
mark[u]++;
}
int inquire(string s)
{
int u=0,l=s.size();
for(int i=0;i<l;i++)
{
int x=s[i]-'a'+1;
if(k[u][x]==0) return 0;
u=k[u][x];
}
if(mark[u]==0) return 1;
mark[u]--;
return 2;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],add(a[i]);
cin>>m;
for(int j=1;j<=m;j++)
{
cin>>b[j];
switch(inquire(b[j]))
{
case 0:cout<<"WRONG"<<endl;break;
case 1:cout<<"REPEAT"<<endl;break;
case 2:cout<<"OK"<<endl;break;
}
}
return 0;
}
(有错误求大佬指出,蒟蒻感激不尽qwq)