BZOJ 2555 Substring(后缀自动机+LCT子树维护)

2555: SubString

Time Limit:30 Sec   Memory Limit:512 MB
Submit:3888   Solved:1177
[ Submit][ Status][ Discuss]

Description

懒得写背景了,给你一个字符串init,要求你支持两个操作
(1):在当前字符串的后面插入一个字符串
(2):询问字符串s在当前字符串中出现了几次?(作为连续子串)
你必须在线支持这些操作。

Input

第一行一个数Q表示操作个数
第二行一个字符串表示初始字符串init
接下来Q行,每行2个字符串Type,Str
Type是ADD的话表示在后面插入字符串。
Type是QUERY的话表示询问某字符串在当前字符串中出现了几次。
为了体现在线操作,你需要维护一个变量mask,初始值为0 

    

读入串Str之后,使用这个过程将之解码成真正询问的串TrueStr。
询问的时候,对TrueStr询问后输出一行答案Result
然后mask=maskxorResult
插入的时候,将TrueStr插到当前字符串后面即可。
HINT:ADD和QUERY操作的字符串都需要解压
长度 <= 600000,询问次数<= 10000,询问总长度<= 3000000
新加数据一组--2015.05.20

Output

Sample Input

2

A

QUERY B

ADD BBABBBBAAB

Sample Output

0

HINT

Source

Ctsc模拟赛By 洁妹


      查找一个字符串在另一个字符串中的出现次数,这是一个很简单的问题。用很多的数据结构的可以解决。但是如果遇到动态的问题就不是那么好解决了。本题要求支持强制在线的增加与查询,纵观字符串的数据结构,只能是后缀自动机了。

      后缀自动机本身加入字符的时候是一个个加入的,在加入的同时本身动态的可以维护parent和len等数据。对于后缀自动机来说,求一个字符串在原串中出现次数,还是和parent树的性质有关。根据parent指针的含义,parent表示的状态是当前状态的后缀,反过来当前状态的串就是parent状态串的拓展。即当前状态串包含parent状态串。所以说,查询出现次数,就是用串在自动机上走,到一个状态之后,看这个状态有多少个拓展串,即有多少个其他状态的parent指向它,对应在parent树中就是节点的子树有多少个有效状态点。问题求变成了维护子树有效状态点数目的问题。

       再进一步把问题剥离,会发现,这题就是维护一个支持动态连接(自动机中新加入点)、动态切断边(自动机中拆出新建点),然后还可以查询子树权值和的数据结构。其中这些边都是parent树中的,故是一个树形结构。LCT正好很好的可以支持连接和切断的功能。但是根据以往的经验,貌似LCT不能累积子树上的权值和。其实做一些变动即可,原本LCT只统计一条链上的数据,对于不在所求链的节点的信息不予以更新,所以每次计算相当于是在链区间内重新覆盖计算。而这里是整个子树的权值和,故不需要重新覆盖计算,累积权值和即可。具体来说,在每次Rotate和Access过程中不对节点数据进行修改,唯一进行修改的地方就是在Splay操作之前,自顶向下把每个节点的标记下放处理。如此一来节点数据不随树的形态而改变,得到了保存,然后在Splay的时候下放标记更新。本题每次新加入节点改变的只是从根到该点的一条链上的节点的数值,所以修改的时候做标记还是对一条链的修改,LCT可以做到。

        继续说说LCT,虽然说可以维护子树的权值和,进一步可以维护极值,但是修改操作确实很局限。至少我现在没有发现什么好方法额能够在利用LCT修改整个子树的数值,然后对于极值,貌似甚至不能支持修改操作,比如说只要一Cut,我就无法确定原本取极值极值节点是否被删除,也就无法确定极值。然后如果一条链数值减少,我也同样无法确定极值是否改变。所以说鱼与熊掌不可兼得嘛……当然了,如果有那个大神知道方法可以解决这个问题,也欢迎提出指正。具体见代码:

#include
#define N 1200010
using namespace std;

struct Link_Cut_Tree
{
    int son[N][2],fa[N],sum[N],lazy[N];
    stack st;

    inline bool which(int x){return son[fa[x]][1]==x;}
    bool isroot(int x){return !fa[x]||son[fa[x]][which(x)]!=x;}

    inline void Rotate(int x)
    {
        int y=fa[x]; bool ch=which(x);
        son[y][ch]=son[x][ch^1];son[x][ch^1]=y;
        if (!isroot(y)) son[fa[y]][which(y)]=x;
        fa[x]=fa[y]; fa[y]=x; fa[son[y][ch]]=y;
    }

    inline void push_down(int x)
    {
        if (!lazy[x]) return;
        int lc=son[x][0],rc=son[x][1];
        if (lc) lazy[lc]+=lazy[x],sum[lc]+=lazy[x];
        if (rc) lazy[rc]+=lazy[x],sum[rc]+=lazy[x];
        lazy[x]=0;
    }

    inline void splay(int x)
    {
    	int i=x;
        for(;!isroot(i);i=fa[i])st.push(i);st.push(i);
        for(;!st.empty();st.pop())push_down(st.top());
        for(int y=fa[x];!isroot(x);Rotate(x),y=fa[x])
            if (!isroot(y)) Rotate(which(x)^which(y)?x:y);
    }

    inline void access(int x)
    {
        for(int y=0;x;x=fa[x])
            splay(x),son[x][1]=y,y=x;
    }

    void beroot(int x){access(x);splay(x);}

    inline void cut(int x)
    {
        beroot(x);
        sum[son[x][0]]-=sum[x];
        lazy[son[x][0]]-=sum[x];
        son[x][0]=fa[son[x][0]]=0;
    }

    inline void link(int x,int y)
    {
        fa[x]=y; beroot(y);
        sum[y]+=sum[x]; lazy[y]+=sum[x];
    }

} LCT;

struct Suffix_Automation
{
    int tot,cur;
    struct node{int ch[26],len,fa;} T[N];
    void init(){cur=tot=1;memset(T,0,sizeof(T));}

    void ins(int x,int id)
    {
        int p=cur; cur=++tot; T[cur].len=id;
        for(;p&&!T[p].ch[x];p=T[p].fa) T[p].ch[x]=cur;LCT.sum[cur]++;
        if (!p){T[cur].fa=1;LCT.link(cur,1);return;}int q=T[p].ch[x];
        if (T[p].len+1==T[q].len) {T[cur].fa=q;LCT.link(cur,q);return;}
        int np=++tot; memcpy(T[np].ch,T[q].ch,sizeof(T[q].ch));
        T[np].fa=T[q].fa; LCT.link(np,T[q].fa);
        T[q].fa=T[cur].fa=np; T[np].len=T[p].len+1;
        LCT.cut(q); LCT.link(q,np); LCT.link(cur,np);
        for(;p&&T[p].ch[x]==q;p=T[p].fa) T[p].ch[x]=np;
    }

} SAM;

char init[N],s[N],op[10];
int mask;

int query(char *s)
{
    int res=0,x=1;
    for(int i=0;s[i];i++)
    {
        int c=s[i]-'A';
        if (SAM.T[x].ch[c]) x=SAM.T[x].ch[c];
                        else return 0;
    }
    LCT.splay(x);
    return LCT.sum[x];
}

void Decode(char s[],int mask)
{
    int n=strlen(s);
    for(int j=0;j

你可能感兴趣的:(Link,Cut,Tree,---------Online,Judge--------,BZOJ,后缀自动机)