P4081 [USACO17DEC]Standing Out from the Herd P 广义SAM

题意:

戳这里

分析:

一看见本质不同的字符串 \(\to\) \(SAM\)

再一看,字符串集合 \(\to\) 广义 \(SAM\)

所以这个题的做法就是,建一颗广义 \(SAM\) , \(dfs\) 这个 \(SAM\) ,把只出现了一次的点标起来,它的贡献就是 \(len[x]-len[link[x]]\) ,注意没有被标过的点,他属于它的儿子所在的集合

tip:

广义SAM好像不能像普通的SAM一样,通过基数排序得到它的拓扑序

代码:

#include<bits/stdc++.h>
#define pii pair<int,int>
#define mk(x,y) make_pair(x,y)
#define lc rt<<1
#define rc rt<<1|1
#define pb push_back
#define fir first
#define sec second

using namespace std;

namespace zzc
{
	inline int read()
	{
		int x=0,f=1;char ch=getchar();
		while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
		while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
		return x*f;
	}
	
	const int maxn = 2e5+5;
	int n;
	long long ans[maxn];
	char ch[maxn];
	vector<int> tmp[maxn];
	
	namespace suffix_automaton//¹ãÒåSAMÔÚÏß¹¹Ôì°æ 
	{
		int cnt,lst;
		int link[maxn],len[maxn],trans[maxn][26],flag[maxn];
		
		void insert(int x,int p)
		{
			if(trans[lst][x])
			{
				int tmp=lst,q=trans[tmp][x];
				if(len[tmp]+1==len[q])
				{
					flag[q]=-1;
					lst=q;
				}
				else
				{
					int clone=++cnt;
					len[clone]=len[tmp]+1;
					link[clone]=link[q];
					link[q]=clone;
					for(int i=0;i<26;i++) trans[clone][i]=trans[q][i];
					for(;tmp&&trans[tmp][x]==q;tmp=link[tmp]) trans[tmp][x]=clone; 
					lst=clone;flag[clone]=p;
				}
				return ;
			}
			int cur=++cnt,tmp=lst;lst=cnt;
			len[cur]=len[tmp]+1;
			if(!flag[cur]) flag[cur]=p;
			else flag[cur]=-1;
			for(;tmp&&!trans[tmp][x];tmp=link[tmp]) trans[tmp][x]=cur;
			if(!tmp)
			{
				link[cur]=1;
			}
			else
			{
				int q=trans[tmp][x];
				if(len[tmp]+1==len[q])
				{
					link[cur]=q;
				}
				else
				{
					int clone=++cnt;
					len[clone]=len[tmp]+1;
					link[clone]=link[q];
					link[cur]=link[q]=clone;
					for(int i=0;i<26;i++) trans[clone][i]=trans[q][i];
					for(;tmp&&trans[tmp][x]==q;tmp=link[tmp]) trans[tmp][x]=clone; 
				}
			}
		}
	}
	using namespace suffix_automaton;
	
	void dfs(int u)
	{
		for(auto v:tmp[u])
		{
			dfs(v);
			if(!flag[u]) flag[u]=flag[v];
			else if(flag[u]!=flag[v]) flag[u]=-1;
		}
		if(flag[u]!=-1) ans[flag[u]]+=len[u]-len[link[u]];
	}
	
	void work()
	{
		n=read();cnt=1;
		for(int i=1;i<=n;i++)
		{
			scanf("%s",ch+1);
			int len=strlen(ch+1);
			lst=1;
			for(int j=1;j<=len;j++) insert(ch[j]-'a',i);
		}
		for(int i=1;i<=cnt;i++) tmp[link[i]].push_back(i);
		dfs(1);
		for(int i=1;i<=n;i++) printf("%lld\n",ans[i]);
	}

}

int main()
{
	zzc::work();
	return 0;
}

posted @ 2020-12-27 20:13  youth518  阅读(76)  评论(0编辑  收藏  举报