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;
}

  

posted @ 2019-05-04 22:55  Gloid  阅读(132)  评论(0编辑  收藏  举报