前缀统计~[字典树]
题意
给出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