【後綴自動機+LCT】BZOJ2555[SubString]題解

題目概述

給出初始字符串 initm 個操作,操作有兩種:1.在當前字符串後插入一個字符串。2.詢問一個字符串在當前字符串中的出現次數。強制在線

解題報告

(之前做了後綴自動機和LCT就tm爲了這道題)強制在線插入詢問,後綴數組,KMP全都不行。數據範圍又賊大,我們想到後綴自動機。

後綴自動機求字符串 s 出現次數:先識別 s ,若無法識別,答案爲 0 ,否則答案是識別到的節點 p parent樹子樹中 np 節點的個數。這個還是比較顯然的,因爲 np 節點對應所有前綴。

因爲有插入操作,所以需要動態維護parent樹,這就使我們想到了LCT維護子樹信息,接下來就是碼農時間了QAQ。

示例程序

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1200000,maxl=3000000,maxi=26;

int te,lstans;char s[maxl+5];bool vis[maxn+5];
int si,ro,p,son[maxn+5][maxi],fa[maxn+5],MAX[maxn+5];

inline char readc(){
    static char buf[100000],*l=buf,*r=buf;
    if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
    if (l==r) return EOF;return *l++;
}
inline int reads(char *s){
    int len=0;char ch=readc();while (!isupper(ch)) ch=readc();
    while (isupper(ch)) s[++len]=ch,ch=readc();s[len+1]=0;return len;
}
inline void Decode(char *s,int m){
    for (int len=strlen(s),i=0;i<len;i++)
        m=(m*131+i)%len,swap(s[i],s[m]);
}
#define is_ro(p) ((p)!=son[fa[p]][0]&&(p)!=son[fa[p]][1])
#define Son(p) ((p)==son[fa[p]][1])
namespace LCT{
    int son[maxn+5][2],fa[maxn+5],si[maxn+5][2];bool flip[maxn+5];
    inline void Pushup(int p) {si[p][1]=si[son[p][0]][1]+si[son[p][1]][1]+si[p][0]+vis[p];}
    inline void Rotate(int t){
        int p=fa[t],d=Son(t);son[p][d]=son[t][d^1];son[t][d^1]=p;
        Pushup(p);Pushup(t);if (!is_ro(p)) son[fa[p]][Son(p)]=t;
        if (son[p][d]) fa[son[p][d]]=p;fa[t]=fa[p];fa[p]=t;
    }
    inline void Addflip(int p) {swap(son[p][0],son[p][1]);flip[p]^=1;}
    inline void Pushdown(int p) {if (flip[p]) flip[p]^=1,Addflip(son[p][0]),Addflip(son[p][1]);}
    inline void Splay(int p){
        static int top,stk[maxn+5];stk[top=1]=p;
        for (int i=p;!is_ro(i);i=fa[i]) stk[++top]=fa[i];
        while (top) Pushdown(stk[top--]);
        for (int pre=fa[p];!is_ro(p);Rotate(p),pre=fa[p])
            if (!is_ro(pre)) Rotate(Son(p)==Son(pre)?pre:p);
    }
    inline void Access(int p){
        for (int lst=0;p;Pushup(p),lst=p,p=fa[p])
            Splay(p),si[p][0]+=si[son[p][1]][1]-si[lst][1],son[p][1]=lst;
    }
    inline void Makero(int x) {Access(x);Splay(x);Addflip(x);}
    inline void Link(int x,int y) {Makero(x);Makero(y);fa[x]=y;si[y][0]+=si[x][1];Pushup(y);}
    inline void Cut(int x,int y) {Makero(x);Access(y);Splay(y);fa[x]=son[y][0]=0;Pushup(y);}
}
inline void Update(int x,bool f) {LCT::Makero(x);vis[x]=f;LCT::Pushup(x);}
#define newnode(m,f) (fa[++si]=0,Update(si,f),MAX[si]=m,memset(son[si],0,sizeof(son[si])),si)
inline void Extend(int c){
    int np=newnode(MAX[p]+1,true);while (p&&!son[p][c]) son[p][c]=np,p=fa[p];
    if (!p) fa[np]=ro,LCT::Link(np,ro); else{
        int q=son[p][c];
        if (MAX[p]+1==MAX[q]) fa[np]=q,LCT::Link(np,q); else{
            int nq=newnode(MAX[p]+1,false);memcpy(son[nq],son[q],sizeof(son[q]));
            LCT::Cut(q,fa[q]);fa[nq]=fa[q];LCT::Link(nq,fa[q]);
            fa[np]=fa[q]=nq;LCT::Link(q,nq);LCT::Link(np,nq);
            while (p&&son[p][c]==q) son[p][c]=nq,p=fa[p];
        }
    }
    p=np;
}
inline int Sum(char *s){
    int p=ro;for (int i=1;s[i];i++) p=son[p][s[i]-'A'];if (!p) return 0;
    LCT::Makero(ro);LCT::Access(p);LCT::Splay(p);int ans=LCT::si[p][0]+vis[p];
        return lstans^=ans,ans;
}
int main(){
    freopen("program.in","r",stdin);
    freopen("program.out","w",stdout);
    scanf("%d",&te);reads(s);ro=newnode(0,false);p=ro;
    for (int i=1;s[i];i++) Extend(s[i]-'A');
    while (te--){
        reads(s);
        if (s[1]=='Q') reads(s),Decode(s+1,lstans),printf("%d\n",Sum(s));
        else {reads(s);Decode(s+1,lstans);for (int i=1;s[i];i++) Extend(s[i]-'A');}
    }
    return 0;
}
發佈了340 篇原創文章 · 獲贊 124 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章