zoukankan      html  css  js  c++  java
  • BZOJ 2434 阿狸的打字机

    http://www.lydsy.com/JudgeOnline/problem.php?id=2434

    思路:建立fail树,并找出dfs序,那剩下要做的就是每次找到一个串的位置,然后询问它的区间里面有多少我当前串的节点,具体做法见代码。

    #include<cstdio>
    #include<cmath>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    struct edge{
        int to,next,id;
    }que[500005];
    int fail[500005],sz,ch[500005][26],root,num,hw,low[500005],dfn[500005];
    char s[500005];
    int pos[500005],id,fi[500005],first[500005],next[500005],tot,go[500005];
    int fa[500005],ans[500005],V[1000005],n,m;
    void insert(int x,int y){
        tot++;
        go[tot]=y;
        next[tot]=first[x];
        first[x]=tot;
    }
    void add(int x,int v){
        for (int i=x;i<=hw;i+=(i)&(-i)){
            V[i]+=v;
        }
    }
    int query(int x){
        int res=0;
        for (int i=x;i;i-=(i)&(-i)){
            res+=V[i];
        }
        return res;
    }
    void build(){
        int now=1;sz=1;
        for (int i=0;i<n;i++){
            if (s[i]=='P') pos[++id]=now;
            else
            if (s[i]=='B') now=fa[now];
            else{
                int k=s[i]-'a';
                if (ch[now][k]==0) ch[now][k]=++sz,fa[sz]=now;
                now=ch[now][k];
            }
        }
    }
    void bfs(){
        std::queue<int>Q;
        for (int i=0;i<26;i++)
         if (!ch[root][i]) ch[root][i]=root;
         else if (ch[root][i]){
                fail[ch[root][i]]=root;
                Q.push(ch[root][i]);
         }
        while (!Q.empty()){
            int now=Q.front();Q.pop();
            for (int i=0;i<26;i++)
             if (!ch[now][i]){
                ch[now][i]=ch[fail[now]][i];
             }else{
                fail[ch[now][i]]=ch[fail[now]][i];
                Q.push(ch[now][i]);
             }
        } 
    }
    void dfs(int x){
        dfn[x]=++hw;
        for (int i=first[x];i;i=next[i]){
            int pur=go[i];
            dfs(pur);
        }
        low[x]=++hw;
    }
    void solve(){
        add(dfn[1],1);//root节点也算上 
        int sx=0,now=1;
        for (int i=0;i<n;i++){
            if (s[i]=='P'){
                sx++;
                for (int j=fi[sx];j;j=que[j].next){
                    int pur=pos[que[j].to];
                    ans[que[j].id]+=query(low[pur])-query(dfn[pur]-1);
                }//询问dfs序区间里面有多少标记过的节点,有多少就代表y到root路径上的节点有多少能走到x的尾节点 
            }else
            if (s[i]=='B') add(dfn[now],-1),now=fa[now];//删除的时候去掉 
            else{
                now=ch[now][s[i]-'a'];
                add(dfn[now],1);//走一步加一步 
            }
        }
    }
    int main(){
        scanf("%s",s);root=1;
        n=strlen(s);
        build();
        bfs();//建AC自动机 
        for (int i=1;i<=sz;i++)
          insert(fail[i],i);//建fail树 
        dfs(0);//找dfs序 
        scanf("%d",&m);
        for (int i=1;i<=m;i++){//把y相同的询问弄到一起 
            int x,y;
            scanf("%d%d",&x,&y);
            num++;
            que[num].to=x;
            que[num].next=fi[y];
            que[num].id=i;
            fi[y]=num;
        }
        solve();//统计答案 
        for (int i=1;i<=m;i++)
         printf("%d
    ",ans[i]);
    }
  • 相关阅读:
    linux
    day01-02
    测试基础
    cookie session
    多表表与表关系 增删改查 admin
    连接数据库 创建表 字段和参数 增删改查
    LeetCode OJ:Triangle(三角形)
    LeetCode OJ:Unique Paths II(唯一路径II)
    LeetCode OJ:Unique Paths(唯一路径)
    使用双栈实现一个队列
  • 原文地址:https://www.cnblogs.com/qzqzgfy/p/5689086.html
Copyright © 2011-2022 走看看