통계 접두사 ~ [트라이]
문제의 의미
N의 문자열을 감안할 때, M 시간이 될 때마다 주어진 문자열, N은 접두사의 수 쿼리 문자열을 요청했다.
사고
트라이 트라이 항목의 제목입니다.
트라이의 가장 일반적인 응용 프로그램은 문자열을 저장하는 데 사용됩니다.
26 리프 노드 IDX 노드 ID에 새로운 노드 및 빈 루트 노드의 시퀀스를 사용하여 (26 글자에 대응하는) 노드의 각 자식 노드는, 0 번째의되고, 각각의 리프 노드는 CNT 마커를 유지 문자열의 몇 가지 끝이있다.
이 저장소로 문자열이있는 경우 쉽게 찾을 수 등 몇 번이 있었다.
암호:
#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;
}