#include #include #include #include using namespace std; const int N = 1000010; int n; int tr[N][26], idx; int f[N]; // 当前节点代表的字符串在整个trie中出现的次数,也用来记录递推结果 char s[N]; // 字符串 int id[210]; // 每个单词在trie中对应节点的编号,比如id[1]=2,表示第1个模式串,在trie树中是2号节点 void insert(char *s, int x) { int p = 0; for (int i = 0; s[i]; i++) { int t = s[i] - 'a'; if (!tr[p][t]) tr[p][t] = ++idx; p = tr[p][t]; f[p]++; //记录p节点代表的字符串在整个trie中出现的次数 } id[x] = p; //记录x号单词在trie树中的节点编号 } int q[N], ne[N]; void bfs() { int hh = 0, tt = -1; for (int i = 0; i < 26; i++) if (tr[0][i]) q[++tt] = tr[0][i]; while (hh <= tt) { int t = q[hh++]; for (int i = 0; i < 26; i++) { if (!tr[t][i]) tr[t][i] = tr[ne[t]][i]; else { ne[tr[t][i]] = tr[ne[t]][i]; q[++tt] = tr[t][i]; } } } } int main() { //加快读入 ios::sync_with_stdio(false), cin.tie(0); cin >> n; for (int i = 1; i <= n; i++) { cin >> s; insert(s, i); } // AC自动机 bfs(); //从下向上递推更新 for (int i = idx; i; i--) f[ne[q[i]]] += f[q[i]]; //输出 for (int i = 1; i <= n; i++) printf("%d\n", f[id[i]]); return 0; }