bzoj 2555: SubString

后缀自动机+lct维护fail树
注意在copy q节点的信息的时候,right[cpy]=right[q],动态维护其他信息的时候也要注意这一点。
   
   
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
 
#define ll long long
#define inf 1e9
#define eps 1e-8
#define md
#define N 1200010
using namespace std;
char st[3000010];
int ch[N][2],son[N][26],fa[N],ad[N],sum[N],fail[N],len[N];
bool rev[N];
int last=1,cnt=1;
inline void DecodeWithMask(int mask)
{
int length = strlen(st);
for(int i = 0; i < length; ++i) {
mask = (mask * 131 + i) % length;
swap(st[i],st[mask]);
}
}
 
bool dir(int x) { return ch[fa[x]][1]==x;}
bool isroot(int x) { return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
 
void revit(int x)
{
rev[x]^=1;
swap(ch[x][0],ch[x][1]);
}
 
void release(int x)
{
if (rev[x])
{
rev[x]^=1;
if (ch[x][0]) revit(ch[x][0]);
if (ch[x][1]) revit(ch[x][1]);
}
if (ad[x])
{
int d=ad[x]; ad[x]=0;
if (ch[x][0]) { sum[ch[x][0]]+=d; ad[ch[x][0]]+=d;}
if (ch[x][1]) { sum[ch[x][1]]+=d; ad[ch[x][1]]+=d;}
}
}
 
void down(int x)
{
if (!isroot(x)) down(fa[x]);
release(x);
}
 
void rotate(int x)
{
int y=fa[x],z=fa[y],b=dir(x),c=dir(y),a=ch[x][!b];
if (!isroot(y)) ch[z][c]=x;
if (a) fa[a]=y; fa[y]=x; fa[x]=z;
ch[x][!b]=y; ch[y][b]=a;
}
 
void splay(int x)
{
down(x);
while (!isroot(x))
{
int y=fa[x];
if (isroot(y)) rotate(x);
else
{
if (dir(x)==dir(y)) { rotate(y); rotate(x);}
else { rotate(x); rotate(x);}
}
}
}
 
void access(int x)
{
int t=0;
while (x)
{
splay(x);
ch[x][1]=t;
t=x; x=fa[x];
}
}
 
void makeroot(int x)
{
access(x); splay(x); revit(x);
}
 
void link(int x,int y)
{
makeroot(x); fa[x]=y;
}
 
void cut(int x,int y)
{
makeroot(x); access(y); splay(y);
ch[y][0]=fa[x]=0;
}
 
void add(int x,int y)
{
makeroot(x); access(y); splay(y);
ad[y]++; sum[y]++;
}
 
int query(int x)
{
access(x); splay(x); return sum[x];
}
 
void change(int x,int y)
{
if (fail[x]) cut(x,fail[x]);
fail[x]=y;
link(x,y);
}
 
void insert(int c)
{
int p=last,x=last=++cnt; len[x]=len[p]+1;
while (p&&!son[p][c]) { son[p][c]=x; p=fail[p];}
if (!p) change(x,1);
else
{
int q=son[p][c];
if (len[q]==len[p]+1) change(x,q);
else
{
int cpy=++cnt; len[cpy]=len[p]+1; sum[cpy]=query(q);
memcpy(son[cpy],son[q],sizeof(son[q]));
change(cpy,fail[q]); change(q,cpy); change(x,cpy);
while (p&&son[p][c]==q) { son[p][c]=cpy; p=fail[p];}
}
}
add(1,x);
//for (int y=x;y;y=fail[y]) printf("%d ",y); printf("\n");
}
 
int trans()
{
int l=strlen(st);
int x=1;
for (int i=0;i<l;i++)
{
int c=st[i]-'A';
if (!son[x][c]) return 0;
x=son[x][c];
}//printf("x: %d\n",x);
return query(x);
}
 
void init()
{
scanf("%s",st);
int l=strlen(st);
for (int i=0;i<l;i++) insert(st[i]-'A');
}
 
int main()
{
int tt;
scanf("%d",&tt);
init();
int mask=0;
while (tt--)
{
scanf("%s",st);
if (st[0]=='A')
{
scanf("%s",st);
DecodeWithMask(mask);
//printf("real %s\n",st);
int l=strlen(st);
for (int i=0;i<l;i++)
insert(st[i]-'A');
}
else
{
scanf("%s",st);
DecodeWithMask(mask);
//printf("real %s\n",st);
int ans=trans();
printf("%d\n",ans);
mask^=ans;
}
}
return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值