bzoj2555(lct维护sam)
题意:
(1):在当前字符串的后面插入一个字符串
(2):询问字符串s在当前字符串中出现了几次?(作为连续子串)
字符串长度<=6e5,询问总长度<=3e6
分析:
考虑建个sam,然后把slink连起来就形成了一个前缀树
对于每个询问的串,就是求出它在sam里对应的点,然后在slink树种该点子树的size就是答案
用lct维护slink树即可
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1200000; 4 const int maxs=3e6; 5 6 struct LCT 7 { 8 int ch[maxn+5][2],fa[maxn+5],flip[maxn+5]; 9 int top; 10 int q[maxn+5]; 11 int sz[maxn+5]; 12 int tag[maxn+5]; 13 void init() 14 { 15 16 } 17 bool isroot(int x) 18 { 19 return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x; 20 } 21 void add(int x,int data) 22 { 23 if(x) 24 { 25 tag[x]+=data; 26 sz[x]+=data; 27 } 28 } 29 void pushdown(int x) 30 { 31 int l=ch[x][0],r=ch[x][1]; 32 if(flip[x]) 33 { 34 flip[x]^=1;flip[l]^=1;flip[r]^=1; 35 swap(ch[x][0],ch[x][1]); 36 } 37 if(tag[x]) 38 { 39 add(l,tag[x]),add(r,tag[x]); 40 tag[x]=0; 41 } 42 } 43 void rotate(int &x) 44 { 45 int y=fa[x],z=fa[y],l,r; 46 if(ch[y][0]==x) l=0; 47 else l=1; 48 r=l^1; 49 if(!isroot(y)) 50 { 51 if(ch[z][0]==y) ch[z][0]=x; 52 else ch[z][1]=x; 53 } 54 fa[x]=z;fa[y]=x;fa[ch[x][r]]=y; 55 ch[y][l]=ch[x][r];ch[x][r]=y; 56 } 57 void splay(int &x) 58 { 59 top=0; 60 q[++top]=x; 61 for(int i=x;!isroot(i);i=fa[i]) q[++top]=fa[i]; 62 while(top) pushdown(q[top--]); 63 while(!isroot(x)) 64 { 65 int y=fa[x],z=fa[y]; 66 if(!isroot(y)) 67 { 68 if(ch[y][0]==x^ch[z][0]==y) rotate(x); 69 else rotate(y); 70 } 71 rotate(x); 72 } 73 } 74 void access(int x) 75 { 76 for(int t=0;x;t=x,x=fa[x]) 77 splay(x),ch[x][1]=t; 78 } 79 void link(int x,int f) 80 { 81 fa[x]=f; 82 access(f); 83 splay(f); 84 add(f,sz[x]); 85 } 86 void cut(int x) 87 { 88 access(x); 89 splay(x); 90 add(ch[x][0],-sz[x]); 91 fa[ch[x][0]]=0,ch[x][0]=0; 92 } 93 int query(int x) 94 { 95 access(x); 96 splay(x); 97 return sz[x]; 98 } 99 }lct; 100 101 struct SAM 102 { 103 int maxlen[maxn+50],minlen[maxn+50],trans[maxn+50][26],slink[maxn+50]; 104 int sz,last; 105 void init() 106 { 107 for(int i=0;i<26;++i) trans[1][i]=slink[1]=-1; 108 maxlen[1]=minlen[1]=0; 109 sz=1; 110 last=1; 111 } 112 int build(int _maxlen,int _minlen,int* _trans,int _slink) 113 { 114 maxlen[++sz]=_maxlen; 115 minlen[sz]=_minlen; 116 for(int i=0;i<26;++i) 117 if(_trans==NULL) trans[sz][i]=-1;else trans[sz][i]=_trans[i]; 118 slink[sz]=_slink; 119 return sz; 120 } 121 int add(char ch,int u) 122 { 123 int c=ch-'A'; 124 int z=build(maxlen[u]+1,-1,NULL,-1); 125 lct.sz[z]=1; 126 int v=u; 127 while(v!=-1&&trans[v][c]==-1) 128 { 129 trans[v][c]=z,v=slink[v]; 130 } 131 if(v==-1)//最简单的情况,suffix-path(u->S)上都没有对应字符ch的转移 132 { 133 minlen[z]=1; 134 slink[z]=1; 135 lct.link(z,1); 136 return z; 137 } 138 int x=trans[v][c]; 139 if(maxlen[v]+1==maxlen[x])//较简单的情况,不用拆分x 140 { 141 minlen[z]=maxlen[x]+1; 142 slink[z]=x; 143 lct.link(z,x); 144 return z; 145 } 146 int y=build(maxlen[v]+1,-1,trans[x],slink[x]); //最复杂的情况,拆分x,y表示<=maxlen[v]+1的那段 147 slink[y]=slink[x]; 148 lct.link(y,slink[y]); 149 minlen[x]=maxlen[y]+1; 150 lct.cut(x); 151 slink[x]=y; 152 lct.link(x,y); 153 minlen[z]=maxlen[y]+1; 154 slink[z]=y; 155 lct.link(z,y); 156 int w=v; 157 while(w!=-1&&trans[w][c]==x) trans[w][c]=y,w=slink[w]; 158 minlen[y]=maxlen[slink[y]]+1; 159 return z; 160 } 161 void append(char *s) 162 { 163 int len=strlen(s); 164 for(int i=0;i<len;++i) last=add(s[i],last); 165 } 166 int query(char *s) 167 { 168 int len=strlen(s); 169 int now=1; 170 for(int i=0;i<len;++i) 171 { 172 now=trans[now][s[i]-'A']; 173 if(now==-1) return 0; 174 } 175 return lct.query(now); 176 } 177 }sam; 178 char s[maxs+5]; 179 int mask=0; 180 void gets(int mask) 181 { 182 scanf("%s",s); 183 int len=strlen(s); 184 for (int j=0;j<len;j++) 185 { 186 mask=(mask*131+j)%len; 187 char t=s[j]; 188 s[j]=s[mask]; 189 s[mask]=t; 190 } 191 } 192 int main() 193 { 194 int q; 195 scanf("%d",&q); 196 sam.init(); 197 scanf("%s",s); 198 sam.append(s); 199 while(q--) 200 { 201 scanf("%s",s); 202 if(s[0]=='A') 203 { 204 gets(mask); 205 sam.append(s); 206 } 207 else 208 { 209 gets(mask); 210 int ans=sam.query(s); 211 mask^=ans; 212 printf("%d\n",ans); 213 } 214 } 215 return 0; 216 }