【BZOJ2434】【NOI2011】—阿狸的打字机(AC自动机+线段树)

传送门


考虑一个串 A A A在另一个串 B B B中出现的次数

其实就是 B B B串的链上有多少个点的 f a i l fail fail直接或间接指向 A A A的末指针

所以建出 f a i l fail fail树后就是 A A A的末指针的子树和
每次暴力把 B B B的所有点设成1查询可以有 70 70 70

离线后对于每个 B B B记一下要询问哪些就行了
复杂度 O ( n l o g n ) O(nlogn) O(nlogn)

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define gc getchar
inline int read(){
    int res=0,f=1;
    char ch=gc();
    while(!isdigit(ch))f^=ch=='-',ch=gc();
    while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    return f?res:-res;
}
const int N=100005;
char op[N];
int n,m;
namespace Ac{
    struct node{
        int nxt[27],fail,fa;
        vector<int> e;
        vector<int> id;
    }t[N];
    struct ask{
        int x,y,id;
        friend inline bool operator <(const ask &a,const ask &b){
            return a.y<b.y;
        }
    }q[N];
    vector<int> e[N];
    int in[N],out[N],dfn,tot,ql[N],qr[N],ed[N],ans[N];
    int tr[N];
    #define lb(x) (x&(-x))
    inline void update(int p,int k){
        for(;p<=dfn;p+=lb(p))tr[p]+=k;
    }
    inline int query(int p,int res=0){
        for(;p;p-=lb(p))res+=tr[p];return res;
    }
    inline void buildfail(){
        queue<int> q;
        for(int i=0;i<26;i++)
        if(t[0].nxt[i])q.push(t[0].nxt[i]);
        while(!q.empty()){
            int u=q.front();q.pop();
            for(int i=0;i<26;i++){
                int v=t[u].nxt[i];
                if(v)t[v].fail=t[t[u].fail].nxt[i],q.push(v);
                else t[u].nxt[i]=t[t[u].fail].nxt[i];
            }
        }
    }
    void dfs1(int u){
        in[u]=++dfn;
        for(int i=0;i<e[u].size();i++){
            dfs1(e[u][i]);
        }
        out[u]=dfn;
    }
    void dfs2(int u){
        update(in[u],1);
        if(t[u].id.size()){
            for(int j=0;j<t[u].id.size();j++){
                int p=t[u].id[j];
                for(int i=ql[p];i<=qr[p];i++){
                    ans[q[i].id]=query(out[ed[q[i].x]])-query(in[ed[q[i].x]]-1);
                }
            }
        }
        for(int i=0;i<t[u].e.size();i++){
            int v=t[u].e[i];
            dfs2(v);
        }
        update(in[u],-1);
    }
}
using namespace Ac;
int main(){
    scanf("%s",op+1);
    int now=0;
    for(int i=1,len=strlen(op+1);i<=len;i++){
        if(op[i]>='a'&&op[i]<='z'){
            if(!t[now].nxt[op[i]-'a'])t[now].nxt[op[i]-'a']=++tot,t[tot].fa=now;
            now=t[now].nxt[op[i]-'a'];
        }
        if(op[i]=='B')now=t[now].fa;
        if(op[i]=='P')ed[++n]=now,t[now].id.pb(n);
    }
    for(int i=0;i<=tot;i++)
        for(int j=0;j<26;j++)if(t[i].nxt[j])t[i].e.pb(t[i].nxt[j]);
    buildfail();
    for(int i=1;i<=tot;i++)e[t[i].fail].pb(i);
    dfs1(0);
    m=read();
    for(int i=1;i<=m;i++)
        q[i].x=read(),q[i].y=read(),q[i].id=i;
    sort(q+1,q+m+1);
    for(int i=1,pos=1;i<=m;i=pos){
        ql[q[i].y]=i;
        while(q[pos].y==q[i].y)pos++;
        qr[q[i].y]=pos-1;
    }
    dfs2(0);
    for(int i=1;i<=m;i++)cout<<ans[i]<<'\n';
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了小程序应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
提供的源码资源涵盖了小程序应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值