bzoj2555 SubString(后缀自动机+LCT)
2018-01-11 21:49
369 查看
bzoj2555 SubString
原题地址:http://www.lydsy.com/JudgeOnline/problem.php?id=2555题意:
给你一个字符串init,要求你支持两个操作
(1):在当前字符串的后面插入一个字符串
(2):询问字符串s在当前字符串中出现了几次?(作为连续子串)
你必须在线支持这些操作。
数据范围
字符串最终长度 <= 600000,询问次数<= 10000,询问总长度<= 3000000
题解:
动态维护right集合。
那么就是维护每个点的parent树子树大小。
一眼LCT维护子树大小。那不就跟大融合一样?
然后狂T不止,大概是无限循环了,等改了再UPD吧。
UPD:原来先断原pa,再连nB,再连原pa,无限循环,
改成先连原pa,再断原pa,再连nB,A了。不明原因。待UPD。
另外一种做法是可以不维护子树大小,于是一个点加进来时,就把它到根的这条链上的所有点的ans+=这个点的大小。
打标记在splay时pushdown即可,注意询问前要把询问的点push一次。
代码:
一、打标记
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> using namespace std; const int N=3000050; int ccc; struct node { int fa,ch[2],w,tag; void init(int x) {fa=0; ch[0]=ch[1]=0; w=x;tag=0;} }tr ; int q,tail=1,root=1,last=1,ch [26],len ,pa ,lens; char str ,opt[10]; bool isroot(int x) {return tr[tr[x].fa].ch[0]!=x&&tr[tr[x].fa].ch[1]!=x;} void rotate(int x) { int y=tr[x].fa; int z=tr[y].fa; if(!isroot(y)) {if(tr[z].ch[0]==y) tr[z].ch[0]=x; else tr[z].ch[1]=x;} tr[x].fa=z; int l=(tr[y].ch[0]==x)?0:1; int r=l^1; tr[y].ch[l]=tr[x].ch[r]; tr[tr[x].ch[r]].fa=y; tr[x].ch[r]=y; tr[y].fa=x; } void pushdown(int x) { if(tr[x].tag) { if(tr[x].ch[0]) tr[tr[x].ch[0]].tag+=tr[x].tag,tr[tr[x].ch[0]].w+=tr[x].tag; if(tr[x].ch[1]) tr[tr[x].ch[1]].tag+=tr[x].tag,tr[tr[x].ch[1]].w+=tr[x].tag; tr[x].tag=0; } } void push(int x) { if(!isroot(x)) push(tr[x].fa); pushdown(x); } void splay(int x) { push(x); while(!isroot(x)) { int y=tr[x].fa; int z=tr[y].fa; if(!isroot(y)) { if((tr[y].ch[0]==x)^(tr[z].ch[0]==y)) rotate(x); else rotate(y); } rotate(x); } } void access(int x) { for(int y=0;x;y=x,x=tr[x].fa) { splay(x); tr[x].ch[1]=y; } } void cut(int x,int y) {access(x); splay(x); tr[x].ch[0]=0; tr[y].fa=0; tr[y].w+=-tr[x].w; tr[y].tag+=-tr[x].w;} void link(int x,int y) {access(y); splay(y); access(x); splay(x); tr[x].fa=y; tr[y].w+=tr[x].w; tr[y].tag+=tr[x].w;} void insert(int c) { int nd=++tail; tr[nd].init(1); len[nd]=len[last]+1; int tmp=last; for(;tmp&&!ch[tmp][c];tmp=pa[tmp]) ch[tmp][c]=nd; if(!tmp) {link(nd,root); pa[nd]=root;} else { int B=ch[tmp][c]; if(len[B]==len[tmp]+1) {link(nd,B); pa[nd]=B;} else { int nB=++tail; tr[nB].init(0); len[nB]=len[tmp]+1; for(int i=0;i<26;i++) ch[nB][i]=ch[B][i]; link(nB,pa[B]); cut(B,pa[B]); link(B,nB); pa[nB]=pa[B]; pa[B]=nB; for(int i=tmp;i&&ch[i][c]==B;i=pa[i]) ch[i][c]=nB; pa[nd]=nB; link(nd,nB); } } last=nd; } void getstr(int mask) { for(int i=0;i<lens;i++) { mask=(mask*131+i)%lens; char t=str[i]; str[i]=str[mask]; str[mask]=t; } } int query() { int tmp=root; for(int i=0;i<lens;i++) { if(!ch[tmp][str[i]-'A']) return 0; tmp=ch[tmp][str[i]-'A']; } splay(tmp); return tr[tmp].w; } int main() { int mask=0; scanf("%d",&q); scanf("%s",str); lens=strlen(str); for(int i=0;i<lens;i++) insert(str[i]-'A'); while(q--) { scanf("%s",opt); int ret=0; scanf("%s",str); lens=strlen(str); getstr(mask); if(opt[0]=='A') for(int i=0;i<lens;i++) insert(str[i]-'A'); else {ret=query(); printf("%d\n",ret); mask^=ret;} } return 0; }
二、维护子树大小
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> using namespace std; const int N=3000050; int ccc; struct node { int fa,ch[2],size,ss,vr; void init(int x) {fa=0; ch[0]=ch[1]=0; size=x; ss=0; vr=x;} }tr ; int q,tail=1,root=1,last=1,ch [26],len ,pa ,lens; char str ,opt[10]; void update(int x) { int ls=tr[x].ch[0]; int rs=tr[x].ch[1]; tr[x].size=tr[x].ss+tr[x].vr+tr[ls].size+tr[rs].size; } bool isroot(int x) {return tr[tr[x].fa].ch[0]!=x&&tr[tr[x].fa].ch[1]!=x;} void rotate(int x) { int y=tr[x].fa; int z=tr[y].fa; if(!isroot(y)) {if(tr[z].ch[0]==y) tr[z].ch[0]=x; else tr[z].ch[1]=x;} tr[x].fa=z; int l=(tr[y].ch[0]==x)?0:1; int r=l^1; tr[y].ch[l]=tr[x].ch[r]; tr[tr[x].ch[r]].fa=y; tr[x].ch[r]=y; tr[y].fa=x; update(y); update(x); } void splay(int x) { while(!isroot(x)) { int y=tr[x].fa; int z=tr[y].fa; if(!isroot(y)) { if((tr[y].ch[0]==x)^(tr[z].ch[0]==y)) rotate(x); else rotate(y); } rotate(x); } } void access(int x) { for(int y=0;x;y=x,x=tr[x].fa) { splay(x); tr[x].ss+=tr[tr[x].ch[1]].size; tr[x].ss-=tr[y].size; tr[x].ch[1]=y; update(x); } } void cut(int x,int y) {access(x); splay(x); tr[x].ch[0]=0; tr[y].fa=0; update(x);} void link(int x,int y) {access(y); splay(y); access(x); splay(x); tr[x].fa=y; tr[y].ss+=tr[x].size; update(y);} void insert(int c) { int nd=++tail; tr[nd].init(1); len[nd]=len[last]+1; int tmp=last; for(;tmp&&!ch[tmp][c];tmp=pa[tmp]) ch[tmp][c]=nd; if(!tmp) {link(nd,root); pa[nd]=root;} else { int B=ch[tmp][c]; if(len[B]==len[tmp]+1) {link(nd,B); pa[nd]=B;} else { int nB=++tail; tr[nB].init(0); len[nB]=len[tmp]+1; for(int i=0;i<26;i++) ch[nB][i]=ch[B][i]; link(nB,pa[B]); cut(B,pa[B]); link(B,nB); pa[nB]=pa[B]; pa[B]=nB; for(int i=tmp;i&&ch[i][c]==B;i=pa[i]) ch[i][c]=nB; pa[nd]=nB; link(nd,nB); } } last=nd; } void getstr(int mask) { for(int i=0;i<lens;i++) { mask=(mask*131+i)%lens; char t=str[i]; str[i]=str[mask]; str[mask]=t; } } int query() { int tmp=root; for(int i=0;i<lens;i++) { if(!ch[tmp][str[i]-'A']) return 0; tmp=ch[tmp][str[i]-'A']; } access(tmp); return tr[tmp].ss+tr[tmp].vr; } int main() { int mask=0; scanf("%d",&q); scanf("%s",str); lens=strlen(str); for(int i=0;i<lens;i++) insert(str[i]-'A'); while(q--) { scanf("%s",opt); int ret=0; scanf("%s",str); lens=strlen(str); getstr(mask); if(opt[0]=='A') for(int i=0;i<lens;i++) insert(str[i]-'A'); else {ret=query(); printf("%d\n",ret); mask^=ret;} } return 0; }
相关文章推荐
- 后缀自动机 + LCT 【bzoj2555】SubString
- BZOJ2555 SubString 后缀自动机+LCT
- [BZOJ2555]SubString(后缀自动机+lct)
- 【bzoj2555】SubString 后缀自动机+LCT
- BZOJ 2555 Substring(后缀自动机+LCT子树维护)
- BZOJ 2555 SubString 后缀自动机+LCT
- BZOJ 2555 SubString LCT 后缀自动机
- 【bzoj2555】SubString LCT+后缀自动机
- [BZOJ2555][LCT][后缀自动机]SubString
- [BZOJ]2555 Substring 后缀自动机&LCT
- bzoj 2555: SubString 后缀自动机+LCT
- [BZOJ2555]SubString(后缀自动机+LCT)
- 【后缀自动机+LCT】BZOJ2555[SubString]题解
- BZOJ2555:SubString 后缀自动机 LCT
- bzoj 2555: SubString 后缀自动机+LCT
- BZOJ 2555: SubString 后缀自动机 LCT
- bzoj 2555: SubString 后缀自动机+lct
- [后缀自动机][LCT] BZOJ 2555: SubString
- [后缀自动机 LCT] BZOJ 2555 SubString
- BZOJ2555 SubString 【后缀自动机 + LCT】