[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]);
}
發佈了99 篇原創文章 · 獲贊 1 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章