#include<iostream>
using namespace std;
#define N 1000100/*最长字符串的长度*/
#include<cstring>
#include<cstdio>
int topt=0,n;
struct Trie{
int nxt[26],cnt,fail;
Trie()
{
memset(nxt,0,sizeof(nxt));
cnt=fail=0;/*结构体初始化*/
}
}trie[N];
int pos[201],que[N],head=-1,tail=-1;
void build_trie(int k,char*str)/*建trie书的过程*/
{
int now=0;
while(*str)
{
if(!trie[now].nxt[*str-‘a‘])
trie[now].nxt[*str-‘a‘]=++topt;
now=trie[now].nxt[*str-‘a‘];
str++;
trie[now].cnt++;/*记录该前缀出现的次数*/
}
pos[k]=now;/*记录第k个单词终点的节点编号*/
}
void input()
{
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
char s[N];
scanf("%s",s);
build_trie(i,s);
}
}
void make_fail()/*生成fail数组*/
{
int now=0;
trie[now].fail=0;
for(int i=0;i<26;++i)/*根节点及第一层点的入队处理*/
{
if(!trie[now].nxt[i]) continue;
que[++tail]=trie[now].nxt[i];
trie[trie[now].nxt[i]].fail=0;
}
int p;
while(head<tail)
{
++head;
now=que[head];
for(int i=0;i<26;++i)
{
if(!trie[now].nxt[i]) continue;
que[++tail]=trie[now].nxt[i];/*如果存在,就入队*/
p=trie[now].fail;/*p是该节点父亲的fail指针*/
while(!trie[p].nxt[i]&&p)/*回调的过程*/
p=trie[p].fail;
if(trie[p].nxt[i])
trie[trie[now].nxt[i]].fail=trie[p].nxt[i];
else trie[trie[now].nxt[i]].fail=0;
}
}
for(int i=tail;i>=0;--i)
trie[trie[que[i]].fail].cnt+=trie[que[i]].cnt/*关键:从队列的反方向,因为是广搜,所以反方向的1<--3<--5都有该单词的cnt,只有反向才能把cnt一层层传上来,因为fail不一定会指向我们想要的位置*/;
for(int i=1;i<=n;++i)
printf("%d\n",trie[pos[i]].cnt);/*这是该单词的这终结点,但是也许别的单词中也会包括该单词,因为这是广搜,所以包含该单词的单词终结位置的fail一定指向当前这个单词,上面那一步就是,把这里的单词数转移上去*/
}
int main()
{
input();
make_fail();
return 0;
}