BZOJ4516 SDOI2016生成魔咒(后缀自动机)

时间:2023-03-09 16:43:51
BZOJ4516 SDOI2016生成魔咒(后缀自动机)

  本质不同子串数量等于所有点的len-parent树上父亲的len的和。可以直接维护。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
#define ll long long
#define N 200010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
int n,fail[N],len[N],cnt=1,last=1;
ll ans;
map<int,int> son[N];
void relink(int x,int y)
{
ans+=len[fail[x]];
fail[x]=y;
ans-=len[fail[x]];
}
void ins(int c)
{
int x=++cnt,p=last;last=x;ans+=len[x]=len[p]+1;
while (son[p].find(c)==son[p].end()) son[p][c]=x,p=fail[p];
if (!p) relink(x,1);
else
{
int q=son[p][c];
if (len[p]+1==len[q]) relink(x,q);
else
{
int y=++cnt;
ans+=len[y]=len[p]+1;
son[y]=son[q];
relink(y,fail[q]);
relink(q,y);
relink(x,y);
while (son[p][c]==q) son[p][c]=y,p=fail[p];
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("qwq.in","r",stdin);
freopen("qwq.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
n=read();
for (int i=1;i<=n;i++)
{
ins(read());
printf(LL,ans);
}
return 0;
}