字典树是一种比较容易的数据结构,个人觉得理解起来比较简单,只要掌握几个基本要点就可以了
1.字典树有一个超级原点是0点
2.因为超级原点的存在,所以在查询的时候(比如说查前缀的数量),要加的不是当前节点的cnt[now],而是son[now][u]的cnt,这样就可以避免自己忘了在最后加上cnt[now]
3.插入的操作也是比较简单,注意的是把now循环到最后一点的时候再加cnt,也就是在for循环外侧进行懒惰标记,方便以后查找
4.字典树里的懒惰标记就是以当前节点为结尾的字符串有多少个
5.怎么开数组的大小呢,这是一个匪夷所思的问题,一般的话题目上会给出一个数据范围说是整体的字符串长度不超过N
6.查询的时候一层一层向下跳就行,就和lca暴力的思想是一样的,
7.字典树的复杂度还是很好的,一般是O(logn*m),其实是比map更加优化的数据结构,考到字符串的时候,可以用一下
8.字典树的转换思想,可以把一个数的每一位二进制,左补全0,对齐之后,从根节点开始建树
9.尤其注意的是,建立一个新节点的时候,如果idx是0开始的话,要++idx,不能把0号点覆盖掉
10.字典树和kmp是字符串的唯二算法,要考的话,必须要会哦~!!
下面给出模板代码
const int Maxn=2e6+5;
int n,m,idx;
int son[Maxn][28],cnt[Maxn];
char a[Maxn];
inline void insert_tree(char t[])
{
int len=strlen(t),now=0;
for(int i=0;i<len;i++)
{
int u=t[i]-'a';
if(son[now][u]==0) son[now][u]=++idx;
now=son[now][u];
}
cnt[now]++;
}
inline int query(char t[])
{
int len=strlen(t),now=0,tmp=0;
for(int i=0;i<len;i++)
{
int u=t[i]-'a';
if(son[now][u]==0) break;
tmp+=cnt[son[now][u]];
now=son[now][u];
}
return tmp;
}
int main()
{
n=read();m=read();
for(int i=1;i<=n;i++)
{
scanf("%s",a);
insert_tree(a);
}
while(m--)
{
scanf("%s",a);
printf("%d\n",query(a));
}
return 0;
}
应该好理解着