BZOJ 2555: SubString [后缀自动机 LCT]
Posted Candy?
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 2555: SubString [后缀自动机 LCT]相关的知识,希望对你有一定的参考价值。
2555: SubString
Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 2045 Solved: 583
[Submit][Status][Discuss]
Description
懒得写背景了,给你一个字符串init,要求你支持两个操作
(1):在当前字符串的后面插入一个字符串
(2):询问字符串s在当前字符串中出现了几次?(作为连续子串)
你必须在线支持这些操作。
Input
第一行一个数Q表示操作个数
第二行一个字符串表示初始字符串init
接下来Q行,每行2个字符串Type,Str
Type是ADD的话表示在后面插入字符串。
Type是QUERY的话表示询问某字符串在当前字符串中出现了几次。
为了体现在线操作,你需要维护一个变量mask,初始值为0
读入串Str之后,使用这个过程将之解码成真正询问的串TrueStr。
询问的时候,对TrueStr询问后输出一行答案Result
然后mask = mask xor Result
插入的时候,将TrueStr插到当前字符串后面即可。
HINT:ADD和QUERY操作的字符串都需要解压
题意:
维护一个串,支持在末尾添加一个字符和询问一个串在其中出现了多少次这两个操作。
出现次数就是走完这个字符串到达的状态的|Right|
然后就变成了动态维护Right集合大小
用LCT来维护Parent Tree,支持区间修改和单点查询即可,加入np的时候Link,需要用nq替换q的时候Cut和Link,进行这些操作时需要更新这个点到根的|Right|集合大小
Link和Cut写的灵活一点 要处理到根的路径哦
这里的LCT维护的是有向树,所以不用MakeRoot,连rev都省了
注意:
1.看明白人家mask是传的参数....并且第一个串不用
2.查询时如果走不了转移边就说明没有出现过!!!然后因为打了标记需要先下传标记在用t[u].w
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <map> using namespace std; #define lc t[x].ch[0] #define rc t[x].ch[1] #define pa t[x].fa const int N=2e6+5; inline int read(){ char c=getchar();int x=0,f=1; while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1; c=getchar();} while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘; c=getchar();} return x*f; } struct Node{ int ch[2],fa,w,add; }t[N]; inline int isR(int x){return t[pa].ch[0]!=x&&t[pa].ch[1]!=x;} inline int wh(int x){return t[pa].ch[1]==x;} inline void paint(int x,int d){t[x].add+=d;t[x].w+=d;} inline void pushDown(int x){ if(t[x].add){ paint(lc,t[x].add); paint(rc,t[x].add); t[x].add=0; } } inline void rotate(int x){ int f=t[x].fa,g=t[f].fa,c=wh(x); if(!isR(f)) t[g].ch[wh(f)]=x;t[x].fa=g; t[f].ch[c]=t[x].ch[c^1];t[t[f].ch[c]].fa=f; t[x].ch[c^1]=f;t[f].fa=x; } inline void pd(int x){ if(!isR(x)) pd(t[x].fa); pushDown(x); } inline void splay(int x){ pd(x); for(;!isR(x);rotate(x)) if(!isR(pa)) rotate(wh(x)==wh(pa)?pa:x); } inline void Access(int x){ for(int y=0;x;y=x,x=pa) splay(x),rc=y; } inline void Link(int x,int y){ t[x].fa=y; Access(y);splay(y);paint(y,t[x].w); } inline void Cut(int x){ Access(x);splay(x);paint(lc,-t[x].w); t[lc].fa=0;lc=0; //update(y); } inline void SetW(int x,int v){t[x].w=v;} inline int GetW(int x){return t[x].w;} int n,Q; char s[N],op[20]; int mask; void Decode(char s[],int mask){ for(int j=0;j<n;j++){ mask=(mask*131+j)%n; swap(s[j],s[mask]); } } struct SAM{ struct State{ int ch[26],val,par; }t[N]; int sz,root,last; inline int nw(int _){t[++sz].val=_;return sz;} inline void iniSAM(){sz=0;root=last=nw(0);} void extend(int c){ int p=last,np=nw(t[p].val+1); SetW(np,1); while(p&&!t[p].ch[c]) t[p].ch[c]=np,p=t[p].par; if(!p) t[np].par=root, Link(np,root); else{ int q=t[p].ch[c]; if(t[q].val==t[p].val+1) t[np].par=q, Link(np,q); else{ int nq=nw(t[p].val+1); memcpy(t[nq].ch,t[q].ch,sizeof(t[q].ch)); t[nq].par=t[q].par; Link(nq,t[q].par); t[q].par=t[np].par=nq; Cut(q);Link(q,nq);Link(np,nq); while(p&&t[p].ch[c]==q) t[p].ch[c]=nq,p=t[p].par; } } last=np; } int Query(){ int u=root; for(int i=0;i<n;i++){ int c=s[i]-‘A‘; if(t[u].ch[c]) u=t[u].ch[c]; else return 0; } pd(u);//!! return GetW(u); } void Insert(){ for(int i=0;i<n;i++) extend(s[i]-‘A‘); } }sam; int main(){ freopen("in","r",stdin); sam.iniSAM(); scanf("%d%s",&Q,s); n=strlen(s); sam.Insert(); while(Q--){ scanf("%s%s",op,s); n=strlen(s); Decode(s,mask); if(op[0]==‘A‘) sam.Insert(); else{ int _=sam.Query(); printf("%d\n",_); mask^=_; } //puts(s); } }
以上是关于BZOJ 2555: SubString [后缀自动机 LCT]的主要内容,如果未能解决你的问题,请参考以下文章
bzoj 2555 SubString —— 后缀自动机+LCT
BZOJ2555SubString(后缀自动机,Link-Cut Tree)