zoukankan      html  css  js  c++  java
  • 【bzoj2010】SubString【后缀自动机+LCT】

    题意:

    有2个操作。
    (1):在当前字符串的后面插入一个字符串
    (2):询问字符串s在当前字符串中出现了几次?(作为连续子串)
    你必须在线支持这些操作。

    题解:

    建后缀自动机。cnt表示当前状态字符串出现的次数。
    每插入一个字符串,就把它插进sam里面,再把往上跳fail走到的节点的cnt值+1。因为当前状态表示的字符串,在fail链上的所有状态肯定也出现了。
    每次查询,顺着sam的边走,最后走到的节点的cnt就是答案。
    可以想到,把fail链倒过来之后形成的一定是一棵树。所以链上加,直接用link-cut tree维护即可。
    注意单点修改后一定要再LCT上splay,access,或者makeroot一下。而且mask穿进解码函数是一个形参!不要直接修改了!

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=600005;
    int m,l,ans,mask;
    char op[10],s[N*5];
    void decode(int mm){
        for(int i=0;i<l;i++){
            mm=(mm*131+i)%l;
            swap(s[i],s[mm]);
        }
    }
    struct LCT{
        int cnt,ch[N*2][2],fa[N*2],val[N*2],rev[N*2],tag[N*2],stk[N*2];
        bool isroot(int u){
            return u!=ch[fa[u]][0]&&u!=ch[fa[u]][1];
        }
        int which(int u){
            return u==ch[fa[u]][1];
        }
        void reverse(int u){
            if(!u){
                return;
            }
            rev[u]^=1;
            swap(ch[u][0],ch[u][1]);
        }
        void add(int u,int v){
            if(!u){
                return;
            }
            tag[u]+=v;
            val[u]+=v;
        }
        void downtag(int u){
            if(rev[u]){
                reverse(ch[u][0]);
                reverse(ch[u][1]);
                rev[u]=0;
            }
            if(tag[u]){
                add(ch[u][0],tag[u]);
                add(ch[u][1],tag[u]);
                tag[u]=0;
            }
        }
        void pushdown(int u){
            stk[stk[0]=1]=u;
            for(;!isroot(u);u=fa[u]){
                stk[++stk[0]]=fa[u];
            }
            while(stk[0]){
                downtag(stk[stk[0]--]);
            }
        }
        void rotate(int x){
            int y=fa[x],md=which(x);
            if(!isroot(y)){
                ch[fa[y]][which(y)]=x;
            }
            fa[x]=fa[y];
            ch[y][md]=ch[x][!md];
            fa[ch[y][md]]=y;
            ch[x][!md]=y;
            fa[y]=x;
        }
        void splay(int u){
            pushdown(u);
            while(!isroot(u)){
                if(!isroot(fa[u])){
                    rotate(which(u)==which(fa[u])?fa[u]:u);
                }
                rotate(u);
            }
        }
        void access(int u){
            for(int v=0;u;v=u,u=fa[u]){
                splay(u);
                ch[u][1]=v;
            }
        }
        void makeroot(int u){
            access(u);
            splay(u);
            reverse(u);
        }
        void link(int u,int v){
            makeroot(u);
            fa[u]=v;
        }
        void cut(int u,int v){
            makeroot(u);
            access(v);
            splay(v);
            fa[u]=ch[v][0]=0;
        }
    }lct;
    struct Sam{
        int last,cnt,ch[N*2][26],fa[N*2],len[N*2],siz[N*2];
        Sam(){
            last=cnt=1;
        }
        void insert(int x){
            int p=last,np=++cnt;
            last=np;
            len[np]=len[p]+1;
            for(;p&&!ch[p][x];p=fa[p]){
                ch[p][x]=np;
            }
            if(!p){
                fa[np]=1;
                lct.link(np,1);
            }else{
                int q=ch[p][x];
                if(len[q]==len[p]+1){
                    fa[np]=q;
                    lct.link(np,q); 
                }else{
                    int nq=++cnt;
                    len[nq]=len[p]+1;
                    memcpy(ch[nq],ch[q],sizeof(ch[q]));
                    fa[nq]=fa[q];
                    lct.link(nq,fa[nq]);
                    lct.cut(q,fa[q]);
                    fa[q]=fa[np]=nq;
                    lct.link(q,fa[q]);
                    lct.link(np,fa[np]);
                    lct.pushdown(q);
                    lct.val[nq]=lct.val[q];
                    lct.access(nq);
                    for(;ch[p][x]==q;p=fa[p]){
                        ch[p][x]=nq;
                    }
                }
            }
            lct.makeroot(1);
            lct.access(np);
            lct.splay(np);
            lct.add(np,1);
        }
        int query(){
            int k=1;
            for(int i=0;i<l;i++){
                if(!ch[k][s[i]-'A']){
                    return 0;
                }
                k=ch[k][s[i]-'A'];
            }
            lct.access(k);
            return lct.val[k];
        }
    }sam;
    int main(){
        scanf("%d%s",&m,s);
        l=strlen(s);
        for(int i=0;i<l;i++){
            sam.insert(s[i]-'A');
        }
        while(m--){
            scanf("%s%s",op,s);
            l=strlen(s);
            decode(mask);
            if(op[0]=='A'){
                for(int i=0;i<l;i++){
                    sam.insert(s[i]-'A');
                }
            }else{
                ans=sam.query();
                printf("%d
    ",ans);
                mask^=ans;
            }
        }
        return 0;
    }
  • 相关阅读:
    数码摄影入门之十 数码相片后期处理
    Easy CHM 2.10
    LeapFTP 3.0.0.43 汉化版(附带LeapFTP 3.0注册码)
    使用“淘宝助理”的常见错误
    “互联网浏览器”控件与webBrowser控件的区别
    易语言源代码毁来者来了!!
    易语言正则表达式的多行匹配替换
    Explorer.exe鲜为人知的参数
    原始套接字概述
    网络技术数据封装
  • 原文地址:https://www.cnblogs.com/2016gdgzoi471/p/9476893.html
Copyright © 2011-2022 走看看