#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 20;
ll n,tr[maxn][30],last[300],fail[maxn],id[300],tot=0;
ll res[300];
string ss[300];
void insert(string s,int idx){
int p=0;
for(auto c:s){
int u=c-'a';
if(!tr[p][u]) tr[p][u]=++tot;
p=tr[p][u];
}
last[idx]=p;//存这个单词在tr的哪
}
void build(){//建立失配数组
queue<int>q;
for(int i=0;i<26;i++) if(tr[0][i]) q.push(tr[0][i]);
int temp=0;
while(!q.empty()){//因为fail必等于父亲节点fail+1 通过宽搜逐层来更新fail数组
int u=q.front();
q.pop();
id[++temp]=u;//id数组(好像)按照BFS序来排
for(int v=0;v<26;v++){
if(tr[u][v]){
q.push(tr[u][v]);
fail[tr[u][v]]=tr[fail[u]][v];//父亲结点的fail,然后根据v来找
}
else tr[u][v]=tr[fail[u]][v];//在这直接 把父节点的子节点的失配指针 指向父节点这一层
}
}
}
void get(string s){
int p=0;
for(auto c:s){
int u=c-'a';
p=tr[p][u];
res[p]++;
}
for(int i=tot;i;i--) res[fail[id[i]]]+=res[id[i]];//(每一个树上的点)前缀已经出现过 把它的后缀也加一下
//细节.应该是从tot到1 按照反bfs序来加res
}
void solve(){
cin>>n;
string t,s;
for(int i=1;i<=n;i++){
cin>>ss[i];
insert(ss[i],i);//第几个插入字典树中
}
build();
for(int i=1;i<=n;i++) get(ss[i]);
for(int i=1;i<=n;i++) cout<<res[last[i]]<<endl;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T = 1;
// cin >> T;
while (T--) solve();
return 0;
}
怎么事