[bzoj2434]阿狸的打字机

[bzoj2434]阿狸的打字机


按要求模拟建AC自动机,我们看可以发现答案就是fail树上的子树中出现的end节点个数。离线然后在trie上dfs,遇到对应节点就更新答案

  • 代码
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+5;
const int SZ=26;
struct trie{
    int ch[SZ],fail;
    int fa;
}t[N];
int fail[N];
int root=0,cnt=0;
int pos[N],n,m;
char str[N];
inline void ins(char ch[]){
    int len=strlen(ch+1);
    int cur=root;
    for(int i=1;i<=len;++i){
        if(ch[i]=='P')pos[++n]=cur;
        else if(ch[i]=='B')cur=t[cur].fa;
        else {
            int c=ch[i]-'a';
            if(t[cur].ch[c])cur=t[cur].ch[c];
            else {
                t[++cnt].fa=cur;cur=t[cur].ch[c]=cnt;
            }
        }
    }
}
int hed[N],nxt[N],to[N];
int tot;
inline void adde(int u,int v){
    tot++;to[tot]=v,nxt[tot]=hed[u];hed[u]=tot;
}
queue<int>q;
inline void build(){
    for(int i=0;i<SZ;i++)if(t[0].ch[i]){
        fail[t[0].ch[i]]=0;
        q.push(t[0].ch[i]);
        adde(0,t[0].ch[i]);
    }
    while(!q.empty()){
        int u=q.front();q.pop();
        for(int c=0;c<SZ;c++)if(t[u].ch[c]){
            int x=fail[u];
            while(x&&!t[x].ch[c])x=fail[x];
            if(t[x].ch[c])x=t[x].ch[c];
            fail[t[u].ch[c]]=x;
            adde(x,t[u].ch[c]);
            q.push(t[u].ch[c]);
        }
    }
}
int dfn[N],num,sz[N];
inline void dfs(int x){
    dfn[x]=++num,sz[x]=1;
    for(int i=hed[x];i;i=nxt[i]){
        int v=to[i];
        dfs(v);
        sz[x]+=sz[v];
    }
}
int triedfn[N],cont;
struct question{
    int L,R,id;
    bool operator < (const question b)const{return triedfn[pos[R]]<triedfn[pos[b.R]];}
}Q[N];
#define lowbit(x) ((x)&(-x))
int Sum[N];
inline void add(int pos,int add){
    for(;pos<=num;pos+=lowbit(pos))Sum[pos]+=add;
}
inline int query(int pos){
    int ans=0;
    for(;pos;pos-=lowbit(pos))ans+=Sum[pos];
    return ans;
}

inline int askson(int pos){
    int l=dfn[pos]-1;
    int r=dfn[pos]+sz[pos]-1;
    return query(r)-query(l);
}
int ans[N];
int L[N],R[N];
int II=1;
inline void dfstrie(int x){
    add(dfn[x],1);
    while(II<=m&&triedfn[pos[Q[II].R]]==triedfn[x]){
        ans[Q[II].id]=askson(pos[Q[II].L]);
        ++II;
    }
    for(int i=0;i<SZ;i++)if(t[x].ch[i]){
        dfstrie(t[x].ch[i]);
    }
    add(dfn[x],-1);
}
inline void dfsprep(int x){
    triedfn[x]=++cont;
    for(int i=0;i<SZ;i++)if(t[x].ch[i]){
        dfsprep(t[x].ch[i]);
    }
}

int main()
{
    scanf("%s",str+1);
    ins(str);
    build();
    dfs(root);
    dfsprep(root);
    scanf("%d",&m);
    for(int i=1;i<=m;++i){
        Q[i].id=i;scanf("%d%d",&Q[i].L,&Q[i].R);
    }
    sort(Q+1,Q+m+1);
    dfstrie(0);
    for(int i=1;i<=m;i++)
        printf("%d\n",ans[i]);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值