您的位置:首页 > 其它

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: