spoj NSUBSTR

先求个SAM,然后再每个后缀的对应点上标记si[nw]=1,造好SAM之后用吧parent树建出来把si传上去,然后用si[u]更新f[max(u)],最后用j>i的[j]更新f[i]
因为每个点u对应长为min(u)~max(u)的串,我们就把它记在max(u)上,最后再统一向前更新,然后更新后的si就表示right大小,也就是这个串对应的后缀个数

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1000005;
int n,fa[N],ch[N][27],dis[N],si[N],cur=1,con=1,la,h[N],cnt,f[N];
char s[N];
struct qwe
{
	int ne,to;
}e[N<<2];
void add(int u,int v)
{
	cnt++;
	e[cnt].ne=h[u];
	e[cnt].to=v;
	h[u]=cnt;
}
void ins(int c,int id)
{
	la=cur,dis[cur=++con]=id,si[cur]=1;
	int p=la;
	for(;p&&!ch[p][c];p=fa[p])
		ch[p][c]=cur;
	if(!p)
		fa[cur]=1;
	else
	{
		int q=ch[p][c];
		if(dis[q]==dis[p]+1)
			fa[cur]=q;
		else
		{
			int nq=++con;
			dis[nq]=dis[p]+1;
			memcpy(ch[nq],ch[q],sizeof(ch[q]));
			fa[nq]=fa[q];
			fa[q]=fa[cur]=nq;
			for(;ch[p][c]==q;p=fa[p])
				ch[p][c]=nq;
		}
	}
}
void dfs(int u)
{
	for(int i=h[u];i;i=e[i].ne)
	{
		dfs(e[i].to);
		si[u]+=si[e[i].to];
	}
	f[dis[u]]=max(f[dis[u]],si[u]);
}
int main()
{
	scanf("%s",s+1);
	n=strlen(s+1);
	for(int i=1;i<=n;i++)
		ins(s[i]-'a',i);
	for(int i=2;i<=con;i++)
		add(fa[i],i);
	dfs(1);
	for(int i=n-1;i>=1;i--)
		f[i]=max(f[i],f[i+1]);
	for(int i=1;i<=n;i++)
		printf("%d
",f[i]);
	return 0;
}
原文地址:https://www.cnblogs.com/lokiii/p/10001924.html