您的位置:首页 > 其它

【bzoj2555】SubString 后缀自动机+LCT

2017-06-06 15:47 471 查看
题目描述

懒得写背景了,给你一个字符串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操作的字符串都需要解压

输出

询问的时候,对TrueStr询问后输出一行答案Result

样例输入

2

A

QUERY B

ADD BBABBBBAAB

样例输出

0

题解

后缀自动机+LCT

每次插入一个字符,对应的就相当于在parent树中np到root上所有节点的出现次数+1。

只要维护这样的修改,查询时找到位置直接输出即可。

然而parent树的结构是变化的,所以我们不得不使用Link-Cut-Tree来维护parent树的结构,同时来实现区间修改以及单点查询。

具体地,在插入节点后,需要access(x)splay(x)后打上加的标记。

查询时在后缀自动机中找到位置后将标记下传,然后输出答案。

细节有点多。。。需要注意的几点:原始字符串不需要解密、解密过程中不修改实际维护的mask值(解密函数的mask是数值传递)、查询时先把标记下传。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 1200010
using namespace std;
int next
[26] , pre
, dis
, last = 1 , tot = 1;
int fa
, c[2]
, w
, tag
;
char opt[10] , str
;
void read(int mask)
{
scanf("%s" , str);
int i , l = strlen(str);
for(i = 0 ; i < l ; i ++ ) mask = (mask * 131 + i) % l , swap(str[i] , str[mask]);
}
bool isroot(int x)
{
return c[0][fa[x]] != x && c[1][fa[x]] != x;
}
void add(int x , int a)
{
w[x] += a , tag[x] += a;
}
void pushdown(int x)
{
if(tag[x])
{
w[c[0][x]] += tag[x] , tag[c[0][x]] += tag[x];
w[c[1][x]] += tag[x] , tag[c[1][x]] += tag[x];
tag[x] = 0;
}
}
void update(int x)
{
if(!isroot(x)) update(fa[x]);
pushdown(x);
}
void rotate(int x)
{
int y = fa[x] , z = fa[y] , l = (c[1][y] == x) , r = l ^ 1;
if(!isroot(y)) c[c[1][z] == y][z] = x;
fa[x] = z , fa[y] = x , fa[c[r][x]] = y , c[l][y] = c[r][x] , c[r][x] = y;
}
void splay(int x)
{
update(x);
while(!isroot(x))
{
int y = fa[x] , z = fa[y];
if(!isroot(y))
{
if((c[0][y] == x) ^ (c[0][z] == y)) rotate(x);
else rotate(y);
}
rotate(x);
}
}
void access(int x)
{
int t = 0;
while(x) splay(x) , c[1][x] = t , t = x , x = fa[x];
}
void cut(int x)
{
access(x) , splay(x) , c[0][x] = fa[c[0][x]] = 0;
}
void link(int x , int y)
{
cut(x) , fa[x] = y;
}
void ins(int c)
{
int p = last , np = last = ++tot;
dis[np] = dis[p] + 1;
while(p && !next[p][c]) next[p][c] = np , p = pre[p];
if(!p) pre[np] = 1 , link(np , 1);
else
{
int q = next[p][c];
if(dis[q] == dis[p] + 1) pre[np] = q , link(np , q);
else
{
int nq = ++tot;
memcpy(next[nq] , next[q] , sizeof(next[q])) , dis[nq] = dis[p] + 1;
pre[nq] = pre[q] , link(nq , pre[q]);
pre[q] = nq , link(q , nq);
pre[np] = nq , link(np , nq);
while(p && next[p][c] == q) next[p][c] = nq , p = pre[p];
update(q) , w[nq] = w[q];
}
}
access(np) , splay(np) , add(np , 1);
}
int query()
{
int t , i , l = strlen(str);
for(i = 0 , t = 1 ; i < l ; i ++ )
{
if(!next[t][str[i] - 'A']) return 0;
t = next[t][str[i] - 'A'];
}
update(t);
return w[t];
}
int main()
{
int n , mask = 0 , i , l , t;
scanf("%d%s" , &n , str) , l = strlen(str);
for(i = 0 ; i < l ; i ++ ) ins(str[i] - 'A');
while(n -- )
{
scanf("%s" , opt) , read(mask);
if(opt[0] == 'A')
{
l = strlen(str);
for(i = 0 ; i < l ; i ++ ) ins(str[i] - 'A');
}
else printf("%d\n" , t = query()) , mask ^= t;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: