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