题面
题解
明显的广义后缀自动机, 关键怎么算, 只能按字符串出遍历每个节点
再根据link去标记节点, 最后根据标记去算贡献
struct EXSAM { //trie一样的空间 N * M, 再建自动机为 N * M << 1
static const int N = 1e5 + 5, M = 26, C = 'a', NUM = 15;//N字串总长度,NUM字符串个数
struct Node { int len, fa, ne[M]; } tr[N << 1];
int tot, mxlen, tax[N << 1], rk[N << 1];
int newNode() { return memset(tr[++tot].ne, 0, sizeof tr[0].ne), tot; }
void init() {
memset(tr[0].ne, 0, sizeof tr[0].ne);
tot = mxlen = 0; tr[0].fa = -1;
}
int insertSAM(int las, int ch) {
int cur = tr[las].ne[ch], p = tr[las].fa;
tr[cur].len = tr[las].len + 1;
for (; p != -1 && !tr[p].ne[ch]; p = tr[p].fa) tr[p].ne[ch] = cur;
if (p == -1) return tr[cur].fa = 0, cur;
int q = tr[p].ne[ch];
if (tr[p].len + 1 == tr[q].len) return tr[cur].fa = q, cur;
int nq = ++tot; tr[nq].len = tr[p].len + 1; tr[nq].fa = tr[q].fa;
rep (i, 0, M - 1) tr[nq].ne[i] = tr[tr[q].ne[i]].len ? tr[q].ne[i] : 0;
for (; p != -1 && tr[p].ne[ch] == q; p = tr[p].fa) tr[p].ne[ch] = nq;
return tr[cur].fa = tr[q].fa = nq, cur;
}
int insertTrie(int cur, int ch) {
if (!tr[cur].ne[ch]) tr[cur].ne[ch] = newNode();
return tr[cur].ne[ch];
}
int insert(const char *s) {
int len = 0;
for (int& i = len, p = 0; s[i]; p = insertTrie(p, s[i++] - C));
return umax(mxlen, len), len;
}
void build() {
queue<pair<int, int>> q;
rep (i, 0, M - 1) if (tr[0].ne[i]) q.push({ i, 0 });
while (!q.empty()) {
PII it = q.front(); q.pop();
int las = insertSAM(it.se, it.fi);
rep (i, 0, M - 1) if (tr[las].ne[i]) q.push({ i, las });
}
}
int tag[N << 1], ans[N];
void dfs(int p, int id) {
for (; p != -1 && tag[p] != id && tag[p] != -1; p = tr[p].fa) tag[p] = tag[p] ? -1 : id;
}
void difsub(char *s, int* len, int n) {
rep (i, 1, n) for (int j = len[i - 1], p = tr[0].ne[s[j] - C]; j < len[i]; p = tr[p].ne[s[++j] - C]) dfs(p, i);
rep (i, 0, tot) if (tag[i] != -1) ans[tag[i]] += tr[i].len - tr[tr[i].fa].len;
rep (i, 1, n) cout << ans[i] << '
';
}
} exSam;
const int N = 1e5 + 5, inf = 0x3f3f3f3f;
int n, m, _, k;
int len[N], ans[N];
char s[N];
int main() {
exSam.init(); read(n);
rep (i, 1, n) { cin >> s + len[i - 1]; len[i] = exSam.insert(s + len[i - 1]) + len[i - 1]; }
exSam.build(); exSam.difsub(s, len, n);
return 0;
}