传送门biu~
把AC自动机中的Fail指针反向,可以形成一棵Fail树,树上任意一个点是它所有子节点的后缀。那么可以统计以某个点为根的子树的大小,就表示这个字符串在所有字符串的前缀中作为后缀出现的次数,即出现次数。
#include<bits/stdc++.h>
using namespace std;
char c[1000005];
struct Node{
Node *ch[26],*nex;
int cnt;
Node(){
nex=NULL; cnt=0;
for(int i=0;i<26;++i) ch[i]=NULL;
}
}*root=new Node,*tail[205];
inline void Insert(char *s,int id){
Node *o=root;
for(int i=1;s[i];++i){
int to=s[i]-'a';
if(!o->ch[to]) o->ch[to]=new Node;
o=o->ch[to];
++o->cnt;
}
tail[id]=o;
}
queue<Node*>q;stack<Node*>s;
inline void GetFail(){
root->nex=root;
for(int i=0;i<26;++i){
if(root->ch[i]) q.push(root->ch[i]),root->ch[i]->nex=root;
else root->ch[i]=root;
}
while(!q.empty()){
Node *x=q.front();q.pop();
s.push(x);
for(int i=0;i<26;++i){
if(x->ch[i]) q.push(x->ch[i]),x->ch[i]->nex=x->nex->ch[i];
else x->ch[i]=x->nex->ch[i];
}
}
while(!s.empty()){
Node *x=s.top();s.pop();
x->nex->cnt+=x->cnt;
}
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%s",c+1),Insert(c,i);
GetFail();
for(int i=1;i<=n;++i) printf("%d\n",tail[i]->cnt);
return 0;
}