您的位置:首页 > 其它

bzoj 3172 [Tjoi2013]单词 后缀自动机

2016-10-25 10:27 369 查看
把所有串放在一起,两个串中间加非法字符,建一个后缀自动机。

然后按拓扑序遍历自动机,求一个点子树中的结尾数量。

然后对于每个串,在后缀自动机中跑trs指针找到对应终点。

那么这个串的答案就是终点子树中的结尾数量。

#include <bits/stdc++.h>
using namespace std;
#define N 1100000
int n,len,l[210],beg[210];
char s
;
struct SAM
{
int trs[N<<1][28],fa[N<<1],len[N<<1],num[N<<1];
int du[N<<1],cnt,last;
queue<int>q;
void init(){cnt=last=1;}
void insert(int x)
{
int p=last,np=++cnt,q,nq;
last=np;len[np]=len[p]+1;num[np]++;
for(;p&&!trs[p][x];p=fa[p])trs[p][x]=np;
if(!p)fa[np]=1;
else
{
q=trs[p][x];
if(len[q]==len[p]+1)fa[np]=q;
else
{
fa[nq=++cnt]=fa[q];
len[nq]=len[p]+1;
memcpy(trs[nq],trs[q],sizeof(trs[nq]));
fa[q]=fa[np]=nq;
for(;p&&trs[p][x]==q;p=fa[p])trs[p][x]=nq;
}
}
}
void cal()
{
for(int i=1;i<=cnt;i++)du[fa[i]]++;
for(int i=1;i<=cnt;i++)
if(!du[i])q.push(i);
while(!q.empty())
{
int t=q.front();q.pop();
if((--du[fa[t]])==0)q.push(fa[t]);
num[fa[t]]+=num[t];
}
}
}sam;
int main()
{
//freopen("tt.in","r",stdin);
sam.init();
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s",s+len+1);
beg[i]=len+1;
len+=(l[i]=strlen(s+len+1));
s[++len]='z'+1;
}
for(int i=1;i<=len;i++)
sam.insert(s[i]-'a');
sam.cal();
for(int i=1;i<=n;i++)
{
int now=1;
for(int j=beg[i];j<=beg[i]+l[i]-1;j++)
now=sam.trs[now][s[j]-'a'];
printf("%d\n",sam.num[now]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: