Luogu6139 【模板】广义后缀自动机(广义 SAM)

https://www.luogu.com.cn/problem/P6139

广义后缀自动机(广义 SAM)

后缀自动机可以处理单串的问题,而多串问题则需要广义后缀自动机

广义后缀自动机可以用离线处理,也可以在线处理

离线:

将所有字符串建成一颗\(trie\)树,进行\(bfs\),依次将各节点丢进\(SAM\)中,此时的\(last\)\(trie\)树中其父节点在\(SAM\)中的位置

C++ Code:

#include<bits/stdc++.h>
#define N 1000005
#define TN 2000005
#define son s[i]-'a'
using namespace std;
int n,tot=1,trie[N][26],t[TN][26],f[N],pre[TN],cnt=1,wz[TN],len[TN];
queue<int>q;
char s[N];
namespace Trie
{
	void ins(char *s)
	{
		int n=strlen(s);
		int u=1;
		for (int i=0;i<n;i++)
		{
			if (!trie[u][son])
				trie[u][son]=++tot,f[trie[u][son]]=u;
			u=trie[u][son];
		}
	}
}
namespace GY_SAM
{
	int np,p,q,g;
	void Ins(int last,int u,int c)
	{
		np=++cnt;
		len[np]=len[last]+1;
		for (p=last;p&&!t[p][c];p=pre[p])
			t[p][c]=np;
		if (!p)
			pre[np]=1; else
			{
				q=t[p][c];
				if (len[p]+1==len[q])
					pre[np]=q; else
					{
						g=++cnt;
						len[g]=len[p]+1;
						for (int i=0;i<26;i++)
							t[g][i]=t[q][i];
						pre[g]=pre[q];
						for (;p&&t[p][c]==q;p=pre[p])
							t[p][c]=g;
						pre[np]=pre[q]=g;
					}
			}
		wz[u]=np;
	}
	void Build()
	{
		::q.push(1);
		wz[1]=1;
		while (!::q.empty())
		{
			int u=::q.front();
			::q.pop();
			for (int i=0;i<26;i++)
				if (trie[u][i])
				{
					::q.push(trie[u][i]);
					Ins(wz[u],trie[u][i],i);	
				}
		}
	}
	long long Query()
	{
		long long ans=0;
		for (int i=2;i<=cnt;i++)	
			ans+=len[i]-len[pre[i]];
		return ans;
	}
}
int main() 
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	{
		scanf("%s",s);
		Trie::ins(s);
	}
	GY_SAM::Build();
	cout << GY_SAM::Query() << endl;
	return 0;
}

在线:

将每个字符串的初始\(last\)设为\(1\),进行操作

加特判(具体见此处

C++ Code:

#include<bits/stdc++.h>
#define N 2000005
using namespace std;
int n,t[N][26],cnt=1,len[N],last=1,pre[N];
char s[N];
namespace GY_SAM
{
	int np,p,q,g;
	void ins(int c)
	{
		if (t[last][c])
		{
			p=last;
			q=t[last][c];
			if (len[p]+1==len[q])
			{
				last=q;
				return;
			} else
			{
				g=++cnt;
				len[g]=len[p]+1;
				for (int i=0;i<26;i++)
					t[g][i]=t[q][i];
				pre[g]=pre[q];
				for (;p&&t[p][c]==q;p=pre[p])
					t[p][c]=g;
				pre[q]=g;
				last=g;
				return;
			}
		}
		np=++cnt;
		len[np]=len[last]+1;
		for (p=last;p&&!t[p][c];p=pre[p])
			t[p][c]=np;
		if (!p)
			pre[np]=1; else
			{
				q=t[p][c];
				if (len[p]+1==len[q])
					pre[np]=q; else
					{
						g=++cnt;
						len[g]=len[p]+1;
						for (int i=0;i<26;i++)
							t[g][i]=t[q][i];
						pre[g]=pre[q];
						for (;p&&t[p][c]==q;p=pre[p])
							t[p][c]=g;
						pre[q]=pre[np]=g;
					}
			}
		last=np;
	}
	void ins_string(char *s)
	{
		int n=strlen(s);
		for (int i=0;i<n;i++)
			ins(s[i]-'a');
	}
	long long query()
	{
		long long ans=0;
		for (int i=2;i<=cnt;i++)
			ans+=len[i]-len[pre[i]];
		return ans; 
	}
}
int main() 
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	{
		scanf("%s",s);
		last=1;
		GY_SAM::ins_string(s);
	}
	cout << GY_SAM::query() << endl;
	return 0;
}
posted @ 2020-07-20 17:24  GK0328  阅读(118)  评论(0编辑  收藏  举报