zoukankan      html  css  js  c++  java
  • 【BZOJ2434】【NOI2011】—阿狸的打字机(AC自动机+线段树)

    传送门


    考虑一个串AA在另一个串BB中出现的次数

    其实就是BB串的链上有多少个点的failfail直接或间接指向AA的末指针

    所以建出failfail树后就是AA的末指针的子树和
    每次暴力把BB的所有点设成1查询可以有7070

    离线后对于每个BB记一下要询问哪些就行了
    复杂度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]<<'
    ';
    }
    
    
  • 相关阅读:
    css实现多行文本溢出显示省略号(…)全攻略
    Git使用教程
    requireJS对文件合并与压缩(二)
    requireJS(版本是2.1.15)学习教程(一)
    谷歌浏览器javascript调试教程
    IPMITool driver
    ironic的自动化脚本
    serial console
    如何将自己写的代码上传到github上
    硬件检查
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/11145542.html
Copyright © 2011-2022 走看看