zoukankan      html  css  js  c++  java
  • bzoj 2434 fail tree+dfs序

      首先比较明显的是我们可以将字符串组建立ac自动机,那么对于询问s1字符串在s2字符串中出现的次数,就是在以s1结尾为根的fail tree中,子树有多少个节点是s2的节点,这样我们处理fail tree的dfs序,然后用BIT维护,但是如果只是在线处理询问的话会tle,因为每个询问需要将节点的每一位在BIT中都修改,那么我们就浪费了好多性质,因为对于好多字符串拥有较长的LCP,那么我们可以模拟建trie的过程在自动机上跑,每遇到一个添加的字符,就解决所有询问为某字符串在该字符串中出现的次数,这样就可以了。

    /**************************************************************
        Problem: 2434
        User: BLADEVIL
        Language: C++
        Result: Accepted
        Time:852 ms
        Memory:39128 kb
    ****************************************************************/
     
    //By BLADEVIL
    #include <cstdio>
    #include <cstring>
    #define maxn 200010
     
    using namespace std;
     
    struct node{
        int cnt,last,left,right;
        node *child[30],*fail,*father;
        node(){
            cnt=last=left=right=0;
            fail=father=NULL;
            memset(child,0,sizeof child);
        }
    }nodepool[maxn],*totnode,*root,*que[maxn],*adr[maxn],*other[maxn],*adrans[maxn];
    char c[maxn];
    int len,tot,l,sum;
    int pre[maxn],bit[maxn];
    int ll,preans[maxn],otherans[maxn],lastans[maxn],sizeans[maxn];
    int ans[maxn];
     
    void add(int x,int y){
        while (x<=sum){
            bit[x]+=y;
            x+=x&(-x);
        }
    }
     
    int ask(int x){
        int ans=0;
        while (x){
            ans+=bit[x];
            x-=x&(-x);
        }
        return ans;
    }
     
    void connect(node *x,node *y){
        pre[++l]=x->last;
        x->last=l;
        other[l]=y;
        //printf("%d %d
    ",x,y);
    }
     
    void connectans(int x,int y,int z){
        preans[++l]=lastans[x];
        lastans[x]=l;
        otherans[l]=y;
        sizeans[l]=z;
    }
     
    void build_trie(){
        totnode=nodepool; root=totnode++;
        scanf("%s",&c); len=strlen(c);
        node *t=root;
        for (int i=0;i<len;i++){
            if (c[i]=='P') adrans[++tot]=t; else
            if (c[i]=='B') t=t->father; else {
                if (!t->child[c[i]-'a']) 
                    t->child[c[i]-'a']=totnode++,t->child[c[i]-'a']->father=t;
                t=t->child[c[i]-'a'];
                adr[i]=t;
            };
            //printf("%d ",t);
        }
        //printf("
    ");
        //for (int i=0;i<len;i++) printf("%d ",adr[i]);
        //for (node *i=nodepool;i!=totnode;i++) printf("%d %d
    ",i,i->father);
    }
     
    void build_ac(){
        int h=0,t=1;
        que[1]=root; root->fail=root;
        for (int i=0;i<26;i++) if (!root->child[i]) root->child[i]=root;
        while (h<t){
            node *v=que[++h];
            for (int i=0;i<26;i++) if (v->child[i]&&v->child[i]!=root){
                que[++t]=v->child[i];
                node *u=v->fail;
                que[t]->fail=u->child[i]!=que[t]?u->child[i]:root;
            } else v->child[i]=v->fail->child[i];
        }
        //for (int i=1;i<=t;i++) printf("%d %d ",que[i],que[i]->fail); printf("
    ");
        //for (int i=1;i<=tot;i++) printf("%d ",adr[i]); printf("
    ");
    }
     
    void dfs(node *x,node *fa){
        //printf("%d %d %d
    ",x,fa,sum);
        x->left=++sum;
        for (int p=x->last;p;p=pre[p]){
            if (other[p]==fa) continue;
            dfs(other[p],x);
        }
        x->right=sum;
    }
     
    /*void work(){
        for (node *i=nodepool;i!=totnode;i++) if (i!=root) connect(i->fail,i);
        dfs(root,NULL);
        //for (node *i=nodepool;i!=totnode;i++) printf("%d %d %d %d
    ",i,i->left,i->right,i->father);
        int m;
        scanf("%d",&m);
        while (m--){
            int x,y;
            scanf("%d %d",&x,&y);
            for (node *i=adr[y];i!=root;i=i->father) add(i->left,1);//printf("%d ",i->left);
            //printf("%d %d",adr[x]->left,adr[x]->right);
            //printf("%d ",ask(adr[x]->right));
            printf("%d
    ",ask(adr[x]->right)-ask(adr[x]->left-1));
            for (node *i=adr[y];i!=root;i=i->father) add(i->left,-1);
        }
    }*/
     
    void work(){
        for (node *i=nodepool;i!=totnode;i++) if (i!=root) connect(i->fail,i);
        dfs(root,NULL);
        int m;
        scanf("%d",&m);
        for (int i=1;i<=m;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            connectans(y,x,i);
        }
        int stack[maxn],tot=0,ansy=0;
        memset(stack,0,sizeof stack);
        for (int i=0;i<len;i++){
            if (c[i]=='P'){
                ansy++;
                for (int p=lastans[ansy];p;p=preans[p]){
                    ans[sizeans[p]]=ask(adrans[otherans[p]]->right)-ask(adrans[otherans[p]]->left-1);
                }
            } else
            if (c[i]=='B') {
                add(adr[stack[tot--]]->left,-1);
            } else {
                stack[++tot]=i;
                add(adr[i]->left,1);
            }
        }
        for (int i=1;i<=m;i++) printf("%d
    ",ans[i]);
    }
     
    int main(){
        build_trie();
        build_ac();
        work();
        return 0;
    }
  • 相关阅读:
    POJ 2236 Wireless Network(并查集)
    POJ 2010 Moo University
    POJ 3614 Sunscreen(贪心,区间单点匹配)
    POJ 2184 Cow Exhibition(背包)
    POJ 1631 Bridging signals(LIS的等价表述)
    POJ 3181 Dollar Dayz(递推,两个long long)
    POJ 3046 Ant Counting(递推,和号优化)
    POJ 3280 Cheapest Palindrome(区间dp)
    POJ 3616 Milking Time(dp)
    POJ 2385 Apple Catching(01背包)
  • 原文地址:https://www.cnblogs.com/BLADEVIL/p/3580825.html
Copyright © 2011-2022 走看看