首页 > 代码库 > BZOJ 2555 Substring 后缀自动机+Link-Cut-Tree

BZOJ 2555 Substring 后缀自动机+Link-Cut-Tree

题目大意:给定一个初始字符串,提供两种操作:

1.在这个字符串的后面连接一个字符串

2.询问某个字符串在当前串中出现了多少次

SAM大叔的自动机~~

对于每个询问就是在后缀自动机上找到该子串所对应的节点 找不到返回0

然后这个节点的Right集合的大小就是这个子串的出现次数

每次Extend的时候将新建节点沿着parent指针到根的路径上所有点的Right集合大小+1即可

分裂节点的时候要将Right集合一并复制

这方法虽然暴力但是非常有效

由于parent是一棵树,所以可以用LCT来维护这棵树 Extend的时候直接路径修改 O(logn)

结果尼玛反倒变慢了。。。

此外就是解密过程是不改变mask的值的 mask的值只在Query的时候改变 小心被坑


暴力:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int q,mask;
char s[3003003];
namespace Suffix_Automaton{
    struct SAM{
        SAM *son[26],*parent;
        int dpt,size;
        SAM(int _=0):parent(0x0),dpt(_),size(0)
        {
            memset(son,0,sizeof son);
        }
    }*root=new SAM,*last=root;
    void Extend(int x)
    {
        SAM *p=last;
        SAM *np=new SAM(p->dpt+1);
        while(p&&!p->son[x])
            p->son[x]=np,p=p->parent;
        if(!p) np->parent=root;
        else
        {
            SAM *q=p->son[x];
            if(q->dpt==p->dpt+1)
                np->parent=q;
            else
            {
                SAM *nq=new SAM(p->dpt+1);
                memcpy(nq->son,q->son,sizeof nq->son);
                nq->parent=q->parent;
                q->parent=nq;np->parent=nq;
                nq->size=q->size;
                for(;p&&p->son[x]==q;p=p->parent)
                    p->son[x]=nq;
            }
        }
        last=np;
        for(;np;np=np->parent)
            np->size++;
    }
    void Insert()
    {
        int i;
        for(i=1;s[i];i++)
            Extend(s[i]-'A');
    }
    int Query(char *s)
    {
        SAM *p;
        for(p=root;p;p=p->son[(*s++)-'A'])
            if(!*s) return p->size;
        return 0;
    }
}
void Decode(char s[],int mask)
{
    int i,n=strlen(s);
    for(i=0;i<n;i++)
    {
        mask=(mask*131+i)%n;
        swap(s[i],s[mask]);
    }
}
int main()
{
    int i;
    char p[100];
    cin>>q;
    scanf("%s",s+1);
    Suffix_Automaton::Insert();
    for(i=1;i<=q;i++)
    {
        scanf("%s%s",p,s+1);
        Decode(s+1,mask);
        if(p[0]=='Q')
        {
            int temp=Suffix_Automaton::Query(s+1);
            mask^=temp;
            printf("%d\n",temp);
        }
        else
            Suffix_Automaton::Insert();
    }
}

