[BZOJ3172][TJOI2013]单词

BZOJ
Luogu

sol

比较裸的(AC)自动机模板题。注意重复的单词的处理,这里使用的是并查集合并(注意也要维护大小)。较卡常。

code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1000005;
string s[205];
int n,l,tot,fa[205],sz[205],ch[26][N],fail[N],id[N],ans[205];
int q[N],hd,tl;
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void Union(int x,int y)
{
    int fx=find(x),fy=find(y);
    if (fx==fy) return;
    sz[fx]+=sz[fy];fa[fy]=fx;
}
void Insert(string c,int ID)
{
    int l=c.length(),x=0;
    for (int i=0;i<l;i++)
    {
        if (!ch[c[i]-'a'][x]) ch[c[i]-'a'][x]=++tot;
        x=ch[c[i]-'a'][x];
    }
    id[x]=ID;
}
void Get_Fail()
{
    for (int i=0;i<26;i++) if (ch[i][0]) q[++tl]=ch[i][0];
    while (hd<tl)
    {
        int u=q[++hd];
        for (int i=0;i<26;i++)
            if (ch[i][u]) fail[ch[i][u]]=ch[i][fail[u]],q[++tl]=ch[i][u];
            else ch[i][u]=ch[i][fail[u]];
    }
}
void Query(string c,int k)
{
    int l=c.length();
    for (int i=0,x=0;i<l;i++)
    {
        x=ch[c[i]-'a'][x];
        for (int t=x;t;t=fail[t])
            ans[id[t]]+=k;
    }
}
int main()
{
    cin>>n;
    for (int i=1;i<=n;i++) cin>>s[i],fa[i]=i,sz[i]=1;
    for (int i=1;i<=n;i++)
        for (int j=i+1;j<=n;j++)
            if (s[i]==s[j]) Union(i,j);
    for (int i=1;i<=n;i++)
        if (i==find(i)) Insert(s[i],i);
    Get_Fail();
    for (int i=1;i<=n;i++)
        if (i==find(i)) Query(s[i],sz[i]);
    for (int i=1;i<=n;i++) printf("%d
",ans[find(i)]);
    return 0;
}
原文地址:https://www.cnblogs.com/zhoushuyu/p/8350142.html