码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj2555(后缀自动机+LCT)

时间:2018-12-31 21:15:31      阅读:176      评论:0      收藏:0      [点我收藏+]

标签:print   stream   bool   roo   pre   scan   oid   span   def   

题目描述

(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\n",x);
        }
        else for(int i=1;i<=n;++i)ins(s[i]-A);
    }
    return 0; 
}

bzoj2555(后缀自动机+LCT)

标签:print   stream   bool   roo   pre   scan   oid   span   def   

原文地址:https://www.cnblogs.com/ZH-comld/p/10203207.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!