题链:
http://www.lydsy.com/JudgeOnline/problem.php?id=2555
题解:
后缀自动机+LCT
不难发现,对于输入的询问串,在自动机里trans后的到的状态的Right集合的大小就是答案。
那么后缀自动机本身就是支持在线添加的,问题就是如何维护好parent树,即如何维护好每个状态的Right集合。
那么Link-Cut-Tree就显然可以完成动态维护parent树的任务。
(这里是维护的一颗根固定的树,没有Beroot()等换根函数)
代码:
#include<bits/stdc++.h> #define MAXN 600005 using namespace std; int MASK; struct LCT{ int size; int ch[MAXN*3][2],fa[MAXN*3],lazy[MAXN*3],val[MAXN*3]; bool Who(int x){return ch[fa[x]][0]!=x;} bool Isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;} void Update(int x,int v){val[x]+=v; lazy[x]+=v;} void Pushdown(int x){ if(!Isroot(x)) Pushdown(fa[x]); if(!lazy[x]) return; Update(ch[x][0],lazy[x]); Update(ch[x][1],lazy[x]); lazy[x]=0; } void Rotate(int x){ static int y,z,l1,l2; y=fa[x]; z=fa[y]; l1=Who(y); l2=Who(x); fa[x]=z; if(!Isroot(y)) ch[z][l1]=x; fa[y]=x; fa[ch[x][l2^1]]=y; ch[y][l2]=ch[x][l2^1]; ch[x][l2^1]=y; } void Splay(int x){ static int y; Pushdown(x); for(;y=fa[x],!Isroot(x);Rotate(x)) if(!Isroot(y)) Rotate(Who(y)==Who(x)?y:x); } void Access(int x){ static int y; for(y=0;x;y=x,x=fa[x]) Splay(x),ch[x][1]=y; } void Link(int x,int y){ Access(x); Splay(x); Update(x,val[y]); fa[y]=x; } void Cut(int x){ Access(x); Splay(x); Update(ch[x][0],-val[x]); fa[ch[x][0]]=0; ch[x][0]=0; } int Query(int x){ Splay(x); return val[x]; } }DT; struct SAM{ int size,last; int maxs[MAXN*3],trans[MAXN*3][26],parent[MAXN*3]; int Newnode(int a,int b){ ++size; maxs[size]=a; memcpy(trans[size],trans[b],sizeof(trans[b])); return size; } void Extend(int x){ static int p,np,q,nq; p=last; last=np=Newnode(maxs[p]+1,0); for(;p&&!trans[p][x];p=parent[p]) trans[p][x]=np; if(!p) parent[np]=1; else{ q=trans[p][x]; if(maxs[p]+1!=maxs[q]){ nq=Newnode(maxs[p]+1,q); parent[nq]=parent[q]; parent[q]=parent[np]=nq; for(;p&&trans[p][x]==q;p=parent[p]) trans[p][x]=nq; DT.Cut(q); DT.Link(parent[nq],nq); DT.Link(nq,q); } else parent[np]=q; } DT.val[np]=1; DT.Link(parent[np],np); } void Reset(){ memset(trans[0],0,sizeof(trans[0])); size=0; last=Newnode(0,0); } void Add(char *S){ for(int i=0;S[i];i++) Extend(S[i]-‘A‘); } void Query(char *T){ static int p,ans; p=1; for(int i=0;T[i];i++){ if(!trans[p][T[i]-‘A‘]){ p=0; break; } p=trans[p][T[i]-‘A‘]; } if(!p) ans=0; else ans=DT.Query(p); printf("%d\n",ans); MASK^=ans; } }SUF; void decode(char *S,int mask){ static int len; len=strlen(S); for(int i=0;i<len;i++) mask=(mask*131+i)%len,swap(S[i],S[mask]); } int main(){ static char S[MAXN*5],Type[10]; int Q; scanf("%d",&Q); SUF.Reset(); scanf("%s",S); SUF.Add(S); while(Q--){ scanf("%s%s",Type,S); decode(S,MASK); if(Type[0]==‘A‘) SUF.Add(S); else SUF.Query(S); } return 0; }