【后缀自动机+LCT】BZOJ2555[SubString]题解
2018-01-08 08:24
330 查看
题目概述
给出初始字符串 init 和 m 个操作,操作有两种:1.在当前字符串后插入一个字符串。2.询问一个字符串在当前字符串中的出现次数。强制在线。解题报告
(之前做了后缀自动机和LCT就tm为了这道题)强制在线插入询问,后缀数组,KMP全都不行。数据范围又贼大,我们想到后缀自动机。后缀自动机求字符串 s 出现次数:先识别 s ,若无法识别,答案为 0 ,否则答案是识别到的节点 p parent树子树中 np 节点的个数。这个还是比较显然的,因为 np 节点对应所有前缀。
因为有插入操作,所以需要动态维护parent树,这就使我们想到了LCT维护子树信息,接下来就是码农时间了QAQ。
示例程序
#include<cstdio> #include<cctype> #include<cstring> #include<algorithm> using namespace std; const int maxn=1200000,maxl=3000000,maxi=26; int te,lstans;char s[maxl+5];bool vis[maxn+5]; int si,ro,p,son[maxn+5][maxi],fa[maxn+5],MAX[maxn+5]; inline char readc(){ static char buf[100000],*l=buf,*r=buf; if (l==r) r=(l=buf)+fread(buf,1,100000,stdin); if (l==r) return EOF;return *l++; } inline int reads(char *s){ int len=0;char ch=readc();while (!isupper(ch)) ch=readc(); while (isupper(ch)) s[++len]=ch,ch=readc();s[len+1]=0;return len; } inline void Decode(char *s,int m){ for (int len=strlen(s),i=0;i<len;i++) m=(m*131+i)%len,swap(s[i],s[m]); } #define is_ro(p) ((p)!=son[fa[p]][0]&&(p)!=son[fa[p]][1]) #define Son(p) ((p)==son[fa[p]][1]) namespace LCT{ int son[maxn+5][2],fa[maxn+5],si[maxn+5][2];bool flip[maxn+5]; inline void Pushup(int p) {si[p][1]=si[son[p][0]][1]+si[son[p][1]][1]+si[p][0]+vis[p];} inline void Rotate(int t){ int p=fa[t],d=Son(t);son[p][d]=son[t][d^1];son[t][d^1]=p; Pushup(p);Pushup(t);if (!is_ro(p)) son[fa[p]][Son(p)]=t; if (son[p][d]) fa[son[p][d]]=p;fa[t]=fa[p];fa[p]=t; } inline void Addflip(int p) {swap(son[p][0],son[p][1]);flip[p]^=1;} inline void Pushdown(int p) {if (flip[p]) flip[p]^=1,Addflip(son[p][0]),Addflip(son[p][1]);} inline void Splay(int p){ static int top,stk[maxn+5];stk[top=1]=p; for (int i=p;!is_ro(i);i=fa[i]) stk[++top]=fa[i]; while (top) Pushdown(stk[top--]); for (int pre=fa[p];!is_ro(p);Rotate(p),pre=fa[p]) if (!is_ro(pre)) Rotate(Son(p)==Son(pre)?pre:p); } inline void Access(int p){ for (int lst=0;p;Pushup(p),lst=p,p=fa[p]) Splay(p),si[p][0]+=si[son[p][1]][1]-si[lst][1],son[p][1]=lst; } inline void Makero(int x) {Access(x);Splay(x);Addflip(x);} inline void Link(int x,int y) {Makero(x);Makero(y);fa[x]=y;si[y][0]+=si[x][1];Pushup(y);} inline void Cut(int x,int y) {Makero(x);Access(y);Splay(y);fa[x]=son[y][0]=0;Pushup(y);} } inline void Update(int x,bool f) {LCT::Makero(x);vis[x]=f;LCT::Pushup(x);} #define newnode(m,f) (fa[++si]=0,Update(si,f),MAX[si]=m,memset(son[si],0,sizeof(son[si])),si) inline void Extend(int c){ int np=newnode(MAX[p]+1,true);while (p&&!son[p][c]) son[p][c]=np,p=fa[p]; if (!p) fa[np]=ro,LCT::Link(np,ro); else{ int q=son[p][c]; if (MAX[p]+1==MAX[q]) fa[np]=q,LCT::Link(np,q); else{ int nq=newnode(MAX[p]+1,false);memcpy(son[nq],son[q],sizeof(son[q])); LCT::Cut(q,fa[q]);fa[nq]=fa[q];LCT::Link(nq,fa[q]); fa[np]=fa[q]=nq;LCT::Link(q,nq);LCT::Link(np,nq); while (p&&son[p][c]==q) son[p][c]=nq,p=fa[p]; } } p=np; } inline int Sum(char *s){ int p=ro;for (int i=1;s[i];i++) p=son[p][s[i]-'A'];if (!p) return 0; LCT::Makero(ro);LCT::Access(p);LCT::Splay(p);int ans=LCT::si[p][0]+vis[p]; return lstans^=ans,ans; } int main(){ freopen("program.in","r",stdin); freopen("program.out","w",stdout); scanf("%d",&te);reads(s);ro=newnode(0,false);p=ro; for (int i=1;s[i];i++) Extend(s[i]-'A'); while (te--){ reads(s); if (s[1]=='Q') reads(s),Decode(s+1,lstans),printf("%d\n",Sum(s)); else {reads(s);Decode(s+1,lstans);for (int i=1;s[i];i++) Extend(s[i]-'A');} } return 0; }
相关文章推荐
- [BZOJ2555]SubString(后缀自动机+lct)
- [后缀自动机][LCT] BZOJ 2555: SubString
- BZOJ 2555: SubString [后缀自动机 LCT]
- BZOJ 2555: SubString 后缀自动机+LCT
- bzoj 2555: SubString 后缀自动机+lct
- BZOJ 2555 SubString LCT 后缀自动机
- 字符串(LCT,后缀自动机):BZOJ 2555 SubString
- BZOJ2555 SubString 【后缀自动机 + LCT】
- 【BZOJ2555】SubString 后缀自动机+LCT
- bzoj 2555: SubString 后缀自动机+LCT
- [BZOJ2555]SubString(后缀自动机+LCT)
- [BZOJ2555]-SubString-后缀自动机+LCT维护parent树
- bzoj 2555: SubString 后缀自动机+LCT
- [BZOJ2555][LCT][后缀自动机]SubString
- BZOJ 2555 SubString 后缀自动机+LCT
- BZOJ2555 SubString 后缀自动机+LCT
- 【bzoj2555】SubString LCT+后缀自动机
- 【bzoj2555】SubString 后缀自动机+LCT
- BZOJ2555:SubString 后缀自动机 LCT
- BZOJ 2555 Substring(后缀自动机+LCT子树维护)