BZOJ2555: SubString

题面:https://www.lydsy.com/JudgeOnline/problem.php?id=2555
题解:
如果没有修改操作,这就是一道SAM模板题。
有了修改操作后,发现fail树可能会有断边的过程,
不难想到使用LCT维护fail树。
每次加边时,需要将贡献也一并加入LCT的节点中,
查询时,找到对应节点,将其splay到根,此时的val就是答案。
注意:
1.splay时记得要pushdown;
2.是大写字母;
3.数组要开到\(1.2e6\)
时间复杂度:\(O(n+Qlogn)\)
代码:

#pragma GCC optimize(2)
#include
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
typedef long long ll;
#define I inline void
#define IN inline int
#define C(x,y) memset(x,y,sizeof(x))
#define STS system("pause")
templateI read(D &res){
    res=0;register D g=1;register char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')g=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        res=(res<<3)+(res<<1)+(ch^48);
        ch=getchar();
    }
    res*=g;
}
char c[3030000];
int n,m,Q;
namespace LCT{
    int fa[1202000],ch[1202000][2],laz[1202000],w[1202000];
    int st[1202000];
    IN nroot(int x){
        return (ch[fa[x]][0]==x)||(ch[fa[x]][1]==x);
    }
    IN get(int x){
        return ch[fa[x]][1]==x;
    }
    I add(int x,int val){
        if(!x)return;laz[x]+=val;w[x]+=val;
    }
    I push_down(int x){
        add(ch[x][0],laz[x]);add(ch[x][1],laz[x]);
        laz[x]=0;
    }
    I rotate(int x){
        re y=fa[x],z=fa[y],dir=get(x);
        if(nroot(y))ch[z][get(y)]=x;fa[x]=z;
        ch[y][dir]=ch[x][dir^1];fa[ch[x][dir^1]]=y;
        ch[x][dir^1]=y;fa[y]=x;
    }
    I splay(int x){
        re y=x,z=0;st[++z]=y;
        while(y)st[++z]=y=fa[y];
        while(z)push_down(st[z--]);
        while(nroot(x)){
            y=fa[x],z=fa[y];
            if(nroot(y))rotate((get(x)^get(y))?x:y);
            rotate(x);
        }
    }
    I access(int x){
        for(re y=0;x;x=fa[y=x])splay(x),ch[x][1]=y;
    }
    I link(int x,int y){
        fa[x]=y;access(y);splay(y);add(y,w[x]);
    }
    I cut(int x,int y){
        access(x);splay(x);add(ch[x][0],-w[x]);
        fa[ch[x][0]]=0;ch[x][0]=0;
    }
};
namespace SAM{
    int len[1202000],ch[1202000][27],link[1202000],tot,las,p,q,cle,cur;
    I init(){tot=las=1;}
    I add(int x){
        cur=++tot;len[cur]=len[las]+1;p=las;las=cur;LCT::w[cur]=1;
        while(p&&!ch[p][x])ch[p][x]=cur,p=link[p];
        if(!p){link[cur]=1;LCT::link(cur,1);return;}
        q=ch[p][x];
        if(len[p]+1==len[q]){link[cur]=q;LCT::link(cur,q);return;}
        cle=++tot;len[cle]=len[p]+1,link[cle]=link[q];LCT::link(cle,link[cle]);
        memcpy(ch[cle],ch[q],sizeof(ch[q]));
        LCT::cut(q,link[q]);link[q]=cle;LCT::link(q,link[q]);link[cur]=cle;LCT::link(cur,cle);
        while(p&&ch[p][x]==q)ch[p][x]=cle,p=link[p];
    }
    I insert(){F(i,0,n-1)add(c[i]-'A'+1);}
    I ques(){
        p=1;
        F(i,0,n-1){
            if(!ch[p][c[i]-'A'+1]){
                printf("0\n");return;
            }
            p=ch[p][c[i]-'A'+1];
        }
        LCT::splay(p);
        printf("%d\n",LCT::w[p]);m^=LCT::w[p];
    } 
};
I getit(int x){
    scanf("%s",c);n=strlen(c);
    F(i,0,n-1){
        x=(x*131+i)%n;
        swap(c[i],c[x]);
    }
}
int main(){
    read(Q);m=0;
    scanf("%s",c);
    n=strlen(c);
    SAM::init();
    SAM::insert();
    while(Q--){
        scanf("%s",c+1);
        if(c[1]=='A'){
            getit(m);SAM::insert();
        }
        else{
            getit(m);SAM::ques();
        }
    }
    return 0;
}

你可能感兴趣的:(BZOJ2555: SubString)