1. 程式人生 > >BZOJ 2434 [Noi2011]阿貍的打字機(AC自動機)

BZOJ 2434 [Noi2011]阿貍的打字機(AC自動機)

樹狀 ont highlight true ++ 打印 const 查詢 我們

【題目鏈接】 http://www.lydsy.com/JudgeOnline/problem.php?id=2434

【題目大意】

  給出一個打印的過程,‘a‘-‘z‘表示輸入字母,P表示打印該字符串
  B表示刪去一個字符。問第x個打印的字符串在第y個打印的字符串中出現的次數

【題解】

  我們根據打印的過程建立trie樹,
  當x是y的子串當且僅當y到根的鏈上有fail指針指向x的結尾,
  而x在y中的出現次數則取決於有幾個這樣的指針,
  我們根據fail指針建立fail樹,按照fail樹的dfs序進行統計,
  在每個y處記錄其要查詢的x,在y點用樹狀數組對x點求dfs序區間和即可。

【代碼】

#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring> 
using namespace std;
const int N=100010;
int dfn,l[N],r[N],ans[N];
vector<int> v[N],Q[N],ID[N];
namespace BIT{
    int c[N<<1]; //dfs
    void Initialize(){memset(c,0,sizeof(c));}
    void add(int x,int v){while(x<=dfn)c[x]+=v,x+=x&-x;}
    int query(int x){int res=0;while(x)res+=c[x],x-=x&-x;return res;}
}
namespace AC_DFA{
    const int Csize=26; 
    int id,tot,son[N][Csize],sum[N],f[N],fail[N],q[N],pos[N],match[N];
    void Initialize(){
        memset(sum,0,sizeof(int)*(tot+1));
        memset(fail,0,sizeof(int)*(tot+1));
        for(int i=0;i<=tot;i++)for(int j=0;j<Csize;j++)son[i][j]=0;
        tot=0; id=0; fail[0]=-1;
    }
    inline int Tr(char ch){return ch-‘a‘;}
    void Build(char *s){
        int x=0;
        for(int l=strlen(s),i=0,w;i<l;i++){
            if(s[i]==‘P‘)pos[++id]=x;
            else if(s[i]==‘B‘)x=f[x];
            else{
                if(!son[x][w=Tr(s[i])]){
                    son[x][w]=++tot;
                    f[tot]=x;
                }x=son[x][w];
            } 
        }
    }
    void MakeFail(){
        int h=1,t=0,i,j,x=0;
        for(i=0;i<Csize;i++)if(son[0][i])q[++t]=son[0][i];
        while(h<=t)for(x=q[h++],i=0;i<Csize;i++)
        if(son[x][i]){
            fail[son[x][i]]=son[fail[x]][i],q[++t]=son[x][i];
        }else son[x][i]=son[fail[x]][i];
    }
    void Solve(char *s){
        using namespace BIT;
        BIT::Initialize();
        int x=0,id=0;
        add(l[0],1);
        for(int L=strlen(s),i=0;i<L;i++){
            if(s[i]==‘P‘){
                id++;
                for(int k=0;k<Q[id].size();k++){
                    int u=pos[Q[id][k]];
                    ans[ID[id][k]]=query(r[u])-query(l[u]-1);
                }
            }else if(s[i]==‘B‘)add(l[x],-1),x=f[x];
            else x=son[x][Tr(s[i])],add(l[x],1);
        }
    }
}
void Dfs(int x){
    l[x]=++dfn;
    for(int i=0;i<v[x].size();i++)Dfs(v[x][i]);
    r[x]=++dfn;
}
char s[N];
int main(){
    using namespace AC_DFA;
    Initialize();
    scanf("%s",s);
    Build(s); MakeFail();
    for(int i=1;i<=tot;i++)v[fail[i]].push_back(i);
    int m,x,y;
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        Q[y].push_back(x);
        ID[y].push_back(i);
    }Dfs(0); Solve(s);
    for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
    return 0;
}

BZOJ 2434 [Noi2011]阿貍的打字機(AC自動機)