前缀统计~[字典树]
题意
给出N个字符串,进行M次询问,每次给出一个字符串,询问N个字符串中有多少个是它的前缀。
思路
字典树Trie入门题。
字典树最典型的应用就是用来存储字符串。
其中每个节点下有26个子节点(对应26个字母),根据新建节点的顺序使用idx为节点编号,根节点和空节点编号都为0,每个叶节点维护一个cnt,标记以这个叶节点结尾的字符串有几个。
使用这种存储方式可以很容易查找一个字符串是否存在,以及出现过几次等等。
Code:
#include <bits/stdc++.h>
using namespace std;
#define fre freopen("data.in","r",stdin);
#define ms(a) memset((a),0,sizeof(a))
#define go(i,a,b) for(register int (i)=(a);(i)<(b);++(i))
#define rep(i,a,b) for(register int (i)=(a);(i)<=(b);++(i))
#define sf(x) scanf("%d",&(x))
#define reg register
typedef long long LL;
const int inf=(0x3f3f3f3f);
const int maxn=1e6+5;
int son[maxn][30]; //维护字典树
int cnt[maxn],idx,n,m; //idx为使用到的节点编号
char str[maxn];
inline void insert(char *str){
int p=0,u;//p表示当前的根节点
for(int i=0;str[i];++i){
u=str[i]-'a';
if(!son[p][u])son[p][u]=++idx; //如果这个节点不存在,那么为这个节点编号,表示新建这个节点,节点从1开始编号
p=son[p][u]; //沿着节点一直走到叶节点
}
++cnt[p];//统计以该叶节点结尾的字符串的个数
}
inline LL query(char *str){
int p=0,u;
LL ans=0;
for(int i=0;str[i];++i){
u=str[i]-'a';
if(!son[p][u])return ans;
ans+=cnt[son[p][u]];//遍历字符串,统计前缀
p=son[p][u];
}
return ans;
}
int main(){
sf(n);sf(m);
while(n--){
scanf(" %s",str);
insert(str);
}
while(m--){
scanf(" %s",str);
printf("%lld\n",query(str));
}
return 0;
}
原文地址:https://www.cnblogs.com/sstealer/p/12233104.html
时间: 2024-10-08 18:49:59