后缀自动机
插入字符更新fail树即可。
#include<cstdio>
#include<map>
#define N 100005
#define A 28
using namespace std;
namespace runzhe2000
{
typedef long long ll;
int n; ll ans;
struct SAM
{
map<int,SAM*> next;
SAM *fail;
int len;
} mem[N*2], *tot, *null, *last, *root;
SAM* newnode(int len)
{
SAM *p = ++tot;
*p = *null; p->len = len;
return p;
}
void init()
{
null = tot = mem;
null->fail = null; null->len = 0;
last = root = newnode(0);
}
void ins(int v)
{
SAM *np = newnode(last->len + 1), *p = last; last = np;
for(; p != null && !p->next[v]; p = p->fail) p->next[v] = np;
if(p == null) np->fail = root, ans += np->len;
else
{
SAM *q = p->next[v];
if(q->len == p->len + 1) np->fail = q, ans += np->len - q->len;
else
{
SAM *nq = newnode(0); *nq = *q; nq->len = p->len + 1;
np->fail = q->fail = nq; ans += np->len - nq->len;
for(; p!=null && p->next[v] == q; p = p -> fail) p->next[v] = nq;
}
}
}
void main()
{
scanf("%d",&n);
init();
for(int i = 1, v; i <= n; i++)
{
scanf("%d",&v);
ins(v); printf("%lld\n",ans);
}
}
}
int main()
{
runzhe2000::main();
}