您的位置:首页 > 其它

【bzoj2555】SubString LCT+后缀自动机

2016-03-01 17:08 309 查看

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 洁妹

顺手复习了一下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
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: