BZOJ 2434 [Noi2011] 阿狸的打字机 Fail树

来源:互联网 发布:海通证券行情软件 编辑:程序博客网 时间:2024/05/19 00:49

2017.3.17补…
题目大意:造一台打字机(滑稽),要求支持:1.在末尾添加一个字符 2.删除结尾字符 3.打印当前字符串 4.回答打印出的第x个字符串在第y个字符串中出现了几次。

询问一个字符串在另一个字符串中的出现次数可以想到利用AC自动机中构造出的Fail树的性质(类似BZOJ3172)。要如何回答询问呢?

查询x在y中出现了几次,就是查询Fail树上x的子树中有多少个结点属于y.

这样的话,维护一个dfs序的树状数组(因为想求子树和,且子树在dfs序中是连续的),而对于一个单词,将他的所有节点插入到树状数组后就可以处理所有与其有关的询问。把所有询问建成一个邻接表,遇到P就处理所有有关这个字符串的询问,最后一起输出即可。

#include <cstdio>#include <cstring>#include <queue>#include <vector>#define pb push_back#define N 100005using namespace std;struct Edge {    int u,v,nxt,ans;}query[N];int fir[N],st[N],ed[N];struct Node {    Node *ch[26],*fail,*pa;    int val,pos;    vector<Node*> to;    Node():val(0),fail(NULL),pa(NULL),pos(0) {        to.clear();        memset(ch,0,sizeof ch);    }}*root=new Node();int len,tot;char s[N];void Insert() {    Node* o=root;    for(int i=0;i<len;i++) {        if(s[i]=='P') o->val=++tot;        else if(s[i]=='B') o=o->pa;        else {            int z=s[i]-'a';            if(!o->ch[z]) o->ch[z]=new Node(), o->ch[z]->pa=o;            o=o->ch[z];        }    }    return ;}void getFail() {    queue<Node*> q;    Node* o=root;    for(int i=0;i<26;i++)        if(o->ch[i]) {            q.push(o->ch[i]);            o->ch[i]->fail=o;            o->to.pb(o->ch[i]);        }        else o->ch[i]=o;    while(!q.empty()) {        o=q.front(); q.pop();        for(int i=0;i<26;i++)            if(o->ch[i]) {                q.push(o->ch[i]);                o->ch[i]->fail=o->fail->ch[i];                o->fail->ch[i]->to.pb(o->ch[i]);            }            else o->ch[i]=o->fail->ch[i];    }    return ;}int T;namespace BIT {    int c[N];    inline int lowbit(int x) {return x&-x;}    void add(int x,int y) {        for(int i=x;i<=T;i+=lowbit(i)) c[i]+=y;        return ;    }    int sum(int x) {        int tmp=0;        for(int i=x;i;i-=lowbit(i)) tmp+=c[i];        return tmp;    }}///build FailTreevoid dfs(Node* o) {    o->pos=++T;    if(o->val) st[o->val]=T;    for(int i=0;i<o->to.size();i++)        dfs(o->to[i]);    if(o->val) ed[o->val]=T;    return ;}void solve() {    using namespace BIT;    Node* o=root;    for(int i=0;i<len;i++) {        if(s[i]=='B') add(o->pos,-1), o=o->pa;        else if(s[i]=='P')            for(int j=fir[o->val];j;j=query[j].nxt)                query[j].ans=sum(ed[query[j].v])-sum(st[query[j].v]-1);        else {            int z=s[i]-'a';            o=o->ch[z];            add(o->pos,1);        }    }    return ;}int main() {    scanf("%s",s);    len=strlen(s);    Insert();    getFail();    dfs(root);    int n;    scanf("%d",&n);    for(int i=1;i<=n;i++) {        int x,y;        scanf("%d%d",&x,&y);        query[i].u=y; query[i].v=x;        query[i].nxt=fir[y]; fir[y]=i;    }    solve();    for(int i=1;i<=n;i++) printf("%d\n",query[i].ans);    return 0;}
1 0