bzoj 2555: SubString
显然,在后缀自动机的后缀树上插入一个后缀后,此时表示整串的节点(np)到根的所有节点,其表示的串作为子串的出现次数都要+1;发现需要链修改,动态连边/删边,因此用LCT维护
注意:虽然没明确写,但根据讨论区以及做题情况,此题字符集只有AB两个字母
错误记录:没有msk^=res
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 int Add(int a,int b) {return a+b;} 6 int Add(int a,int b,int c) {return a+b+c;} 7 int Mul(int a,int b) {return a*b;} 8 namespace LCT 9 { 10 const int N=1200000; 11 struct Node 12 { 13 Node *ch[2],*fa; 14 bool rev; 15 int addv; 16 int dat,sz; 17 void upd() {sz=(ch[0]?ch[0]->sz:0)+1+(ch[1]?ch[1]->sz:0);} 18 void padd(int x) {addv=Add(addv,x);dat=Add(dat,x);} 19 void pd() 20 { 21 if(rev) 22 { 23 swap(ch[0],ch[1]); 24 if(ch[0]) ch[0]->rev^=1; 25 if(ch[1]) ch[1]->rev^=1; 26 rev=0; 27 } 28 if(addv) 29 { 30 if(ch[0]) ch[0]->padd(addv); 31 if(ch[1]) ch[1]->padd(addv); 32 addv=0; 33 } 34 } 35 bool isroot() {return (!fa)||(this!=fa->ch[0]&&this!=fa->ch[1]);} 36 bool gson() {return this==fa->ch[1];} 37 void rot()//将自身向上旋,要求已经完成下传标记 38 { 39 bool d=gson();Node *f=fa; 40 fa=f->fa;if(!f->isroot()) f->fa->ch[f->gson()]=this; 41 f->ch[d]=ch[!d];if(ch[!d]) ch[!d]->fa=f; 42 f->fa=this;ch[!d]=f; 43 f->upd();upd(); 44 } 45 }nodes[N+100]; 46 Node *st[N+100];int top; 47 int mem; 48 Node *getnode() 49 { 50 Node *t=nodes+mem++;t->sz=1;//t->ch[0]=t->ch[1]=t->fa=0;t->rev=t->addv=t->dat=0; 51 return t; 52 } 53 void solvetag(Node *o) 54 { 55 while(!o->isroot()) st[++top]=o,o=o->fa; 56 st[++top]=o; 57 while(top) st[top--]->pd(); 58 } 59 void splay(Node *o) 60 { 61 solvetag(o); 62 for(;!o->isroot();o->rot()) 63 if(!o->fa->isroot()) 64 o->gson()==o->fa->gson()?o->fa->rot():o->rot(); 65 } 66 void acc(Node *o) 67 { 68 for(Node *lst=0;o;lst=o,o=o->fa) 69 splay(o),o->ch[1]=lst,o->upd(); 70 } 71 void mtop(Node *o) {acc(o);splay(o);o->rev^=1;} 72 void link(Node *x,Node *y) {acc(x);splay(x);x->fa=y;}//保证x是根,使x成为y子节点 73 void cut(Node *x) {acc(x);splay(x);x->ch[0]->fa=0;x->ch[0]=0;}//断开x与父亲 74 void add(Node *y,int t) {acc(y);splay(y);y->padd(t);}//y到根路径+t 75 int query(Node *y) {splay(y);return y->dat;}//查询y单点的权值 76 } 77 using LCT::Node;using LCT::link;using LCT::getnode;using LCT::cut;using LCT::query; 78 namespace SAM 79 { 80 int mem,np,root; 81 int len[1200100],fa[1200100],trans[1200100][3]; 82 Node *nd[1200100]; 83 void append(int c) 84 { 85 int p=np;np=++mem;len[np]=len[p]+1;nd[np]=getnode(); 86 for(;p&&trans[p][c]==0;p=fa[p]) trans[p][c]=np; 87 if(!p) link(nd[np],nd[root]),fa[np]=root; 88 else 89 { 90 int q=trans[p][c]; 91 if(len[q]==len[p]+1) link(nd[np],nd[q]),fa[np]=q; 92 else 93 { 94 int nq=++mem;nd[nq]=getnode();nd[nq]->dat=query(nd[q]); 95 cut(nd[q]);link(nd[nq],nd[fa[q]]);link(nd[q],nd[nq]);link(nd[np],nd[nq]); 96 fa[nq]=fa[q];fa[q]=fa[np]=nq; 97 memcpy(trans[nq],trans[q],sizeof(trans[nq]));len[nq]=len[p]+1; 98 for(;p&&trans[p][c]==q;p=fa[p]) trans[p][c]=nq; 99 } 100 } 101 LCT::add(nd[np],1); 102 } 103 int query(const char *ss,int len) 104 { 105 int now=root,i; 106 for(i=0;i<len;i++) 107 { 108 now=trans[now][ss[i]-'A']; 109 if(!now) return 0; 110 } 111 return query(nd[now]); 112 } 113 } 114 char tmp[3000100],ttt[10];int len,q; 115 void decode(int msk) 116 { 117 for(int j=0;j<len;j++) 118 { 119 msk=(msk*131+j)%len; 120 swap(tmp[j],tmp[msk]); 121 } 122 } 123 int main() 124 { 125 int msk=0,res,i;SAM::np=SAM::root=++SAM::mem;SAM::nd[SAM::root]=getnode(); 126 scanf("%d",&q); 127 scanf("%s",tmp);len=strlen(tmp); 128 for(i=0;i<len;i++) SAM::append(tmp[i]-'A'); 129 while(q--) 130 { 131 scanf("%s",ttt); 132 if(ttt[0]=='A') 133 { 134 scanf("%s",tmp);len=strlen(tmp);decode(msk); 135 for(i=0;i<len;i++) SAM::append(tmp[i]-'A'); 136 } 137 else if(ttt[0]=='Q') 138 { 139 scanf("%s",tmp);len=strlen(tmp);decode(msk); 140 res=SAM::query(tmp,len);msk^=res;printf("%d\n",res); 141 } 142 } 143 return 0; 144 }