LCT:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int q,mask;
char s[3003003];
namespace Link_Cut_Tree{
    struct abcd{
        abcd *fa,*ls,*rs;
        int val,add_mark;
        abcd();
        void Push_Down();
        void Add(int x);
    }*null=new abcd;
    abcd :: abcd()
    {
        fa=ls=rs=null;
        val=add_mark=0;
    }
    void abcd :: Push_Down()
    {
        if(fa->ls==this||fa->rs==this)
            fa->Push_Down();
        if(add_mark)
        {
            ls->Add(add_mark);
            rs->Add(add_mark);
            add_mark=0;
        }
    }
    void abcd :: Add(int x)
    {
        val+=x;
        add_mark+=x;
    }
    void Zig(abcd *x)
    {
        abcd *y=x->fa;
        y->ls=x->rs;
        x->rs->fa=y;
        x->rs=y;
        x->fa=y->fa;
        if(y==y->fa->ls)
            y->fa->ls=x;
        else if(y==y->fa->rs)
            y->fa->rs=x;
        y->fa=x;
    }
    void Zag(abcd *x)
    {
        abcd *y=x->fa;
        y->rs=x->ls;
        x->ls->fa=y;
        x->ls=y;
        x->fa=y->fa;
        if(y==y->fa->ls)
            y->fa->ls=x;
        else if(y==y->fa->rs)
            y->fa->rs=x;
        y->fa=x;
    }
    void Splay(abcd *x)
    {
        x->Push_Down();
        while(x->fa->ls==x||x->fa->rs==x)
        {
            abcd *y=x->fa,*z=y->fa;
            if(x==y->ls)
            {
                if(y==z->ls)
                    Zig(y);
                Zig(x);
            }
            else
            {
                if(y==z->rs)
                    Zag(y);
                Zag(x);
            }
        }
    }
    void Access(abcd *x)
    {
        abcd *y=null;
        while(x!=null)
        {
            Splay(x);
            x->rs=y;
            y=x;x=x->fa;
        }
    }
    void Cut(abcd *x)
    {
        Access(x);
        Splay(x);
        x->ls->fa=null;
        x->ls=null;
    }
    void Link(abcd *x,abcd *y)
    {
        Cut(x);
        x->fa=y;
    }
 
}
namespace Suffix_Automaton{
    struct SAM{
        SAM *son[26],*parent;
        Link_Cut_Tree::abcd *tree;
        int dpt;
        SAM(int _=0):parent(0x0),dpt(_)
        {
            memset(son,0,sizeof son);
            tree=new Link_Cut_Tree::abcd;
        }
    }*root=new SAM,*last=root;
    void Extend(int x)
    {
        SAM *p=last;
        SAM *np=new SAM(p->dpt+1);
        while(p&&!p->son[x])
            p->son[x]=np,p=p->parent;
        if(!p)
        {
            np->parent=root;
            Link_Cut_Tree::Link(np->tree,root->tree);
        }
        else
        {
            SAM *q=p->son[x];
            if(q->dpt==p->dpt+1)
            {
                np->parent=q;
                Link_Cut_Tree::Link(np->tree,q->tree);
            }
            else
            {
                SAM *nq=new SAM(p->dpt+1);
                memcpy(nq->son,q->son,sizeof nq->son);
                nq->parent=q->parent;
                Link_Cut_Tree::Link(nq->tree,q->parent->tree);
                q->parent=nq;np->parent=nq;
                Link_Cut_Tree::Link(q->tree,nq->tree);
                Link_Cut_Tree::Link(np->tree,nq->tree);
                //nq->size=q->size;
                q->tree->Push_Down();
                nq->tree->val=q->tree->val;
                for(;p&&p->son[x]==q;p=p->parent)
                    p->son[x]=nq;
            }
        }
        last=np;
        //for(;np;np=np->parent)
        //  np->size++;
        Link_Cut_Tree::Access(np->tree);
        Link_Cut_Tree::Splay(np->tree);
        np->tree->Add(1);
    }
    void Insert()
    {
        int i;
        for(i=1;s[i];i++)
            Extend(s[i]-'A');
    }
    int Query(char *s)
    {
        SAM *p;
        for(p=root;p;p=p->son[(*s++)-'A'])
            if(!*s) return p->tree->Push_Down(),p->tree->val;
        return 0;
    }
}
void Decode(char s[],int mask)
{
    int i,n=strlen(s);
    for(i=0;i<n;i++)
    {
        mask=(mask*131+i)%n;
        swap(s[i],s[mask]);
    }
}
int main()
{
    int i;
    char p[100];
    cin>>q;
    scanf("%s",s+1);
    Suffix_Automaton::Insert();
    for(i=1;i<=q;i++)
    {
        scanf("%s%s",p,s+1);
        Decode(s+1,mask);
        if(p[0]=='Q')
        {
            int temp=Suffix_Automaton::Query(s+1);
            mask^=temp;
            printf("%d\n",temp);
        }
        else
            Suffix_Automaton::Insert();
    }
}


BZOJ 2555 Substring 后缀自动机+Link-Cut-Tree