bzoj3172

3172 单词

  AC自动机模板题,因为i的fail指向j说明j的深度比i小,也就是说明j的后缀一定在i中也出现过,所以add一条j指向i的边,最后答案即为该字符串最后一个字母所在AC自动机节点的子树和。

/**************************************************************

    Problem: 3172

    User: syh0313

    Language: C++

    Result: Accepted

    Time:444 ms

    Memory:309244 kb

****************************************************************/

 

#include <iostream>

#include <cstdio>

#include <cstdlib>

#include <cstring>

#include <string>

#include <queue>

using namespace std;

const int maxn=2000010;

int n,root=1,topt,head,tail,q[maxn*20],cnt=1;

int st[maxn],nt[maxn],to[maxn],num[210];

bool f[maxn];

string s[210],ss;

struct data{int v,c[30],fa;}a[1000010];

void add(int x,int y)

{to[++topt]=y; nt[topt]=st[x]; st[x]=topt;}

void insert(int k)

{

    int len=ss.length(); int now=root;

    for (int i=0;i<len;i++)

    {

        int x=ss[i]-'a'+1;

        if (!a[now].c[x]) a[now].c[x]=++cnt;

        now=a[now].c[x];

        a[now].v++;

    }

    num[k]=now;

return;

}

void getfail()

{

    head=1; tail=1; q[1]=root;

    while (head<=tail)

    {

        int now=q[head++];

        for (int i=1;i<=26;i++)

        {

            int to=a[now].c[i];

            if (!to) continue;

            if (now==root) {a[to].fa=root; add(root,to);}

            else

            {

                int father=a[now].fa;

                while (father)

                {

                    if (a[father].c[i])

                    {a[to].fa=a[father].c[i]; add(a[to].fa,to); break;}

                    father=a[father].fa;

                }

                if (!father) {a[to].fa=root; add(root,to);}

            }

            q[++tail]=to;

        }

    }

return;

}

void dfs(int x)

{

    f[x]=1; int p=st[x];

    while (p)

    {

        if (!f[to[p]])

        {

            dfs(to[p]);

            a[x].v+=a[to[p]].v;

        }

        p=nt[p];

    }

}

int main()

{

    //freopen("1.in","r",stdin);

    //freopen("my.out","w",stdout);

    ios::sync_with_stdio(false);

    cin>>n;

    for (int i=1;i<=n;i++) {cin>>ss; insert(i); s[i]=ss;}

    getfail();

    dfs(root);

    for (int i=1;i<=n;i++) printf("%d\n",a[num[i]].v);

return 0;

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值