1. 程式人生 > 實用技巧 >LG P5212 SubString

LG P5212 SubString

Description

給定一個字串init,要求支援兩個操作:

  • 在當前字串的後面插入一個字串。

  • 詢問字串 $s$在當前字串中出現了幾次。(作為連續子串)

強制線上。

Solution

由於需要求字串的出現次數,所以使用SAM

一個模式串在文字串中的出現次數是其對應點的子樹endpos並的大小(parent樹上對應點的子樹大小),此處為了防止重複應該只計算為字首的節點(即非複製而來的點)

所以對於所有非複製而來的點,權值為$1$

由於在構建SAM的過程中有的點會更改字尾連結,即有斷邊和加邊的操作,所以應該用LCT維護

在LCT中維護虛邊子樹和與子樹和,答案為

$$lsiz[p]+siz[ch[p][1]]+v[p]$$

$lsiz$為虛邊子樹和,$v$為權值

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
namespace LCT
{
    int tree[8000005][2],tag[8000005],tag2[8000005],fa[8000005],st[8000005],top,rev[8000005],v[8000005];
    void pushdown(int x)
    {
        if(rev[x])
        {
            if(tree[x][0])
            {
                rev[tree[x][
0]]^=1; swap(tree[tree[x][0]][0],tree[tree[x][0]][1]); } if(tree[x][1]) { rev[tree[x][1]]^=1; swap(tree[tree[x][1]][0],tree[tree[x][1]][1]); } rev[x]=0; } } void pushup(int x) { tag[x]
=tag[tree[x][0]]+tag[tree[x][1]]+tag2[x]+v[x]; } bool nroot(int x) { return tree[fa[x]][0]==x||tree[fa[x]][1]==x; } int getson(int x) { return tree[fa[x]][1]==x; } void rotate(int x) { int y=fa[x],z=fa[y],b=getson(x),c=getson(y),a=tree[x][!b]; if(nroot(y)) { tree[z][c]=x; } fa[x]=z; tree[x][!b]=y; fa[y]=x; tree[y][b]=a; if(a) { fa[a]=y; } pushup(y); pushup(x); } void splay(int x) { int top=0; st[++top]=x; for(int i=x;nroot(i);i=fa[i]) { st[++top]=fa[i]; } while(top) { pushdown(st[top--]); } while(nroot(x)) { int y=fa[x]; if(nroot(y)) { getson(x)^getson(y)?rotate(x):rotate(y); } rotate(x); } } void access(int x) { for(int y=0;x;x=fa[y=x]) { splay(x); tag2[x]+=tag[tree[x][1]]-tag[y]; tree[x][1]=y; pushup(x); } } void makeroot(int x) { access(x); splay(x); rev[x]^=1; swap(tree[x][0],tree[x][1]); } void split(int x,int y) { makeroot(x); access(y); splay(y); } void link(int x,int y) { split(x,y); fa[x]=y; tag2[y]+=tag[x]; pushup(y); } void cut(int x,int y) { split(x,y); tree[y][0]=fa[x]=0; pushup(y); } } int q,las=1,tot=1,ans,mask; char str[8000005]; struct SAM { int ch[2],fa,len; }sam[8000005]; inline int read() { int w=0,f=1; char ch=0; while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { w=(w<<1)+(w<<3)+ch-'0'; ch=getchar(); } return w*f; } void decodeWithMask(int mask) { scanf("%s",str); int m=strlen(str); for(int j=0;j<m;j++) { mask=(mask*131+j)%m; swap(str[mask],str[j]); } } void insert(int c) { int p=las,np=las=++tot; sam[np].len=sam[p].len+1; for(;p&&!sam[p].ch[c];p=sam[p].fa) { sam[p].ch[c]=np; } if(!p) { sam[np].fa=1; } else { int q=sam[p].ch[c]; if(sam[q].len==sam[p].len+1) { sam[np].fa=q; } else { int nq=++tot; sam[nq]=sam[q]; LCT::link(nq,sam[nq].fa); sam[nq].len=sam[p].len+1; LCT::cut(q,sam[q].fa); sam[q].fa=sam[np].fa=nq; LCT::link(q,nq); for(;p&&sam[p].ch[c]==q;p=sam[p].fa) { sam[p].ch[c]=nq; } } } LCT::tag[np]=LCT::v[np]=1; LCT::link(np,sam[np].fa); } int main() { q=read(); scanf("%s",str); for(int i=0;str[i];i++) { insert(str[i]-'A'); } for(int i=1;i<=q;i++) { char opt[10]; scanf("%s",opt); decodeWithMask(mask); if(opt[0]=='A') { for(int j=0;str[j];j++) { insert(str[j]-'A'); } } else { int p=1; for(int j=0;str[j]&&p;j++) { p=sam[p].ch[str[j]-'A']; } if(p) { LCT::makeroot(1); LCT::access(p); LCT::splay(p); ans=LCT::tag2[p]+LCT::tag[LCT::tree[p][1]]+LCT::v[p]; } else { ans=0; } mask^=ans; printf("%d\n",ans); } } return 0; }
SubString