bzoj2555 LCT维护后缀自动机
通过用LCT维护parent树来实现后缀自动机的在线操作。
注意right值初始化为0,然后加新结点的时候只要将np的right值设为1,而不需要改变nq的right值,因为nq是内部的结点,np才是外层的结点。
思路很简单,代码真长,调了挺久。。。。不过写起来还算清晰。。。
#include<bits/stdc++.h> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) using namespace std; typedef long long ll; const int maxn=3200100; const int INF=1e9+10; char s[maxn]; int len; char op[20]; int Q; struct LCT { int pre[maxn],ch[maxn][2],rev[maxn]; int val[maxn],add[maxn]; void init() { MS0(pre);MS0(ch);MS0(rev);MS0(add); MS0(val); } void update_add(int x,int w) { if(!x) return; val[x]+=w; add[x]+=w; } void update_rev(int x) { if(!x) return; swap(ch[x][0],ch[x][1]); rev[x]^=1; } void down(int x) { if(add[x]){ update_add(ch[x][0],add[x]); update_add(ch[x][1],add[x]); add[x]=0; } if(rev[x]){ update_rev(ch[x][0]); update_rev(ch[x][1]); rev[x]=0; } } bool isroot(int x) { return ch[pre[x]][0]!=x&&ch[pre[x]][1]!=x; } void up(int x) { } void P(int x) { if(!isroot(x)) P(pre[x]); down(x); } void rot(int x,int kind) { int y=pre[x]; ch[y][kind^1]=ch[x][kind]; pre[ch[x][kind]]=y; if(!isroot(y)) ch[pre[y]][ch[pre[y]][1]==y]=x; pre[x]=pre[y]; ch[x][kind]=y; pre[y]=x; up(y); } void splay(int x) { P(x); while(!isroot(x)){ if(isroot(pre[x])) rot(x,ch[pre[x]][0]==x); else{ int y=pre[x],z=pre[y]; int kind=ch[y][0]==x,one=0; if(ch[y][0]==x&&ch[z][0]==y) one=1; if(ch[y][1]==x&&ch[z][1]==y) one=1; if(one) rot(y,kind),rot(x,kind); else rot(x,kind),rot(x,kind^1); } } up(x); } int access(int x) { int t=0; while(x){ splay(x); ch[x][1]=t;t=x;x=pre[x]; up(t); } return t; } void makeroot(int x) { access(x);splay(x);update_rev(x); } void ADD(int x,int y,int w) { makeroot(x);access(y);splay(y); update_add(y,w); } void cut(int x,int y) { makeroot(x);access(y);splay(y);ch[y][0]=pre[x]=0;up(y); ADD(y,1,-val[x]); } void link(int x,int y) { makeroot(x);pre[x]=y;up(y); ADD(y,1,val[x]); } int query(int x) { splay(x); return val[x]; } };LCT lct; struct SAM { int ch[maxn][26]; int pre[maxn],step[maxn]; int last,tot; int newnode(int k) { ++tot; step[tot]=k; MS0(ch[tot]); pre[tot]=0; return tot; } void init() { tot=0; last=newnode(0); lct.init(); } void add(int c) { c-='A'; int p=last,np=newnode(step[p]+1); lct.val[np]=1; while(p&&ch[p][c]==0) ch[p][c]=np,p=pre[p]; if(p==0) pre[np]=1,lct.link(np,1); else{ int q=ch[p][c]; if(step[q]!=step[p]+1){ int nq=newnode(step[p]+1); memcpy(ch[nq],ch[q],sizeof(ch[q])); lct.cut(q,pre[q]); lct.link(nq,pre[q]); lct.link(q,nq); lct.link(np,nq); pre[nq]=pre[q]; pre[q]=pre[np]=nq; while(p&&ch[p][c]==q) ch[p][c]=nq,p=pre[p]; } else pre[np]=q,lct.link(np,q); } last=np; } int find(char *s) { int len=strlen(s); int u=1; REP(i,0,len-1){ int c=s[i]-'A'; if(ch[u][c]) u=ch[u][c]; else return 0; } return lct.query(u); } };SAM sam; void decode(char *s,int mask) { int len=strlen(s); REP(i,0,len-1){ mask=(mask*131+i)%len; swap(s[i],s[mask]); } } int main() { freopen("in.txt","r",stdin); while(~scanf("%d",&Q)){ scanf("%s",s); len=strlen(s); sam.init(); REP(i,0,len-1) sam.add(s[i]); int mask=0; REP(i,1,Q){ scanf("%s%s",op,s); decode(s,mask); if(op[0]=='A'){ len=strlen(s); REP(i,0,len-1) sam.add(s[i]); } else{ int res=sam.find(s); printf("%d\n",res); mask^=res; } } } return 0; }
没有AC不了的题,只有不努力的ACMER!