zoukankan      html  css  js  c++  java
  • bzoj2555(后缀自动机+LCT)

    题目描述

    (1):在当前字符串的后面插入一个字符串
    (2):询问字符串s在当前字符串中出现了几次?(作为连续子串)
    你必须在线支持这些操作。
    题解
    做法很自然,建出后缀自动机,维护每个节点的right集合,对于询问直接在sam上跑就好了。
    然后它是在线的,得用LCT维护。
    然后细节极多,首先必须维护好树的形态,也就是说不能makeroot,所以我的link就长这样。
    inline void link(int x,int y){
        access(x);splay(x);access(y);splay(y);
        f[x]=y;si[y]+=size[x];pushup(y);
    }

    然后cut长这样

    inline void cut(int x,int y){
        access(x);splay(x);
        f[tr[x][0]]=0;tr[x][0]=0;
        pushup(x);
    }

    所以在这颗LCT中,每个点的左儿子维护的是它的父亲,然后我们在算子树和的时候把左儿子扣掉就好了。

    断断续续淦了三天,极菜。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define N 1300002
    using namespace std;
    int size[N],ch[N][26],tr[N][2],fa[N],si[N],last,cnt,n,l[N],q,f[N],val[N];
    int mark;
    char s[N],qs[10];
    inline void pushup(int x){size[x]=size[tr[x][0]]+size[tr[x][1]]+si[x]+val[x];}
    inline bool ge(int x){return tr[f[x]][1]==x;}
    inline bool isroot(int x){return tr[f[x]][0]!=x&&tr[f[x]][1]!=x;}
    inline void rotate(int x){
        int y=f[x],o=ge(x);
        if(isroot(x))return;
        tr[y][o]=tr[x][o^1];f[tr[y][o]]=y;
        if(!isroot(y))tr[f[y]][ge(y)]=x;f[x]=f[y];
        f[y]=x;tr[x][o^1]=y;pushup(y);pushup(x);
    }
    inline void splay(int x){
        while(!isroot(x)){
            int y=f[x];
            if(isroot(y))rotate(x);
            else rotate(ge(x)==ge(y)?y:x),rotate(x);
        }
    }
    inline void access(int x){
        for(int y=0;x;y=x,x=f[x]){
            splay(x);
            si[x]+=size[tr[x][1]];si[x]-=size[y];tr[x][1]=y;
            pushup(x);
        }
    }
    inline void link(int x,int y){
        access(x);splay(x);access(y);splay(y);
        f[x]=y;si[y]+=size[x];pushup(y);
    }
    inline void cut(int x,int y){
        access(x);splay(x);
        f[tr[x][0]]=0;tr[x][0]=0;
        pushup(x);
    }
    void Decode(char *ch,int mask){
        int l=strlen(ch+1);
        for(int i=0;i<l;++i){
            mask=(mask*131+i)%l;
            swap(ch[i+1],ch[mask+1]);
        }
    }
    inline void ins(int x){
        int p=last,np=++cnt;last=np;l[np]=l[p]+1;size[np]=val[np]=1;
        for(;p&&!ch[p][x];p=fa[p])ch[p][x]=np;
        if(!p)fa[np]=1,link(np,1); 
        else{
            int q=ch[p][x];
            if(l[p]+1==l[q])fa[np]=q,link(np,q);
            else{
                int nq=++cnt;l[nq]=l[p]+1;
                memcpy(ch[nq],ch[q],sizeof(ch[q]));
                int y=fa[q];cut(q,y);link(nq,y);
                fa[nq]=fa[q];fa[q]=fa[np]=nq;
                link(q,nq);link(np,nq);
                for(;ch[p][x]==q;p=fa[p])ch[p][x]=nq;
            }
        }
    }
    int query(int n){
        int now=1;
        for(int i=1;i<=n;++i)if(ch[now][s[i]-'A'])now=ch[now][s[i]-'A'];else return 0;
        access(now);splay(now);
        return size[now]-size[tr[now][0]];
    }
    int main(){
        scanf("%d",&q);
        scanf("%s",s+1);n=strlen(s+1);last=cnt=1;
        for(int i=1;i<=n;++i)ins(s[i]-'A');
        while(q--){
            scanf("%s",qs);scanf("%s",s+1);n=strlen(s+1);
            Decode(s,mark);
            if(qs[0]=='Q'){
                int x=query(n);mark^=x;printf("%d
    ",x);
            }
            else for(int i=1;i<=n;++i)ins(s[i]-'A');
        }
        return 0; 
    }
  • 相关阅读:
    How can i install ctags in centos 6.4
    [转载] Ubuntu Vim powerline 插件
    Vim 相关网页
    [转载] vim技巧:设置空格和Tab字符可见
    Don't trust cplusplus.com, it's crap. If any, go to cppreference.com.
    Vim yank only 50 lines
    按进程名终止进程
    Shell 脚本 Tips
    Bash 脚本 逐行处理文本文件的内容
    生成并配置https本地证书
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10203207.html
Copyright © 2011-2022 走看看