BZOJ2555 SubString 后缀自动机+LCT/暴力

题意:给定一个字符串,维护:1、在当前字符串后面插入一个字符串  2、询问一个字符串在当前字符串中出现的次数。强制在线

题解:维护自动机,一个字符插入之后其祖先的出现次数全部++,这个可以拿LCT或者暴力来维护,链上修改单点查询。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <climits>
#include <iostream>
#include <algorithm>
using namespace std;

const int MAXK=26;
const int MAXN=3000000+2;
struct SAM{
    int v,c;
    SAM *child[MAXK],*f;
    SAM(int _v):v(_v),c(0),f(0){ memset(child,0,sizeof(child));}
}*root,*last=root=new SAM(0);
int N,Q,mask;
char S[MAXN],T[MAXN];

void Decode(char *S,int mask){
    for(int i=0,j=strlen(S);i<j;i++){
        mask=(mask*131+i)%j;
        swap(S[i],S[mask]);
    }
}

void Extend(SAM *&x,int c){
    SAM *p=last,*np=new SAM(p->v+1);
    while(p && !p->child[c]) p->child[c]=np,p=p->f;

    if(!p) np->f=x;
    else{
        SAM *q=p->child[c];
        if(q->v==p->v+1) np->f=q;
        else{
            SAM *nq=new SAM(p->v+1);
            memcpy(nq->child,q->child,sizeof(q->child));
            nq->f=q->f,q->f=np->f=nq;
            while(p && p->child[c]==q) p->child[c]=nq,p=p->f;
        }
    }
    last=np;

    while(np) np->c++,np=np->f;
}

int Query(SAM *x,char *S){
    SAM *y=x;
    for(int i=0,j=strlen(S);i<j;i++){
        y=y->child[S[i]-'A'];
        if(!y) return 0;
        if(i==j-1) return y->c;
    }
}

int main(){
    scanf("%d %s",&Q,S);
    for(int i=0,j=strlen(S);i<j;i++) Extend(root,S[i]-'A');

    while(Q--){
        scanf("%s",S);
        if(strstr(S,"ADD")){
            scanf("%s",S),Decode(S,mask);
            for(int i=0,j=strlen(S);i<j;i++) Extend(root,S[i]-'A');
        }
        if(strstr(S,"QUERY")){
            scanf("%s",S),Decode(S,mask);
            int t=Query(root,S);
            printf("%d\n",t),mask^=t;
        }
    }

    return 0;
}
View Code

 

posted @ 2017-02-28 23:15  WDZRMPCBIT  阅读(122)  评论(0编辑  收藏  举报