[BZOJ2434][NOI2011]阿狸的打字机

发现一种新的思路,以前从来没有见过的,即AC自动机的fail树。
这一题我们先考虑暴力,从root往Y的最后一个点走,如果走到了X的末点,ans++,如果通过fail指针走到了X的末点,ans++。
反过来考虑,从X的末点开始,如果当前点在Y串或者通过反向的Fail到了Y串,ans++。
又发把fail反向之后得到的是一棵树,那么也就是要求在X末点的子树里有多少个Y点,转化为DFS序后用树状数组维护即可。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#define X first
#define Y second
#define LL long long
#define MP make_pair
#define lowbit(x) (x&(-x))
#define DEBUG(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
const int MAXN=1e5+10;
char s[MAXN];
int n;
int first[MAXN],e=0,next[MAXN],to[MAXN],sum[MAXN*3],ans[MAXN];
void add(int a,int b)
{
    ++e;next[e]=first[a];first[a]=e;to[e]=b;
}
void _add(int x,int d)
{
    while(x<=2*MAXN)
    {
        sum[x]+=d;
        x+=lowbit(x);
    }
}
int query(int x)
{
    int res=0;
    while(x>0)
    {
        res+=sum[x];
        x-=lowbit(x);
    }
    return res;
}
struct ACM{
    int son[MAXN][27],fa[MAXN],tot,val[MAXN],f[MAXN],FA[MAXN];
    int _first[MAXN],_next[MAXN],_e,_to[MAXN],l[MAXN],r[MAXN],dfs_clock;
    ACM(){tot=0;memset(son,0,sizeof(son));memset(fa,0,sizeof(fa));memset(FA,0,sizeof(FA));memset(f,0,sizeof(f));memset(val,0,sizeof(val));dfs_clock=0;}
    int idx(char c){return c-'a';}
    void insert(char* S)
    {
        int N=strlen(S),u=0,k=0;
        for(int i=0;i<N;i++)
        {
            if(S[i]>='a'&&S[i]<='z')
            {
                int x=idx(S[i]);
                if(!son[u][x])
                {
                    son[u][x]=++tot;
                    FA[tot]=u;
                    u=tot;
                }
                else
                    u=son[u][x];
            }
            else if(S[i]=='P')
                val[++k]=u;
            else if(S[i]=='B')
                u=FA[u];
        }
    }
    void getFail()
    {
        queue<int> q;
        f[0]=0;
        for(int i=0;i<26;i++)
        {
            int u=son[0][i];
            if(u)
            {
                q.push(u);f[u]=0;
            }
        }
        while(!q.empty())
        {
            int r=q.front();q.pop();
            for(int i=0;i<26;i++)
            {
                int u=son[r][i];
                if(!u)continue;
                q.push(u);
                int j=f[r];
                while(j&&!son[j][i])j=f[j];
                f[u]=son[j][i];
            }
        }
    }
    void Add(int a,int b)
    {
        ++_e;_next[_e]=_first[a];_first[a]=_e;_to[_e]=b;fa[b]=a;
    }
    void buildTree()
    {
        _e=0;
        memset(_first,-1,sizeof(first));
        fa[0]=0;
        queue<int> q;
        for(int i=0;i<26;i++)
        {
            int u=son[0][i];
            if(u)q.push(u);
        }
        while(!q.empty())
        {
            int u=q.front();q.pop();
            Add(f[u],u);
            for(int i=0;i<26;i++)
            {
                int v=son[u][i];
                if(!v)continue;
                q.push(v);
            }
        }
        memset(l,0,sizeof(l));
        memset(r,0,sizeof(r));
    }
    void DFS(int u)
    {
        l[u]=++dfs_clock;
        for(int i=_first[u];i!=-1;i=_next[i])
        {
            int v=_to[i];
            DFS(v);
        }
        r[u]=++dfs_clock;
    }
    void solve()
    {
        int N=strlen(s),u=0,now,cnt=0;
        for(int i=0;i<N;i++)
        {
            if(s[i]>='a'&&s[i]<='z')
            {
                now=son[u][idx(s[i])];
                _add(l[now],1);
                u=now;
                //DEBUG("+%d %d\n",u,l[u]);
            }
            else if(s[i]=='P')
            {
                ++cnt;
                if(cnt==8)
                    cnt=8;
                for(int i=first[cnt];i!=-1;i=next[i])
                {
                    int v=to[i];
                    ans[i]=query(r[val[v]])-query(l[val[v]]-1);
                }
            }
            else
            {
                _add(l[u],-1);
                //DEBUG("-%d %d\n",u,l[u]);
                u=FA[u];
            }
        }
    }
}ac;
int main()
{
#ifndef ONLINE_JUDGE
    freopen("type.in","r",stdin);
    freopen("type.out","w",stdout);
#endif
    scanf("%s",s);
    memset(first,-1,sizeof(first));
    ac.insert(s);
    ac.getFail();
    ac.buildTree();
    ac.DFS(0);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int x,y;
        scanf("%d %d",&x,&y);
        add(y,x);
    }
    ac.solve();
    for(int i=1;i<=n;i++)
        printf("%d\n",ans[i]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值