Description
要求资瓷
- 插入一个字符串
- 查询一个字符串出现的次数
墙制在线,长度 <= 600000,询问次数<= 10000,询问总长度<= 3000000
Solution
拍半天暴力打错了OTZ
据说原本暴力可过???
考虑单次询问怎么做。我们建出模板串的SAM在上面跑,终点的right集合大小显然就是答案
由于这题是动态的,于是我们extend的时候动态维护parent树就行了,直接上LCT维护子树内权值和
好像还可以链修改+单点查询打标记的做法
好像还可以ETT
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define copy(x,t) memcpy(x,t,sizeof(x))
const int N=1200005;
struct treeNode {int son[2],size,siz,val,fa,rev,is_root;} t[N];
int mx[N],fa[N],rec[N][26],last,tot;
char str[N];
void decodeWithMask(char *str,int mask) {
int len=strlen(str);
for (int j=0;j<len;j++) {
mask=(mask*131+j)%len;
std:: swap(str[j],str[mask]);
}
}
void push_up(int x) {
t[x].size=t[t[x].son[0]].size+t[t[x].son[1]].size+t[x].val+t[x].siz;
}
void push_down(int x) {
if (!t[x].rev) return ;
t[x].rev=0; std:: swap(t[x].son[0],t[x].son[1]);
if (t[x].son[0]) t[t[x].son[0]].rev^=1;
if (t[x].son[1]) t[t[x].son[1]].rev^=1;
}
void rotate(int x) {
if (t[x].is_root) return ;
int y=t[x].fa; int z=t[y].fa;
int k=t[y].son[1]==x;
t[y].son[k]=t[x].son[!k];
if (t[x].son[!k]) t[t[x].son[!k]].fa=y;
t[x].son[!k]=y; t[y].fa=x;
t[x].fa=z;
if (t[y].is_root) {
t[x].is_root=1;
t[y].is_root=0;
} else t[z].son[t[z].son[1]==y]=x;
push_up(y); push_up(x);
}
void remove(int x) {
if (!t[x].is_root) remove(t[x].fa);
push_down(x);
}
void splay(int x) {
remove(x);
for (;!t[x].is_root;) {
int y=t[x].fa; int z=t[y].fa;
if (!t[y].is_root) {
if ((t[z].son[1]==y)^(t[y].son[1]==x)) rotate(x);
else rotate(y);
}
rotate(x);
}
}
void access(int x) {
int y=0;
while (x) {
splay(x);
t[y].is_root=0;
t[t[x].son[1]].is_root=1;
t[x].siz+=t[t[x].son[1]].size;
t[x].son[1]=y;
t[x].siz-=t[y].size;
push_up(x);
y=x; x=t[x].fa;
}
}
void mroot(int x) {
access(x);
splay(x);
t[x].rev^=1;
}
void link(int x,int y) {
mroot(x);
access(y);
splay(y);
// mroot(y);
t[x].fa=y;
t[y].siz+=t[x].size;
push_up(y);
}
void cut(int x,int y) {
mroot(x); access(y); splay(y);
t[x].fa=t[y].son[0]=0;
t[x].is_root=1;
push_up(y);
}
void extend(int ch) {
int p,q,np,nq;
p=last; np=last=++tot; mx[np]=mx[p]+1;
t[tot].is_root=t[tot].val=1;
for (;p&&!rec[p][ch];p=fa[p]) rec[p][ch]=np;
if (!p) {
fa[np]=1; link(np,1);
} else {
q=rec[p][ch];
if (mx[p]+1==mx[q]) {
fa[np]=q; link(np,q);
} else {
nq=++tot; mx[nq]=mx[p]+1;
t[tot].is_root=1;
copy(rec[nq],rec[q]);
cut(fa[q],q);
link(nq,fa[q]);
link(q,nq);
link(np,nq);
fa[nq]=fa[q];
fa[np]=fa[q]=nq;
for (;p&&rec[p][ch]==q;p=fa[p]) rec[p][ch]=nq;
}
}
}
int main(void) {
freopen("data.in","r",stdin);
freopen("myp.out","w",stdout);
int T,mask=0; scanf("%d",&T);
last=tot=1; t[1].is_root=1;
scanf("%s",str);
for (int len=strlen(str),i=0;i<len;++i) {
extend(str[i]-'A');
}
for (;T--;) {
char opt[8];
scanf("%s%s",opt,str);
decodeWithMask(str,mask);
int len=strlen(str);
if (opt[0]=='A') {
for (int i=0;i<len;++i) {
extend(str[i]-'A');
}
} else {
int now=1,flag=false;
for (int i=0;i<len;++i) {
if (rec[now][str[i]-'A']) now=rec[now][str[i]-'A'];
else {
flag=true;
break;
}
}
if (!flag) {
mroot(1); access(now);
printf("%d\n", t[now].siz+t[now].val);
mask^=t[now].siz+t[now].val;
} else puts("0");
}
}
return 0;
}