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
Source
Ctsc模拟赛By 洁妹
看题后想到
SAM+LCT
(事实上全然是听学长讲课时候知道的)(划掉这句话)
刚開始认为可能会非常长写了写发现不是非常长也就不到150行
对SAM的Parent树建LCT,给每一个状态一个权值
然后就能够通过统计LCT的权值来统计出现次数了.
一開始习惯性的在makeroot时候写了打上rev标记可是WA了?
不知道为什么
删掉之后又做了做微调发现自己又是RE又是TLE
最后开大了数据范围就A了.
这个题上经历了WA,RE,TLE,MLE真是感人至深.人生百态
WA多了怂了一波开小号A了…
可是还是非常慢!
可是还是非常慢!
可是还是非常慢!
非常重要所以说三遍!
居然跑了14sQAQ
最后还是认为真是蛮难调的…
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 3000010
using namespace std;
int Q;
char ch[MAXN],s[MAXN];
string chars;
int top,sta[MAXN];
int mask,ans;
void gets(int mask)
{
scanf("%s",s);
chars=s;
int len=chars.length();
for (int j=0;j<len;j++)
{
mask=(mask*131+j)%len;
char t=chars[j];
chars[j]=chars[mask];
chars[mask]=t;
}
}
struct lct
{
int ch[2],fa,flag,w;
bool rev;
}tree[MAXN];
void modify(int x,int delta)
{
if (x) tree[x].w+=delta,tree[x].flag+=delta;
}
void push_down(int x)
{
if (tree[x].flag)
{
modify(tree[x].ch[0],tree[x].flag);modify(tree[x].ch[1],tree[x].flag);
tree[x].flag=0;
}
}
bool is_root(int x)
{
return tree[tree[x].fa].ch[0]!=x&&tree[tree[x].fa].ch[1]!=x;
}
void rot(int x)
{
int y=tree[x].fa,z=tree[y].fa,l,r;
l=(tree[y].ch[1]==x);r=l^1;
if (!is_root(y)) tree[z].ch[tree[z].ch[1]==y]=x;
tree[y].fa=x;tree[x].fa=z;tree[tree[x].ch[r]].fa=y;
tree[y].ch[l]=tree[x].ch[r];tree[x].ch[r]=y;
}
void Splay(int x)
{
sta[++top]=x;
for (int i=x;!is_root(i);i=tree[i].fa) sta[++top]=tree[i].fa;
while (top) push_down(sta[top--]);
while (!is_root(x))
{
int y=tree[x].fa,z=tree[y].fa;
if (!is_root(y))
{
if ((tree[y].ch[0]==x)^(tree[z].ch[0]==y)) rot(x);
else rot(y);
}
rot(x);
}
}
void access(int x)
{
for (int i=0;x;i=x,x=tree[x].fa) Splay(x),tree[x].ch[1]=i;
}
void make_root(int x)
{
access(x);Splay(x);//tree[x].rev^=1;
}
void link(int x,int y)
{
tree[x].fa=y;make_root(y);modify(y,tree[x].w);
}
void cut(int x)
{
make_root(x);modify(tree[x].ch[0],-tree[x].w);tree[tree[x].ch[0]].fa=0;tree[x].ch[0]=0;
}
struct sam
{
int cnt,last,p,q,np,nq;
int a[MAXN][26],len[MAXN],fa[MAXN];
sam()
{
last=++cnt;
}
void insert(int c)
{
p=last;last=np=++cnt;len[np]=len[p]+1;tree[np].w=1;
while (!a[p][c]&&p) a[p][c]=np,p=fa[p];
if (!p) fa[np]=1,link(np,1);
else
{
q=a[p][c];
if (len[q]==len[p]+1) fa[np]=q,link(np,q);
else
{
nq=++cnt;len[nq]=len[p]+1;
memcpy(a[nq],a[q],sizeof(a[q]));
fa[nq]=fa[q];link(nq,fa[q]);
fa[q]=fa[np]=nq;cut(q);link(q,nq);link(np,nq);
while (a[p][c]==q) a[p][c]=nq,p=fa[p];
}
}
}
int getans()
{
gets(mask);
int st=1,Len=chars.length();
for (int i=0;i<Len;i++)
if (!(st=a[st][chars[i]-'A'])) return 0;
Splay(st);
return tree[st].w;
}
}sam;
int main()
{
scanf("%d",&Q);scanf("%s",ch);
int len=strlen(ch);
for (int i=0;i<len;i++) sam.insert(ch[i]-'A');
while (Q--)
{
scanf("%s",ch);
if (ch[0]=='A')
{
gets(mask);
len=chars.length();
for (int i=0;i<len;i++) sam.insert(chars[i]-'A');
}
else
{
ans=sam.getans();mask^=ans;
printf("%d
",ans);
}
}
}