bzoj2555substring
Posted zcysky
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj2555substring相关的知识,希望对你有一定的参考价值。
蒟蒻有生之年终于切掉了这道题……在陈丽杰的sam课件上就有这道题,但是zcysky太菜一直不敢做。
其实现在做一下,发现这个题目并不是太难。
所谓的出现次数就是这个字符串在SAM上跑完对应的right集合。要支持及时插入,也就是要动态的维护Parent树的形态。
“动态”,“树”,我们很明显本能的会想到动态树。此处动态树肯定是LCT。
回顾Parent tree的性质, 一个父亲节点所表示的所有子串的出现位置相同
并且为其所有子节点的子串的出现位置的集合的并。
这个性质就是解决这道题的关键。
所以我们可以用link-cut-tree维护这一棵Parent tree。(因为要支持加边,同时必须在线)
在插入一个字符时, 对其所对应的parent tree上到根的路径上的节点全部加1. 查询时直接输出一个点上的值即可。
路径修改,单点查询,LCT的权能。
当然这个LCT不是我们平时见到的那种LCT。原因:
- 这是一棵有向树。换而言之,这题不可能有换根操作。(SAM的Parent树的形态是相对固定的)
- 注意link和cut的时候要消除之前的影响,体现在标记上。
- 查询的时候如果没有转移边(trans)可走,证明这个子串就没有出现过。
然后就是……练习码力的时候了。
其实最后写完也才一百多行
你的幻想乡战略游戏,共价大爷游长沙不是也100多行吗!
#include<bits/stdc++.h> #define N 1200005 #define inf 1000000007 using namespace std; int mask;char s[3000005]; int Q; string chars; void gets(int mask){ scanf("%s",s);chars=s; for(int j=0;j<chars.length();j++){ mask=(mask*131+j)%chars.length(); char t=chars[j]; chars[j]=chars[mask]; chars[mask]=t; } } struct Link_Cut_Tree{ int top,fa[N],c[N][2],val[N],tag[N],q[N]; inline void add(int x,int y){if(x)tag[x]+=y,val[x]+=y;} inline void pushdown(int x){ int l=c[x][0],r=c[x][1]; if(tag[x]){ add(l,tag[x]);add(r,tag[x]); tag[x]=0; } } inline bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;} inline void rotate(int x){ int y=fa[x],z=fa[y],l,r; if(c[y][0]==x)l=0;else l=1;r=l^1; if(!isroot(y)){if(c[z][0]==y)c[z][0]=x;else c[z][1]=x;} fa[x]=z;fa[y]=x;fa[c[x][r]]=y; c[y][l]=c[x][r];c[x][r]=y; } inline void splay(int x){ int top=1;q[top]=x; for(int i=x;!isroot(i);i=fa[i])q[++top]=fa[i]; for(int i=top;i;i--)pushdown(q[i]); while(!isroot(x)){ int y=fa[x],z=fa[y]; if(!isroot(y)){ if((c[z][0]==y)^(c[y][0]==x))rotate(x); else rotate(y); }rotate(x); } } void access(int x){for(int t=0;x;t=x,x=fa[x])splay(x),c[x][1]=t;} inline void link(int x,int y){fa[x]=y;access(y);splay(y);add(y,val[x]);} inline void cut(int x){ access(x);splay(x);add(c[x][0],-val[x]); fa[c[x][0]]=0;c[x][0]=0; } }T; struct Suffix_AutoMaton{ int l[N],fa[N],ch[N][26]; int cnt,last; Suffix_AutoMaton(){cnt=1;last=1;} void ins(int c){ int p=last,np=++cnt;last=np;T.val[np]=1;l[np]=l[p]+1; for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np; if(!p)fa[np]=1,T.link(np,1); else{ int q=ch[p][c]; if(l[p]+1==l[q])fa[np]=q,T.link(np,q); else{ int nq=++cnt;l[nq]=l[p]+1; memcpy(ch[nq],ch[q],sizeof(ch[q])); fa[nq]=fa[q];T.link(nq,fa[q]); fa[np]=fa[q]=nq; T.cut(q);T.link(q,nq);T.link(np,nq); for(;ch[p][c]==q;p=fa[p])ch[p][c]=nq; } } } void build(){ scanf("%s",s);int len=strlen(s); for(int i=0;i<len;i++)ins(s[i]-‘A‘); } int query(){ gets(mask); int p=1;int len=chars.length(); for(int i=0;i<len;i++)if(!(p=ch[p][chars[i]-‘A‘]))return 0; T.splay(p); return T.val[p]; } void add(){ gets(mask);int len=chars.length(); for(int i=0;i<len;i++)ins(chars[i]-‘A‘); } }sam; int main(){ scanf("%d",&Q);sam.build(); while(Q--){ scanf("%s",s); if(*s==‘A‘)sam.add(); else{ int ans=sam.query(); printf("%d\n",ans); mask^=ans; } } return 0; }
以上是关于bzoj2555substring的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 2555 2555: SubString (SAM+LCT)