P4070 [SDOI2016]生成魔咒
在每个字符插入后,求有多少个不同的子串。
一个字符所对应的节点 $a$ 的贡献为 tr[a].len - tr[tr[a].fa].len
。
查看代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| #include <cstdio> #include <map> using namespace std; typedef long long LL; const int N = 1e5 + 10; struct Node { int len, fa; map<int, int> nxt; } tr[N << 1]; LL ans; int n, last = 1, cnt = 1; int insert(int c) { int p = last, np = ++cnt; tr[np].len = tr[p].len + 1; for (; p && !tr[p].nxt.count(c); p = tr[p].fa) tr[p].nxt[c] = np; last = cnt; if (!p) { tr[np].fa = 1; return np; } int q = tr[p].nxt[c]; if (tr[q].len == tr[p].len + 1) { tr[np].fa = q; return np; } int nq = ++cnt; tr[nq] = tr[q], tr[nq].len = tr[p].len + 1; tr[q].fa = tr[np].fa = nq; for (; p && tr[p].nxt.count(c) && tr[p].nxt[c] == q; p = tr[p].fa) tr[p].nxt[c] = nq; return np; } int main() { scanf("%d", &n); for (int i = 1, a; i <= n; i++) { scanf("%d", &a); a = insert(a); ans += tr[a].len - tr[tr[a].fa].len; printf("%lld\n", ans); } return 0; }
|