bzoj2555: SubString
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #define maxn 1200005 7 #define maxl 3000005 8 using namespace std; 9 10 int q,n,tot,root,last,mark,m,ri[maxn],lazy[maxn]; 11 char st[maxl]; 12 void watch(){ 13 int temp=mark; 14 for (int i=1;i<=m;i++){ 15 temp=(temp*131+i-1)%m+1; 16 char t=st[i]; st[i]=st[temp],st[temp]=t,temp--; 17 } 18 } 19 struct Date{ 20 int fa[maxn],son[maxn][2]; 21 int which(int x){ 22 return son[fa[x]][1]==x; 23 } 24 bool isroot(int x){ 25 return son[fa[x]][0]!=x&&son[fa[x]][1]!=x; 26 } 27 void change(int x,int y){ 28 ri[x]+=y,lazy[x]+=y; 29 } 30 void pushdown(int x){ 31 if (lazy[x]==0) return; 32 if (son[x][0]) change(son[x][0],lazy[x]); 33 if (son[x][1]) change(son[x][1],lazy[x]); 34 lazy[x]=0; 35 } 36 void relax(int x){ 37 if (!isroot(x)) relax(fa[x]); 38 pushdown(x); 39 } 40 void rotata(int x){ 41 int y=fa[x],dd=which(y),d=which(x); 42 if (!isroot(y)) son[fa[y]][dd]=x; fa[x]=fa[y]; 43 fa[son[x][d^1]]=y,son[y][d]=son[x][d^1]; 44 fa[y]=x,son[x][d^1]=y; 45 } 46 void splay(int x){ 47 relax(x); 48 while (!isroot(x)){ 49 if (isroot(fa[x])) rotata(x); 50 else if (which(x)==which(fa[x])) rotata(fa[x]),rotata(x); 51 else rotata(x),rotata(x); 52 } 53 } 54 void access(int x){ 55 for (int p=0;x;x=fa[x]){ 56 splay(x); 57 son[x][1]=p; 58 p=x; 59 } 60 } 61 void link(int x,int y){ 62 fa[x]=y,access(y),splay(y),change(y,ri[x]); 63 } 64 void cut(int x){ 65 access(x),splay(x),change(son[x][0],-ri[x]),fa[son[x][0]]=0,son[x][0]=0; 66 } 67 }lct; 68 struct Tsegment{ 69 int fa[maxn],son[maxn][26],dist[maxn]; 70 void prepare(){tot=root=last=1;memset(lazy,0,sizeof(lazy)); memset(ri,0,sizeof(ri));} 71 int newnode(int x){ 72 dist[++tot]=x; return tot; 73 } 74 void add(int x){ 75 int p=last,np=newnode(dist[last]+1); last=np,ri[np]=1; 76 for (;p&&!son[p][x];p=fa[p]) son[p][x]=np; 77 if (p==0) fa[np]=root,lct.link(np,root); 78 else{ 79 int q=son[p][x]; 80 if (dist[p]+1==dist[q]) fa[np]=q,lct.link(np,q); 81 else{ 82 int nq=newnode(dist[p]+1); ri[nq]=0; 83 memcpy(son[nq],son[q],sizeof(son[q])); 84 fa[nq]=fa[q]; lct.cut(q),lct.link(nq,fa[nq]); 85 fa[q]=fa[np]=nq; lct.link(q,nq),lct.link(np,nq); 86 for (;p&&son[p][x]==q;p=fa[p]) son[p][x]=nq; 87 } 88 } 89 } 90 void build(){ 91 for (int i=1;i<=m;i++) add(st[i]-'A'); 92 } 93 void query(){ 94 int x,y; 95 bool can=1; 96 x=root; 97 for (int i=1;i<=m;i++){ 98 y=st[i]-'A'; 99 if (!son[x][y]){ 100 can=0; 101 break; 102 }else{ 103 x=son[x][y]; 104 } 105 } 106 if (can==0||x==root) puts("0"); 107 else{ 108 lct.splay(x); 109 printf("%d\n",ri[x]),mark^=ri[x]; 110 } 111 } 112 }SAM; 113 114 int main(){ 115 scanf("%d",&q),mark=0; 116 scanf("%s",st+1),m=strlen(st+1); 117 SAM.prepare(); 118 SAM.build(); 119 while (q--){ 120 scanf("%s",st+1); 121 if (st[1]=='A') scanf("%s",st+1),m=strlen(st+1),watch(),SAM.build(); 122 else scanf("%s",st+1),m=strlen(st+1),watch(),SAM.query(); 123 } 124 return 0; 125 }
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2555
题目大意:给你一个字符串init,要求你支持两个操作
(1):在当前字符串的后面插入一个字符串
(2):询问字符串s在当前字符串中出现了几次?(作为连续子串)
你必须在线支持这些操作。
做法:如果没有操作1,显然kmp,ac自动机,后缀自动机都可以轻松解决,用后缀自动机的话,就是对原串建立SAM,匹配串在上面匹配,若失配,则输出0,否则一直跳,假设最后跳到了x节点,答案就是,这个状态的right值。right值为parent树中以该节点为根的子树中right值的和,静态的显然比较好维护,但本题是动态加串,由于SAM是用增量法构建的,显然可以维护这个SAM,但是right则不怎么好维护,看了题解后,发现parent树毕竟是一棵树,那显然可以用lct来维护right值。操作2与静态的类似。恶心的就是这题的解密。
后缀自动机+lct。