题意:
给出一个字符串和m次操作;
每次有两种操作,"ADD"在串后面再加入一个串,"QUERY"查询询问串在整个字符串出现了多少次;
强制在线;
题解:
考虑对原串构建后缀自动机,并利用其为增量法构建的原理维护"ADD"操作;
然后因为这是一个自动机,所以它可以用来识别原串所有的后缀,当识别未完成时,得到的就是一个子串;
那么当延trans指针走了自动机上的某个状态,这个状态的right集合大小就是这个串的出现次数了;
但是right集合不能增量维护,如果直接每次在链上做修改那个复杂度是错的;
所以我们可以用一个数据结构来维护这个修改,那就是LCT了!
虽说如此,LCT不能直接用来维护子树权值的和,但是每次修改造成的影响都是对祖先那一条链上的,这个是可以维护的;
注意在复制结点的时候也要复制right域哦;
时间复杂度O(nlogn);
代码:
#include<stdio.h> #include<string.h> #include<algorithm> #define N 610000 #define M 3100000 #define S 26 using namespace std; char str[M],op[10]; namespace LCT { #define which(x) (ch[fa[x]][1]==x) int fa[N<<1],ch[N<<1][2],val[N<<1],cov[N<<1]; bool rt[N<<1],rev[N<<1]; void reverse(int x) { swap(ch[x][0],ch[x][1]); rev[x]^=1; } void Pushdown(int x) { if(rev[x]) { reverse(ch[x][0]); reverse(ch[x][1]); rev[x]=0; } if(cov[x]) { cov[ch[x][0]]+=cov[x]; cov[ch[x][1]]+=cov[x]; val[ch[x][0]]+=cov[x]; val[ch[x][1]]+=cov[x]; cov[x]=0; } } void down(int x) { if(!rt[x]) down(fa[x]); Pushdown(x); } void Rotate(int x) { int f=fa[x]; bool k=which(x); ch[f][k]=ch[x][!k]; ch[x][!k]=f; if(rt[f]) rt[f]^=rt[x]^=1; else ch[fa[f]][which(f)]=x; fa[ch[f][k]]=f; fa[x]=fa[f]; fa[f]=x; } void Splay(int x) { down(x); while(!rt[x]) { int f=fa[x]; if(rt[f]) { Rotate(x); break; } if(which(x)^which(f)) Rotate(x); else Rotate(f); } } void access(int x) { int y=0; while(x) { Splay(x); rt[ch[x][1]]=1; rt[y]=0; ch[x][1]=y; y=x,x=fa[x]; } } void Mtr(int x) { access(x); Splay(x); reverse(x); } void update(int x,int v) { Mtr(x),access(1),Splay(x); val[x]+=v;cov[x]+=v; } void Link(int x,int y) { Mtr(x); fa[x]=y; } void Cut(int x,int y) { Mtr(x),access(y),Splay(x); fa[ch[x][1]]=0; rt[ch[x][1]]=1; ch[x][1]=0; } int getsum(int x) { if(!x) return 0; Splay(x); return val[x]; } #undef which } namespace SAM { int son[N<<1][S],pre[N<<1],len[N<<1]; bool is[N<<1]; int tot,last; int newnode(int v) { tot++; is[tot]=v; LCT::rt[tot]=1; return tot; } void init() { tot=0; last=newnode(0); } void replace(int x,int y) { if(pre[x]) { if(is[x]) LCT::update(x,-1); LCT::Cut(x,pre[x]); } LCT::Link(x,y); if(is[x]) LCT::update(x,1); pre[x]=y; } void Insert(int x) { int p,np=newnode(1); len[np]=len[last]+1; for(p=last;p&&!son[p][x];p=pre[p]) son[p][x]=np; if(!p) replace(np,1); else { int q=son[p][x]; if(len[q]==len[p]+1) replace(np,q); else { int nq=newnode(0); len[nq]=len[p]+1; LCT::Splay(q); LCT::val[nq]=LCT::val[q]-is[q]; replace(nq,pre[q]); memcpy(son[nq],son[q],sizeof(int)*S); replace(np,nq),replace(q,nq); for(;son[p][x]==q;p=pre[p]) son[p][x]=nq; } } last=np; } int query(char *s) { int p=1; while(*s!='\0') p=son[p][*s-'A'],s++; return p; } } void decode(char *s,int len,int mask) { for(int j=0;j<len;j++) { mask=(mask*131+j)%len; swap(s[j],s[mask]); } } int main() { int m,len,i,j,k,mask,ans; scanf("%d",&m); scanf("%s",str); len=strlen(str); SAM::init(); for(i=0;i<len;i++) SAM::Insert(str[i]-'A'); for(i=1,mask=0;i<=m;i++) { scanf("%s%s",op,str); len=strlen(str); decode(str,len,mask); if(op[0]=='A') { for(j=0;j<len;j++) SAM::Insert(str[j]-'A'); } else { ans=LCT::getsum(SAM::query(str)); printf("%d\n",ans); mask^=ans; } } return 0; }