给你两个字符串的集合A,B,询问B中每个串在A中的前缀匹配数,这里的匹配指的是该串和匹配串至少一个是被匹配没了,中途匹配失败不计入答案
字符的总个数不超过5∗105
一看就是字典树的裸题,他要求完全匹配,那就在每个节点记录一个路过值和终止值,答案就是在字典树上的终止值得和+匹配成功的终点的路过值,然后随便写写就行了
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#define M 500000+5
using namespace std;
struct Trie
{
Trie *son[2];
int end; //截至
int flag;//路过
Trie () {son[0]=son[1]=NULL;end=flag=0;}
}tr[M],*p,*rt=tr,*C=tr;
inline int read()
{
int x=0,f=1;char ch = getchar();
while(ch <'0'||ch >'9'){if(ch=='-')f=-1;ch = getchar();}
while(ch >='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch = getchar();}
return x*f;
}
int T[500000+45];
void insert()
{
p = rt;
for(int i=1;i<=T[0];++i)
{
p->flag++;
if(!p->son[T[i]])
p->son[T[i]] = ++C;
p = p-> son[T[i]];
}
p->flag++;
p->end++;
}
int find()
{
p = rt;
int ans = 0;
for(int i=1;i<=T[0];++i)
{
ans += p->end;
if(i==T[0]&&p->son[T[i]])ans += p->son[T[i]]->flag;
if(!p->son[T[i]])break;
p = p->son[T[i]];
}
return ans;
}
int main()
{
//freopen("06.in","r",stdin);
rt = ++C;
int m=read(),n=read();
for(int i=1;i<=m;++i)
{
int k=read();
T[0]=k;
for(int i=1;i<=k;++i)
T[i]=read();
insert();
}
for(int i=1;i<=n;++i)
{
int k=read();
T[0]=k;
for(int i=1;i<=k;++i)
T[i]=read();
printf("%d\n",find());
}
}