这**什么破题……
看题的时候突然发现:咦这题我怎么见过……后来想起来是sxysxy说给我的一道后缀自动机+LCT的破题,然后我偏不信这个邪,码了个分块hash试图水过去,然后发现不是TLE就是MLE……没办法,只能乖乖写正解了……
加入操作只会在原串末尾加一个字符串,不难想到维护当前串的后缀自动机,加入的时候直接逐个加入字符即可。询问的时候首先在后缀自动机上进行转移,转移到的那个点的right大小即为答案。而一个点的right大小就等于parent树上子树中不是因复制而产生的节点个数(似乎表达有点问题,凑合看吧……),而parent树的形态会发生变化,因此可以用LCT维护子树大小,实现的时候把这个点的父亲到根的值全部加上/减去这个子树的大小即可。
后缀自动机的更新均摊O(1),LCT单次操作均摊O(logn),总复杂度就是$O(|S|\log |S|+\sum{|T|}+Q\log |S|)$,反正跑得挺快就是了。
1 /************************************************************** 2 Problem: 2555 3 User: hzoier 4 Language: C++ 5 Result: Accepted 6 Time:9748 ms 7 Memory:47112 kb 8 ****************************************************************/ 9 #include<cstdio> 10 #include<cstring> 11 #include<algorithm> 12 #define isroot(x) ((x)->p==null||((x)->p->ch[0]!=(x)&&((x)->p->ch[1]!=(x)))) 13 #define dir(x) ((x)==(x)->p->ch[1]) 14 using namespace std; 15 const int maxn=1200010,maxm=3000010; 16 struct node{ 17 int key,lazy; 18 node *ch[2],*p; 19 node(int d=0):key(d),lazy(0){} 20 inline void pushdown(){ 21 if(!lazy)return; 22 key+=lazy; 23 ch[0]->lazy+=lazy; 24 ch[1]->lazy+=lazy; 25 lazy=0; 26 } 27 }null[maxn]; 28 void decode(char*,int,int); 29 void expand(int); 30 int travel(const char*); 31 node *access(node*); 32 void link(node*,node*); 33 void cut(node*); 34 void splay(node*); 35 void rot(node*,int); 36 int root,last,cnt=0,val[maxn]={0},par[maxn]={0},go[maxn][2]={{0}}; 37 char s[maxm],c[maxn]; 38 int n,q,mask=0,ans; 39 int main(){ 40 null->ch[0]=null->ch[1]=null->p=null; 41 root=last=++cnt; 42 null[root].ch[0]=null[root].ch[1]=null[root].p=null; 43 null[root].key=1; 44 scanf("%d%s",&q,s); 45 n=strlen(s); 46 for(int i=0;i<n;i++)expand(s[i]-'A'); 47 while(q--){ 48 scanf("%s%s",c,s); 49 decode(s,n=strlen(s),mask); 50 if(!strcmp(c,"ADD"))for(int i=0;i<n;i++)expand(s[i]-'A'); 51 else{ 52 printf("%d\n",ans=travel(s)); 53 mask^=ans; 54 } 55 } 56 return 0; 57 } 58 void decode(char *s,int n,int mask){ 59 for(int i=0;i<n;i++){ 60 mask=(mask*131+i)%n; 61 swap(s[i],s[mask]); 62 } 63 } 64 void expand(int c){ 65 int p=last,np=++cnt; 66 val[np]=val[p]+1; 67 null[np].ch[0]=null[np].ch[1]=null[np].p=null; 68 null[np].key=1; 69 while(p&&!go[p][c]){ 70 go[p][c]=np; 71 p=par[p]; 72 } 73 if(!p){ 74 par[np]=root; 75 link(null+np,null+root); 76 } 77 else{ 78 int q=go[p][c]; 79 if(val[q]==val[p]+1){ 80 par[np]=q; 81 link(null+np,null+q); 82 } 83 else{ 84 int nq=++cnt; 85 val[nq]=val[p]+1; 86 memcpy(go[nq],go[q],sizeof(go[q])); 87 null[nq].ch[0]=null[nq].ch[1]=null[nq].p=null; 88 par[nq]=par[q]; 89 link(null+nq,null+par[q]); 90 par[np]=par[q]=nq; 91 link(null+np,null+nq); 92 cut(null+q); 93 link(null+q,null+nq); 94 while(p&&go[p][c]==q){ 95 go[p][c]=nq; 96 p=par[p]; 97 } 98 } 99 } 100 last=np; 101 } 102 int travel(const char *c){ 103 int x=root; 104 while(*c)x=go[x][*c++-'A']; 105 if(!x)return 0; 106 splay(null+x); 107 return null[x].key; 108 } 109 node *access(node *x){ 110 node *y=null; 111 while(x!=null){ 112 splay(x); 113 x->ch[1]=y; 114 y=x; 115 x=x->p; 116 } 117 return y; 118 } 119 void link(node *x,node *y){ 120 splay(x); 121 x->p=y; 122 access(y)->lazy+=x->key; 123 } 124 void cut(node *x){ 125 access(x); 126 splay(x); 127 x->ch[0]->lazy-=x->key; 128 x->ch[0]->p=null; 129 x->ch[0]=null; 130 } 131 void splay(node *x){ 132 x->pushdown(); 133 while(!isroot(x)){ 134 if(!isroot(x->p))x->p->p->pushdown(); 135 x->p->pushdown(); 136 x->pushdown(); 137 if(isroot(x->p)){ 138 rot(x->p,dir(x)^1); 139 break; 140 } 141 if(dir(x)==dir(x->p))rot(x->p->p,dir(x->p)^1); 142 else rot(x->p,dir(x)^1); 143 rot(x->p,dir(x)^1); 144 } 145 } 146 void rot(node *x,int d){ 147 node *y=x->ch[d^1]; 148 if((x->ch[d^1]=y->ch[d])!=null)y->ch[d]->p=x; 149 y->p=x->p; 150 if(!isroot(x))x->p->ch[dir(x)]=y; 151 (y->ch[d]=x)->p=y; 152 } 153 /* 154 操作都是向后添加字符,因此考虑后缀自动机。 155 又因为需要动态维护子树大小,因此用LCT维护。 156 */