• BZOJ 2434 [Noi2011]阿狸的打字机(AC自动机)


    【题目链接】 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
    ",ans[i]);
        return 0;
    }
  • 相关阅读:
    310. Minimum Height Trees -- 找出无向图中以哪些节点为根,树的深度最小
    297. Serialize and Deserialize Binary Tree *HARD*
    235.236. Lowest Common Ancestor of a Binary (Search) Tree -- 最近公共祖先
    222. Count Complete Tree Nodes -- 求完全二叉树节点个数
    208. Implement Trie (Prefix Tree) -- 键树
    excel函数累加求和与累计百分比应用
    js去除空格
    js获取标签下标
    js中对String去空格
    css的三种使用方式:行内样式,内嵌样式,外部引用样式
  • 原文地址:https://www.cnblogs.com/forever97/p/bzoj2434.html
Copyright © 2020-2023  润新知