码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ 2434 阿狸的打字机

时间:2016-07-20 17:44:51      阅读:235      评论:0      收藏:0      [点我收藏+]

标签:

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\n",ans[i]);
}

 

BZOJ 2434 阿狸的打字机

标签:

原文地址:http://www.cnblogs.com/qzqzgfy/p/5689086.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!