懒得写背景了,给你一个字符串init,要求你支持两个操作
(1):在当前字符串的后面插入一个字符串
(2):询问字符串s在当前字符串中出现了几次?(作为连续子串)
你必须在线支持这些操作。
第一行一个数Q表示操作个数
第二行一个字符串表示初始字符串init
接下来Q行,每行2个字符串Type,Str
Type是ADD的话表示在后面插入字符串。
Type是QUERY的话表示询问某字符串在当前字符串中出现了几次。
为了体现在线操作,你需要维护一个变量mask,初始值为0
读入串Str之后,使用这个过程将之解码成真正询问的串TrueStr。
询问的时候,对TrueStr询问后输出一行答案Result
然后mask = mask xor Result
插入的时候,将TrueStr插到当前字符串后面即可。
HINT:ADD和QUERY操作的字符串都需要解压
2
A
QUERY B
ADD BBABBBBAAB
0
40 % 的数据字符串最终长度 <= 20000,询问次数<= 1000,询问总长度<= 10000
100 % 的数据字符串最终长度 <= 600000,询问次数<= 10000,询问总长度<= 3000000
新加数据一组–2015.05.20
Ctsc模拟赛By 洁妹
顺手复习了一下LCT…细节处理什么的早忘了TAT
因为强制在线,还支持后面插入字符串,所以需要用后缀自动机,要找某个串在其中出现多少次,就是求这个串的right集合大小,也就是parent树的子树大小…
插入一个字符,这个字符在它所处的parent链上对它的祖先每个贡献了1,需要每个祖先加1
然而因为数据加强了,不能暴力修改(实测T掉了…)所以需要把这个点到根节点的权值加1…
因为后缀自动机的建立过程中parent树是不断加边、删边的,所以LCT维护parent树…
细节处理:copy的时候别忘了copyright集合大小,想得到q的在LCT中的权值v需要先pushpath一遍,查询的时候需要得到LCT中的真实值所以要pushpath一遍
这是我学的最复杂的两个数据结构了…
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int SZ = 2000010;
const int MAXN = 1200010;
namespace LCT{
struct node{
node *ch[2],*f;
int sz,sum,v;
bool rev;
int add;
void maintain()
{
sum = v + ch[0] -> sum + ch[1] -> sum;
sz = ch[0] -> sz + 1 + ch[2] -> sz;
}
void pushdown();
int dir() { return f -> ch[1] == this; }
bool isroot() { return f -> ch[0] != this && f -> ch[1] != this;}
void setc(node* x,int d) { (ch[d] = x) -> f = this; }
}T[SZ],*tree[SZ],*null;
int Tcnt = 0;
node* newnode(int x)
{
node *k = T + (Tcnt ++);
k -> ch[1] = k -> ch[0] = k -> f = null;
k -> sz = 1;
k -> sum = k -> v = x;
k -> add = k -> rev = 0;
return k;
}
void pushrev(node *p)
{
if(p == null) return;
p -> rev ^= 1;
swap(p -> ch[0],p -> ch[1]);
}
void pushadd(node *p,int add)
{
if(p == null) return;
p -> v += add;
p -> sum += add * p -> sz;
p -> add += add;
}
void node :: pushdown()
{
if(rev)
pushrev(ch[0]),pushrev(ch[1]),rev = 0;
if(add)
pushadd(ch[0],add),pushadd(ch[1],add),add = 0;
}
node *S[SZ];
int top = 0;
void pushpath(node *p)
{
while(!p -> isroot())
S[++ top] = p,p = p -> f;
S[++ top] = p;
while(top) S[top --] -> pushdown();
}
void rotate(node *p)
{
node *fa = p -> f;
int d = p -> dir();
p -> f = fa -> f;
if(!fa -> isroot())
p -> f -> ch[fa -> dir()] = p;
fa -> ch[d] = p -> ch[d ^ 1];
if(fa -> ch[d] != null)
fa -> ch[d] -> f = fa;
p -> setc(fa,d ^ 1);
fa -> maintain(); p -> maintain();
}
void splay(node *p)
{
pushpath(p);
while(!p -> isroot())
{
if(p -> f -> isroot()) rotate(p);
else
{
if(p -> dir() == p -> f -> dir())
rotate(p -> f),rotate(p);
else
rotate(p),rotate(p);
}
}
p -> maintain();
}
void access(node *p)
{
node *last = null;
while(p != null)
{
splay(p);
p -> ch[1] = last;
p -> maintain();
last = p;
p = p -> f;
}
}
void toroot(node *p)
{
access(p);
splay(p);
pushrev(p);
}
void cut(node *x,node *y)
{
toroot(x);
access(y);
splay(y);
y -> ch[0] = x -> f = null;
}
void link(node *x,node *y)
{
toroot(x);
x -> f = y;
}
void add(node *x,node *y,int d)
{
toroot(x);
access(y);
splay(y);
pushadd(y,d);
}
int ask(node *x,node *y)
{
toroot(x);
access(y);
splay(y);
return y -> sum;
}
void init()
{
null = newnode(0);
null -> sz = 0;
for(int i = 0;i <= MAXN;i ++)
tree[i] = newnode(0);
}
};
namespace SAM{
struct sam_node{
sam_node *ch[5],*par;
int val;
}T[SZ], *root, *last;
LCT :: node* getnode(sam_node *p)
{
return LCT :: tree[p - T];
}
int Tcnt = 0;
sam_node* newnode(int x)
{
sam_node *k = T + (Tcnt ++);
k -> val = x;
k -> par = 0;
memset(k -> ch,0,sizeof(k -> ch));
return k;
}
void sam_insert(int x)
{
sam_node *p = last,*np = newnode(last -> val + 1);
while(p && !p -> ch[x])
p -> ch[x] = np,p = p -> par;
if(!p)
{
np -> par = root;
LCT :: link(getnode(np),getnode(root));
}
else
{
sam_node *q = p -> ch[x];
if(q -> val == p -> val + 1)
{
np -> par = q;
LCT :: link(getnode(np),getnode(q));
}
else
{
sam_node *nq = newnode(p -> val + 1);
LCT :: cut(getnode(q),getnode(q -> par));
LCT :: link(getnode(nq),getnode(q -> par));
LCT :: link(getnode(nq),getnode(q));
LCT :: link(getnode(nq),getnode(np));
pushpath(getnode(q));
getnode(nq) -> v = getnode(q) -> v;
memcpy(nq -> ch,q -> ch,sizeof(nq -> ch));
nq -> par = q -> par;
np -> par = q -> par = nq;
while(p && p -> ch[x] == q)
p -> ch[x] = nq,p = p -> par;
}
}
LCT :: add(getnode(np),getnode(root),1);
last = np;
}
int ask(char s[])
{
int l = strlen(s);
sam_node *p = root;
for(int i = 0;i < l;i ++)
{
int c = s[i] - 'A' + 1;
if(!p -> ch[c]) return 0;
p = p -> ch[c];
}
LCT :: pushpath(getnode(p));
return getnode(p) -> v;
}
void init()
{
root = newnode(0);
last = root;
}
}
void jieya(char s[],int mask)
{
int l = strlen(s);
for(int i = 0;i < l;i ++)
{
mask = (mask * 131 + i) % l;
swap(s[i],s[mask]);
}
}
char s[SZ],opt[233];
int main()
{
SAM :: init();
LCT :: init();
int n;
scanf("%d",&n);
scanf("%s",s);
int l = strlen(s);
for(int i = 0;i < l;i ++)
SAM::sam_insert(s[i] - 'A' + 1);
int mask = 0,ans = 0;
while(n --)
{
scanf("%s",opt);
if(opt[0] == 'Q')
{
scanf("%s",s);
jieya(s,mask);
ans = SAM::ask(s);
printf("%d\n",ans);
mask ^= ans;
}
else
{
scanf("%s",s);
jieya(s,mask);
int l = strlen(s);
for(int i = 0;i < l;i ++)
SAM::sam_insert(s[i] - 'A' + 1);
}
}
return 0;
}
/*
5
AAA
QUERY A
QUERY AA
ADD BA
QUERY A
QUERY AB
*/