BZOJ 2434: [Noi2011]阿狸的打字机 AC自动机 fail树

来源:互联网 发布:淘宝借贷提前还款 编辑:程序博客网 时间:2024/06/08 10:34

一道AC自动机好题啊,做完了以后对AC自动机有了一个新的认识,首先由于这道题的特殊性我们无需一个一个字符串插入,只要维护一个father指针往回跳就行了,建好树了以后怎么办呢,我们可以想到A在AC自动机上是B的子串当且仅当B的节点跳fail指针可以跳到A,但是这样时间复杂度太大,由于fail指针总是由下向上指所以我们能想得到如果将fail倒过来那么将形成一颗树,我们称之为fail树,那么B的节点跳fail能跳到A等价于B的节点在A的子树中,我们只需维护A的子树中有多少B的节点就好了,我们只要维护一下dfs序就可快速得知子树信息,用树状数组就可以区间求和,由于这道题的特殊性,将询问按照y值排序,我们只需再跑一边字符串就可nlogn维护树状数组,这样这道题就解决了
1A ^_^

#include<cstdio>#include<cstdlib>#include<iostream>#include<iomanip>#include<cstring>#include<string>#include<ctime>#include<cmath>#include<algorithm>using namespace std;struct Trie{    Trie *son[26],*fail,*fa;    int num;    int wz;    Trie()    {        memset(son,0,sizeof(son));        fa=fail=NULL;        num=0;    }}mempool[1000000],*root=&mempool[0];int toppp=0;int top=0;void my_insert(char *s){    root->fa=root;    Trie *o=root;    while(*s)    {        if(*s=='B') o=o->fa;        else if(*s=='P') o->num=++top;        else        {            if(!o->son[*s-'a'])            {                o->son[*s-'a']=&mempool[++toppp];                o->son[*s-'a']->fa=o;            }            o=o->son[*s-'a'];        }        s++;    }}struct edge{    int l,r;}a[1000000];int fir[1000000];int nex[1000000];int tot=0;void add_edge(int l,int r){    a[++tot].l=l;    a[tot].r=r;    nex[tot]=fir[l];    fir[l]=tot;}void bfs(){    static Trie* dui[1000000];    int top=1,my_final=1;    for(int i=0;i<26;i++)    {        if(root->son[i])        {            root->son[i]->fail=root;            add_edge(root->wz,root->son[i]->wz);            dui[my_final++]=root->son[i];        }        else  root->son[i]=root;    }    while(top<my_final)    {        Trie *o=dui[top++];        for(int i=0;i<26;i++)        {            if(o->son[i])            {                dui[my_final++]=o->son[i];                o->son[i]->fail=o->fail->son[i];                add_edge(o->fail->son[i]->wz,o->son[i]->wz);            }            else o->son[i]=o->fail->son[i];        }    }}int dfsx[1000000];int wz[1000000];int tott=0;int my_begin[1000000];int my_end[1000000];int c[1000000];int mapp[1000000];void dfs(int u,int from){    dfsx[++tott]=u;    my_begin[u]=tott;    if(mempool[u].num) mapp[mempool[u].num]=u;    for(int o=fir[u];o!=0;o=nex[o])        if(a[o].r!=from) dfs(a[o].r,u);    dfsx[++tott]=u;    my_end[u]=tott;}struct query{    int x,y,num;    bool operator <(query b) const    {        return y<b.y;    }}queries[1000000];int ans[1000000];inline void add_v(int x,int v){    for(int i=x;i<=tott;i+=i&-i) c[i]+=v;}inline int my_search(int l,int r){    int re=0;    for(int i=r;i;i-=i&-i) re+=c[i];    for(int i=l-1;i;i-=i&-i) re-=c[i];    return re;}int pipei=1;void search_ans(char *s){    Trie *o=root;    add_v(my_begin[root->wz],1);    while(*s)    {        if(*s=='B')        {            add_v(my_begin[o->wz],-1);            o=o->fa;        }        else if(*s=='P')        {            while(queries[pipei].y==o->num)            {                ans[queries[pipei].num]=my_search(my_begin[mapp[queries[pipei].x]],my_end[mapp[queries[pipei].x]]);                pipei++;            }        }        else        {            o=o->son[*s-'a'];            add_v(my_begin[o->wz],1);        }        s++;    }}char s[1000000];int main(){    scanf("%s",s);    my_insert(s);    for(int i=0;i<=toppp;i++) mempool[i].wz=i;    bfs();    dfs(0,-1);    int m;    scanf("%d",&m);    for(int i=1;i<=m;i++) scanf("%d%d",&queries[i].x,&queries[i].y),queries[i].num=i;    sort(queries+1,queries+1+m);    search_ans(s);    for(int i=1;i<=m;i++)    {        printf("%d\n",ans[i]);    }}
1 1
原创粉丝点击