您的位置:首页 > 其它

【后缀自动机+LCT】BZOJ2555[SubString]题解

2018-01-08 08:24 330 查看

题目概述

给出初始字符串 init 和 m 个操作,操作有两种:1.在当前字符串后插入一个字符串。2.询问一个字符串在当前字符串中的出现次数。强制在线

解题报告

(之前做了后缀自动机和LCT就tm为了这道题)强制在线插入询问,后缀数组,KMP全都不行。数据范围又贼大,我们想到后缀自动机。

后缀自动机求字符串 s 出现次数:先识别 s ,若无法识别,答案为 0 ,否则答案是识别到的节点 p parent树子树中 np 节点的个数。这个还是比较显然的,因为 np 节点对应所有前缀。

因为有插入操作,所以需要动态维护parent树,这就使我们想到了LCT维护子树信息,接下来就是码农时间了QAQ。

示例程序

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1200000,maxl=3000000,maxi=26;

int te,lstans;char s[maxl+5];bool vis[maxn+5];
int si,ro,p,son[maxn+5][maxi],fa[maxn+5],MAX[maxn+5];

inline char readc(){
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
if (l==r) return EOF;return *l++;
}
inline int reads(char *s){
int len=0;char ch=readc();while (!isupper(ch)) ch=readc();
while (isupper(ch)) s[++len]=ch,ch=readc();s[len+1]=0;return len;
}
inline void Decode(char *s,int m){
for (int len=strlen(s),i=0;i<len;i++)
m=(m*131+i)%len,swap(s[i],s[m]);
}
#define is_ro(p) ((p)!=son[fa[p]][0]&&(p)!=son[fa[p]][1])
#define Son(p) ((p)==son[fa[p]][1])
namespace LCT{
int son[maxn+5][2],fa[maxn+5],si[maxn+5][2];bool flip[maxn+5];
inline void Pushup(int p) {si[p][1]=si[son[p][0]][1]+si[son[p][1]][1]+si[p][0]+vis[p];}
inline void Rotate(int t){
int p=fa[t],d=Son(t);son[p][d]=son[t][d^1];son[t][d^1]=p;
Pushup(p);Pushup(t);if (!is_ro(p)) son[fa[p]][Son(p)]=t;
if (son[p][d]) fa[son[p][d]]=p;fa[t]=fa[p];fa[p]=t;
}
inline void Addflip(int p) {swap(son[p][0],son[p][1]);flip[p]^=1;}
inline void Pushdown(int p) {if (flip[p]) flip[p]^=1,Addflip(son[p][0]),Addflip(son[p][1]);}
inline void Splay(int p){
static int top,stk[maxn+5];stk[top=1]=p;
for (int i=p;!is_ro(i);i=fa[i]) stk[++top]=fa[i];
while (top) Pushdown(stk[top--]);
for (int pre=fa[p];!is_ro(p);Rotate(p),pre=fa[p])
if (!is_ro(pre)) Rotate(Son(p)==Son(pre)?pre:p);
}
inline void Access(int p){
for (int lst=0;p;Pushup(p),lst=p,p=fa[p])
Splay(p),si[p][0]+=si[son[p][1]][1]-si[lst][1],son[p][1]=lst;
}
inline void Makero(int x) {Access(x);Splay(x);Addflip(x);}
inline void Link(int x,int y) {Makero(x);Makero(y);fa[x]=y;si[y][0]+=si[x][1];Pushup(y);}
inline void Cut(int x,int y) {Makero(x);Access(y);Splay(y);fa[x]=son[y][0]=0;Pushup(y);}
}
inline void Update(int x,bool f) {LCT::Makero(x);vis[x]=f;LCT::Pushup(x);}
#define newnode(m,f) (fa[++si]=0,Update(si,f),MAX[si]=m,memset(son[si],0,sizeof(son[si])),si)
inline void Extend(int c){
int np=newnode(MAX[p]+1,true);while (p&&!son[p][c]) son[p][c]=np,p=fa[p];
if (!p) fa[np]=ro,LCT::Link(np,ro); else{
int q=son[p][c];
if (MAX[p]+1==MAX[q]) fa[np]=q,LCT::Link(np,q); else{
int nq=newnode(MAX[p]+1,false);memcpy(son[nq],son[q],sizeof(son[q]));
LCT::Cut(q,fa[q]);fa[nq]=fa[q];LCT::Link(nq,fa[q]);
fa[np]=fa[q]=nq;LCT::Link(q,nq);LCT::Link(np,nq);
while (p&&son[p][c]==q) son[p][c]=nq,p=fa[p];
}
}
p=np;
}
inline int Sum(char *s){
int p=ro;for (int i=1;s[i];i++) p=son[p][s[i]-'A'];if (!p) return 0;
LCT::Makero(ro);LCT::Access(p);LCT::Splay(p);int ans=LCT::si[p][0]+vis[p];
return lstans^=ans,ans;
}
int main(){
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
scanf("%d",&te);reads(s);ro=newnode(0,false);p=ro;
for (int i=1;s[i];i++) Extend(s[i]-'A');
while (te--){
reads(s);
if (s[1]=='Q') reads(s),Decode(s+1,lstans),printf("%d\n",Sum(s));
else {reads(s);Decode(s+1,lstans);for (int i=1;s[i];i++) Extend(s[i]-'A');}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: