BZOJ 2555: SubString
BZOJ 2555: SubString
标签(空格分隔): OI-BZOJ OI-后缀自动机 OI-LCT
Time Limit: 30 Sec
Memory Limit: 512 MB
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操作的字符串都需要解压
Output
Sample Input
2
A
QUERY B
ADD BBABBBBAAB
Sample Output
0
HINT
40 % 的数据字符串最终长度 <= 20000,询问次数<= 1000,询问总长度<= 10000
100 % 的数据字符串最终长度 <= 600000,询问次数<= 10000,询问总长度<= 3000000
新加数据一组--2015.05.20
Solution####
给一组自己玩的数据:
10
A
QUERY B
ADD BBABBBBAAB
QUERY AB
ADD BBABBBBAAB
QUERY ABB
ADD BBABBBBAAB
QUERY ABB
ADD BBABBBBAAB
QUERY ABB
ADD BBABBBBAAB
输出
0
3
4
3
6
构造后缀自动机,每个状态的right集合大小即为当前串的出现次数。
用LCT维护自动机的fail树在线得到每个点的right集合大小
Code####
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<bitset>
#include<vector>
using namespace std;
#define PA pair<int,int>
int read()
{
int s=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+ch-'0';ch=getchar();}
return s*f;
}
//smile please
const int N=600005;
struct tree;
extern tree t[N*2];
struct tree
{
int w[2],f,s,r,la;
void down()
{
if(r)swap(w[0],w[1]);
if(w[0])t[w[0]].r^=r;
if(w[1])t[w[1]].r^=r;r=0;
s+=la;
if(w[0])t[w[0]].la+=la;
if(w[1])t[w[1]].la+=la;
la=0;
}
void updata()
{
}
}t[N*2];
bool notroot(int x)
{
return t[t[x].f].w[0]==x||t[t[x].f].w[1]==x;
}
void rotate(int x)
{
int f=t[x].f,r=(t[f].w[1]==x);
t[x].f=t[f].f;
if(notroot(f))
t[t[f].f].w[t[t[f].f].w[1]==f]=x;
t[f].w[r]=t[x].w[!r];
if(t[x].w[!r])
t[t[x].w[!r]].f=f;
t[f].f=x;
t[x].w[!r]=f;
t[f].updata();
}
int sta[N*2];
void splay(int x)
{
if(x==0)return;
for(sta[++sta[0]]=x;notroot(sta[sta[0]]);)
sta[++sta[0]]=t[sta[sta[0]-1]].f;
while(sta[0])t[sta[sta[0]--]].down();
for(int f;notroot(x);rotate(x))
if(notroot(f=t[x].f))
rotate(t[t[f].f].w[1]==f^t[f].w[1]==x?x:f);
t[x].updata();
}
void access(int x){int xx=x;for(int las=0;x;splay(x),t[x].w[1]=las,las=x,x=t[x].f);splay(xx);}
struct samm
{
int last,total;
int L[N*2],ch[N*2][26],fa[N*2];//,val[N*2];
samm(){total=1,last=1;}
void plu(int x,int s)
{//for(;x;x=fa[x])
// val[x]+=s;
access(x);t[x].la+=s;
}
void fu(int x,int y)
{
splay(x),splay(y);
if(fa[x])
{if(t[x].s)plu(fa[x],-t[x].s);
access(fa[x]);splay(x);t[x].f=0;
}
t[x].f=y;
access(x);
if(t[x].s)
plu(y,t[x].s);
fa[x]=y;
}
void insert(int C)
{int p=last,now=last=++total;
L[now]=L[p]+1;t[now].s=1;
for(;p&&!ch[p][C];p=fa[p])
ch[p][C]=now;
if(!p){fu(now,1);return;}
if(L[ch[p][C]]==L[p]+1){fu(now,ch[p][C]);return;}
int ne=++total,Q=ch[p][C];
memcpy(ch[ne],ch[Q],sizeof(ch[Q]));
fu(ne,fa[Q]);
fu(Q,ne);fu(now,ne);
L[ne]=L[p]+1;
for(;p&&ch[p][C]==Q;p=fa[p])
ch[p][C]=ne;
}
int ST(char z[],int len)
{int now=1;
for(int i=0;i<len;i++)
now=ch[now][z[i]-'A'];
return now;
}
void print()
{
for(int i=1;i<=total;i++)
printf("%d: f_%d l_%d a_%d b_%d c_%d\n",i,fa[i],L[i],ch[i][0],ch[i][1],ch[i][2]);
}
}a;
int len;
char z[3000005];
int Q,mask;
void readstr()
{
len=0;z[0]=getchar();
while(z[0]<'A'||z[len]>'Z')z[0]=getchar();
while(z[len]>='A'&&z[len]<='Z')z[++len]=getchar();
z[len]=0;
}
void decode(int mask)
{
for(int i=0;i<len;i++)
{mask=(mask*131+i)%len;
swap(z[i],z[mask]);
}
}
int solve()
{
int x=a.ST(z,len);
splay(x);
return t[x].s;
}
int main()
{
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
Q=read();
readstr();
for(int i=0;i<len;i++)
a.insert(z[i]-'A');
while(Q--)
{readstr();
if(z[0]=='A')
{readstr();decode(mask);
for(int i=0;i<len;i++)
a.insert(z[i]-'A');
}
else
{readstr();decode(mask);
int ans=solve();
mask^=ans;
printf("%d\n",ans);
}
}
//fclose(stdin);
//fclose(stdout);
return 0;
}