题解:
把老师点名的串建AC自动机,每个名字在树上匹配,对于匹配的每个结点,沿fail指针对能到达的结点暴力统计答案
就是名字有点难搞。。。
用map吧。
代码:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<map>
#include<vector>
#include<queue>
using namespace std;
const int N=100005;
vector<int>a[N],tag[N],M,V;
map<int,int>sa[N];
int n,m,tot=1;
void insert(int rt)
{
int yu;scanf("%d",&yu);
int now=1;
for(int i=1;i<=yu;i++)
{
int hu;scanf("%d",&hu);
if(!sa[now][hu]) sa[now][hu]=++tot;
now=sa[now][hu];
}
tag[now].push_back(rt);
}
int q[N];
int fail[N];
void buildfail(){
int head=0,tail=1;
q[0]=1;
while(head!=tail)
{
int now=q[head];head++;
for(map<int,int>::iterator i=sa[now].begin();i!=sa[now].end();i++)
{
int t=i->first,k=fail[now];
while(!sa[k][t])k=fail[k];
fail[i->second]=sa[k][t];
q[tail++]=i->second;
}
}
}
int ans1[N],ans2[N];
bool vis[N],mark[N];
void get(int id,int x)
{
for(int i=x;i;i=fail[i])
{
if(!vis[i])
{
vis[i]=true;
V.push_back(i);
for(int j=0;j<tag[i].size();j++)
{
if(!mark[tag[i][j]])
{
mark[tag[i][j]]=true;
M.push_back(tag[i][j]);
ans1[id]++;
ans2[tag[i][j]]++;
}
}
}
else break;
}
}
void solve(int x)
{
int now=1;
for(int i=0;i<a[x].size();i++)
{
int t=a[x][i];
while(!sa[now][t]) now=fail[now];
now=sa[now][t];get(x,now);
}
for(int i=0;i<V.size();i++)vis[V[i]]=0;
for(int i=0;i<M.size();i++)mark[M[i]]=0;
V.clear();M.clear();
}
int main()
{
scanf("%d%d",&n,&m);
int x,y;
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
for(int j=1;j<=x;j++)
{
scanf("%d",&y);
a[i].push_back(y);
}
a[i].push_back(-1);
scanf("%d",&x);
for(int j=1;j<=x;j++)
{
scanf("%d",&y);
a[i].push_back(y);
}
}
for(int i=-1;i<=10000;i++)
sa[0][i]=1;
fail[1]=0;
for(int i=1;i<=m;i++)
insert(i);
buildfail();//printf("!");
memset(vis,0,sizeof(vis));
memset(mark,0,sizeof(mark));
memset(ans1,0,sizeof(ans1));
memset(ans2,0,sizeof(ans2));
for(int i=1;i<=n;i++)
solve(i);
for(int i=1;i<=m;i++)
printf("%d\n",ans2[i]);
for(int i=1;i<n;i++)
printf("%d ",ans1[i]);
printf("%d",ans1[n]);
}