# 51Nod 算法马拉松17 Simple KMP 链剖维护SAM的fail树

542人阅读 评论(0)

### 题目大意

N100000$N \leq 100000$

### 程序

//YxuanwKeith
#include <cstring>
#include <cstdio>
#include <algorithm>

using namespace std;

const int MAXN = 2e5 + 5;
const int Mo = 1e9 + 7;

struct SAM {
int fail, Len, Go[26];
} A[MAXN];

struct Tree {
int tag, Sum, Num;
} Tr[MAXN * 4];

char S[MAXN];
int N, Root, tot, Lst, time;
int Cnt, Last[MAXN], Go[MAXN * 2], Next[MAXN * 2];
int Size[MAXN], MSon[MAXN], Top[MAXN], Ord[MAXN], Bel[MAXN], Pre[MAXN];

void Link(int u, int v) {
Next[++ Cnt] = Last[u], Last[u] = Cnt, Go[Cnt] = v;
}

int np = ++ tot, p = Lst;
A[np].Len = A[p].Len + 1;
for (; p && !A[p].Go[ch]; p = A[p].fail) A[p].Go[ch] = np;
if (!p) A[np].fail = Root; else {
int q = A[p].Go[ch];
if (A[q].Len == A[p].Len + 1) A[np].fail = q; else {
int nq = ++ tot;
A[nq] = A[q];
A[nq].Len = A[p].Len + 1;
A[q].fail = A[np].fail = nq;
for (; p && A[p].Go[ch] == q; p = A[p].fail) A[p].Go[ch] = nq;
}
}
Lst = np;
}

void Basis(int Now) {
Size[Now] = 1;
for (int p = Last[Now]; p; p = Next[p]) {
int v = Go[p];
Pre[v] = Now;
Basis(v);
Size[Now] += Size[v];
if (Size[v] > Size[MSon[Now]]) MSon[Now] = v;
}
}

void Promote(int Now, int top) {
if (!Now) return;
Ord[Now] = ++ time;
Bel[time] = Now;
Top[Now] = top;
Promote(MSon[Now], top);
for (int p = Last[Now]; p; p = Next[p]) {
int v = Go[p];
if (v == MSon[Now]) continue;
Promote(v, v);
}
}

void Build(int Now, int l, int r) {
if (l == r) {
int p = Bel[l];
Tr[Now].Num = A[p].Len - A[A[p].fail].Len;
return;
}
int Mid = (l + r) >> 1;
Build(Now * 2, l, Mid), Build(Now * 2 + 1, Mid + 1, r);
Tr[Now].Num = (Tr[Now * 2].Num + Tr[Now * 2 + 1].Num) % Mo;
}

void Prepare() {
Lst = tot = Root = 1;
for (int i = 1; i <= N; i ++) Add(S[i] - 'a');
for (int i = 1; i <= tot; i ++)
Basis(1);
Promote(1, 1);
Build(1, 1, tot);
}

void MakeTag(int Now, int tag) {
Tr[Now].tag = (Tr[Now].tag + tag) % Mo;
Tr[Now].Sum = (Tr[Now].Sum + tag * 1ll * Tr[Now].Num % Mo) % Mo;
}

void Push(int Now, int l, int r) {
if (l != r && Tr[Now].tag) {
MakeTag(Now * 2, Tr[Now].tag);
MakeTag(Now * 2 + 1, Tr[Now].tag);
}
Tr[Now].tag = 0;
}

int Query(int Now, int l, int r, int lx, int rx) {
if (rx < l || lx > r) return 0;
Push(Now, l, r);
if (l >= lx && r <= rx) return Tr[Now].Sum;
int Mid = (l + r) >> 1;
return (Query(Now * 2, l, Mid, lx, rx) + Query(Now * 2 + 1, Mid + 1, r, lx, rx)) % Mo;
}

void Modify(int Now, int l, int r, int lx, int rx) {
if (rx < l || lx > r) return;
if (l >= lx && r <= rx) {
MakeTag(Now, 1);
return;
}
int Mid = (l + r) >> 1;
Modify(Now * 2, l, Mid, lx, rx), Modify(Now * 2 + 1, Mid + 1, r, lx, rx);
Tr[Now].Sum = (Tr[Now * 2].Sum + Tr[Now * 2 + 1].Sum) % Mo;
}

void Solve() {
int Ans = 0, Now = 0, p = Root;
for (int i = 1; i <= N; i ++) {
p = A[p].Go[S[i] - 'a'];
for (int P = p; P; P = Pre[Top[P]])
Now = (Now + Query(1, 1, tot, Ord[Top[P]], Ord[P])) % Mo;
Ans = (Ans + Now) % Mo;
printf("%d\n", Ans);
for (int P = p; P; P = Pre[Top[P]])
Modify(1, 1, tot, Ord[Top[P]], Ord[P]);
}
}

int main() {
scanf("%d", &N);
scanf("%s", S + 1);

Prepare();
Solve();
}
1
0

* 以上用户言论只代表其个人观点，不代表CSDN网站的观点或立场
个人资料
• 访问：114474次
• 积分：2818
• 等级：
• 排名：第14261名
• 原创：143篇
• 转载：4篇
• 译文：0篇
• 评论：140条
评论排行
最新评论