Luogu P4070 [SDOI2016]生成魔咒

题目描述

https://www.luogu.com.cn/problem/P4070

简要题意:每次添加一个字符,求添加一个字符后有多少新增加的本质不同的子串

$n\le 10^5$

Solution

每次新增的本质不同的子串的个数为 $T[np].L - T[np].l+1$

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
#include <iostream>
#include <map>
#define maxn 100010
#define Maxn 200010
#define ll long long
using namespace std;

int n;

struct SAM {
int L; map<int, int> nxt;
} T[Maxn]; int f[Maxn], last, top, rt;
void init_SAM() {
rt = last = top = 1;
f[rt] = T[rt].L = 0;
}

ll ans;
void extend(int ch) {
int np = ++top, p = last; last = np;
T[np].L = T[p].L + 1;
while (p && T[p].nxt.find(ch) == T[p].nxt.end()) T[p].nxt[ch] = np, p = f[p];
if (!p) return f[np] = rt, ans += T[np].L, void();
int q = T[p].nxt[ch];
if (T[q].L - 1 == T[p].L) f[np] = q;
else {
int nq = ++top; T[nq].L = T[p].L + 1; f[nq] = f[q];
T[nq].nxt = T[q].nxt;
while (p && T[p].nxt[ch] == q) T[p].nxt[ch] = nq, p = f[p];
f[np] = f[q] = nq;
}
ans += T[np].L - T[f[np]].L;
}

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);

cin >> n; init_SAM();
for (int i = 1; i <= n; ++i) {
int x; cin >> x;
extend(x); cout << ans << "\n";
}
return 0;
}