[NOI2011]阿狸的打字机

[NOI2011]阿狸的打字机

题目大意:

一个老式的打字机按照如下的方式工作:用一个栈存储想要打印的内容(小写英文字母),B键将栈顶字母出栈,P键将栈中所有字母打印出来。

给定长度为\(n(n\le10^5)\)的操作序列(包含\(26\)个小写字母和操作BP)。\(m(m\le10^5)\)次询问,第\(x\)个打印出来的字符串在第\(y\)个打印出来的字符串中出现了几次。

思路:

该打字机的特性使得我们可以很容易地构造出一个AC自动机,插入小写字母同普通的AC自动机,B操作时直接将返回到当前结点在Trie上的父亲即可。

将原问题放到Fail树上,就是\(x\)对应的子树中有多少个结点对应着\(y\)。求出Fail树的DFS序,树状数组维护即可。

源代码:

#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
#include<algorithm>
inline int getint() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
const int N=1e5+1,M=1e5;
char s[N];
int m,par[N],pos[N],in[N],out[N],cnt,ans[M];
std::vector<int> e[N];
inline void add_edge(const int &u,const int &v) {
    e[u].push_back(v);
    par[v]=u;
}
struct Query {
    int x,y,id;
    bool operator < (const Query &rhs) const {
        return y<rhs.y;
    }
};
Query q[M];
class FenwickTree {
    private:
        int val[N+1];
        int lowbit(const int &x) const {
            return x&-x;
        }
    public:
        void modify(int p,const int &x) {
            for(;p<=cnt;p+=lowbit(p)) val[p]+=x;
        }
        int query(int p) const {
            int ret=0;
            for(;p;p-=lowbit(p)) ret+=val[p];
            return ret;
        }
};
FenwickTree t;
class AhoCorasick {
    private:
        int ch[N][26],last[N],fail[N];
        int sz,new_node() {
            return ++sz;
        }
        int idx(const char &c) const {
            return c-'a';
        }
    public:
        void insert(const char s[]) {
            for(register int i=0,p=0;s[i];i++) {
                if(s[i]=='P') {
                    pos[++pos[0]]=p;
                    continue;
                }
                if(s[i]=='B') {
                    p=last[p];
                    continue;
                }
                const int c=idx(s[i]);
                if(!ch[p][c]) {
                    ch[p][c]=new_node();
                    last[ch[p][c]]=p;
                }
                p=ch[p][c];
            }
        }
        void get_fail() {
            std::queue<int> q;
            for(register int i=0;i<26;i++) {
                if(ch[0][i]) q.push(ch[0][i]);
            }
            while(!q.empty()) {
                const int &x=q.front();
                for(register int i=0;i<26;i++) {
                    int &y=ch[x][i];
                    if(y) q.push(y);
                    (y?fail[y]:y)=ch[fail[x]][i];
                }
                add_edge(fail[x],x);
                q.pop();
            }
        }
        void solve() const {
            for(register int i=0,j=0,k=0,p=0;s[i];i++) {
                if(s[i]=='P') {
                    if(++k==q[j].y) {
                        for(;j<m&&q[j].y==k;j++) {
                            ans[q[j].id]=t.query(out[pos[q[j].x]])-t.query(in[pos[q[j].x]]-1);
                        }
                    }
                    continue;
                }
                if(s[i]=='B') {
                    t.modify(in[p],-1);
                    p=last[p];
                    continue;
                }
                p=ch[p][idx(s[i])];
                t.modify(in[p],1);
            }
        }
};
AhoCorasick ac;
void dfs(const int &x) {
    in[x]=++cnt;
    for(unsigned i=0;i<e[x].size();i++) {
        const int &y=e[x][i];
        dfs(y);
    }
    out[x]=cnt;
}
int main() {
    scanf("%s",s);
    ac.insert(s);
    ac.get_fail();
    dfs(0);
    m=getint();
    for(register int i=0;i<m;i++) {
        q[i].x=getint();
        q[i].y=getint();
        q[i].id=i;
    }
    std::sort(&q[0],&q[m]);
    ac.solve();
    for(register int i=0;i<m;i++) {
        printf("%d\n",ans[i]);
    }
    return 0;
}
posted @ 2018-08-08 19:41 skylee03 阅读(...) 评论(...) 编辑 收藏