bzoj2555 LCT维护后缀自动机

通过用LCT维护parent树来实现后缀自动机的在线操作。

注意right值初始化为0,然后加新结点的时候只要将np的right值设为1,而不需要改变nq的right值,因为nq是内部的结点,np才是外层的结点。

思路很简单,代码真长,调了挺久。。。。不过写起来还算清晰。。。

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=3200100;
const int INF=1e9+10;

char s[maxn];
int len;
char op[20];
int Q;

struct LCT
{
    int pre[maxn],ch[maxn][2],rev[maxn];
    int val[maxn],add[maxn];
    void init()
    {
        MS0(pre);MS0(ch);MS0(rev);MS0(add);
        MS0(val);
    }
    void update_add(int x,int w)
    {
        if(!x) return;
        val[x]+=w;
        add[x]+=w;
    }
    void update_rev(int x)
    {
        if(!x) return;
        swap(ch[x][0],ch[x][1]);
        rev[x]^=1;
    }
    void down(int x)
    {
        if(add[x]){
            update_add(ch[x][0],add[x]);
            update_add(ch[x][1],add[x]);
            add[x]=0;
        }
        if(rev[x]){
            update_rev(ch[x][0]);
            update_rev(ch[x][1]);
            rev[x]=0;
        }
    }
    bool isroot(int x)
    {
        return ch[pre[x]][0]!=x&&ch[pre[x]][1]!=x;
    }
    void up(int x)
    {

    }
    void P(int x)
    {
        if(!isroot(x)) P(pre[x]);
        down(x);
    }
    void rot(int x,int kind)
    {
        int y=pre[x];
        ch[y][kind^1]=ch[x][kind];
        pre[ch[x][kind]]=y;
        if(!isroot(y)) ch[pre[y]][ch[pre[y]][1]==y]=x;
        pre[x]=pre[y];
        ch[x][kind]=y;
        pre[y]=x;
        up(y);
    }
    void splay(int x)
    {
        P(x);
        while(!isroot(x)){
            if(isroot(pre[x])) rot(x,ch[pre[x]][0]==x);
            else{
                int y=pre[x],z=pre[y];
                int kind=ch[y][0]==x,one=0;
                if(ch[y][0]==x&&ch[z][0]==y) one=1;
                if(ch[y][1]==x&&ch[z][1]==y) one=1;
                if(one) rot(y,kind),rot(x,kind);
                else rot(x,kind),rot(x,kind^1);
            }
        }
        up(x);
    }
    int access(int x)
    {
        int t=0;
        while(x){
            splay(x);
            ch[x][1]=t;t=x;x=pre[x];
            up(t);
        }
        return t;
    }
    void makeroot(int x)
    {
        access(x);splay(x);update_rev(x);
    }
    void ADD(int x,int y,int w)
    {
        makeroot(x);access(y);splay(y);
        update_add(y,w);
    }
    void cut(int x,int y)
    {
        makeroot(x);access(y);splay(y);ch[y][0]=pre[x]=0;up(y);
        ADD(y,1,-val[x]);
    }
    void link(int x,int y)
    {
        makeroot(x);pre[x]=y;up(y);
        ADD(y,1,val[x]);
    }
    int query(int x)
    {
        splay(x);
        return val[x];
    }
};LCT lct;

struct SAM
{
    int ch[maxn][26];
    int pre[maxn],step[maxn];
    int last,tot;
    int newnode(int k)
    {
        ++tot;
        step[tot]=k;
        MS0(ch[tot]);
        pre[tot]=0;
        return tot;
    }
    void init()
    {
        tot=0;
        last=newnode(0);
        lct.init();
    }
    void add(int c)
    {
        c-='A';
        int p=last,np=newnode(step[p]+1);
        lct.val[np]=1;
        while(p&&ch[p][c]==0) ch[p][c]=np,p=pre[p];
        if(p==0) pre[np]=1,lct.link(np,1);
        else{
            int q=ch[p][c];
            if(step[q]!=step[p]+1){
                int nq=newnode(step[p]+1);
                memcpy(ch[nq],ch[q],sizeof(ch[q]));
                lct.cut(q,pre[q]);
                lct.link(nq,pre[q]);
                lct.link(q,nq);
                lct.link(np,nq);
                pre[nq]=pre[q];
                pre[q]=pre[np]=nq;
                while(p&&ch[p][c]==q) ch[p][c]=nq,p=pre[p];
            }
            else pre[np]=q,lct.link(np,q);
        }
        last=np;
    }
    int find(char *s)
    {
        int len=strlen(s);
        int u=1;
        REP(i,0,len-1){
            int c=s[i]-'A';
            if(ch[u][c]) u=ch[u][c];
            else return 0;
        }
        return lct.query(u);
    }
};SAM sam;

void decode(char *s,int mask)
{
    int len=strlen(s);
    REP(i,0,len-1){
        mask=(mask*131+i)%len;
        swap(s[i],s[mask]);
    }
}

int main()
{
    freopen("in.txt","r",stdin);
    while(~scanf("%d",&Q)){
        scanf("%s",s);
        len=strlen(s);
        sam.init();
        REP(i,0,len-1) sam.add(s[i]);
        int mask=0;
        REP(i,1,Q){
            scanf("%s%s",op,s);
            decode(s,mask);
            if(op[0]=='A'){
                len=strlen(s);
                REP(i,0,len-1) sam.add(s[i]);
            }
            else{
                int res=sam.find(s);
                printf("%d
",res);
                mask^=res;
            }
        }
    }
    return 0;
}
View Code
没有AC不了的题,只有不努力的ACMER!
原文地址:https://www.cnblogs.com/--560/p/5462859.html