2555: SubString
Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 2880 Solved: 861
[ Submit][ Status][ Discuss]
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
A
QUERY B
ADD BBABBBBAAB
Sample Output
0
HINT
40 % 的数据字符串最终长度 <= 20000,询问次数<= 1000,询问总长度<= 10000
100 % 的数据字符串最终长度 <= 600000,询问次数<= 10000,询问总长度<= 3000000
新加数据一组--2015.05.20
将后缀链接建边,当前状态cur到根的路径全部需要加1,clone不需要额外加1.
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1200005, N = 3000005;
int ch[maxn][2], fa[maxn], rev[maxn], sta[maxn];
int tag[maxn], cnt[maxn], last, sz, rt, top;
struct state
{
int len, link, next[26];
}sa[maxn];
char s[N];
void add ( int u, int w )
{
if ( u )
{
cnt[u] += w;
tag[u] += w;
}
}
bool isroot ( int u )
{
return ch[ fa[u] ][0] != u && ch[ fa[u] ][1] != u;
}
void down ( int u )
{
int l = ch[u][0], r = ch[u][1];
if ( tag[u] ) //标记下传
{
add ( l, tag[u] );
add ( r, tag[u] );
tag[u] = 0;
}
}
void Rotate ( int u, int k )
{
int x = fa[u];
if ( ! isroot ( x ) )
ch[ fa[x] ][ ch[ fa[x] ][1] == x ] = u;
fa[u] = fa[x];
fa[x] = u;
if ( ch[u][k] )
fa[ ch[u][k] ] = x;
ch[x][k^1] = ch[u][k];
ch[u][k] = x;
}
void splay ( int u )
{
top = 0;
sta[top ++] = u;
for ( int i = u; ! isroot ( i ); i = fa[i] )
sta[top ++] = fa[i];
for ( top --; top >= 0; top -- )
down ( sta[top] );
while ( ! isroot ( u ) )
{
int x = fa[u];
if ( isroot ( x ) )
Rotate ( u, ch[x][0] == u );
else
{
int y = fa[x];
int d = ch[x][0] == u, d2 = ch[y][0] == x;
Rotate ( u, d );
Rotate ( u, d2 );
}
}
}
void access ( int u )
{
int t = 0;
while ( u )
{
splay ( u );
ch[u][1] = t;
t = u;
u = fa[u];
}
}
void link ( int u, int v )
{
fa[u] = v;
access ( v );
splay ( v ); //翻转为根
add ( v, cnt[u] ); //将v至打上更新标记
}
void cut ( int u )
{
access ( u );
splay ( u );
add ( ch[u][0], -cnt[u] ); //减掉一个-cnt[u]防止重复加
fa[ ch[u][0] ] = 0;
ch[u][0] = 0;
}
void init ( )
{
sz = 0;
rt = last = ++ sz;
sa[last].len = 0;
sa[last].link = -1;
}
void sa_extend ( char c )
{
int cur = ++ sz;
sa[cur].len = sa[last].len+1;
cnt[cur] = 1;
int p;
for ( p = last; p != -1 && sa[p].next[c] == 0; p = sa[p].link )
sa[p].next[c] = cur;
if ( p == -1 )
{
sa[cur].link = rt;
link ( cur, rt );
}
else
{
int q = sa[p].next[c];
if ( sa[q].len == sa[p].len+1 )
{
sa[cur].link = q;
link ( cur, q );
}
else
{
int clone = ++ sz;
sa[clone].len = sa[p].len+1;
sa[clone].link = sa[q].link;
link ( clone, sa[q].link );
cut ( q );
cnt[clone] = 0;
memcpy ( sa[clone].next, sa[q].next, sizeof ( sa[q].next ) );
for ( ; p != -1 && sa[p].next[c] == q; p = sa[p].link )
sa[p].next[c] = clone;
sa[q].link = sa[cur].link = clone;
link ( q, clone );
link ( cur, clone );
}
}
last = cur;
}
void decodeWithMask ( int mask )
{
int len = strlen ( s );
for ( int i = 0; i < len; i ++ )
{
mask = ( mask*131+i )%len;
swap ( s[mask], s[i] );
}
}
int query ( )
{
int b = rt;
for ( int i = 0; s[i]; i ++ )
{
int c = s[i]-'A';
if ( sa[b].next[c] == 0 )
return 0;
b = sa[b].next[c];
}
splay ( b ); //将父节点未更新的标记更新下来
return cnt[b];
}
void solve ( )
{
int Q, mask = 0;
char op[15];
init ( );
scanf ( "%d%s", &Q, s );
for ( int i = 0; s[i]; i ++ )
sa_extend ( s[i]-'A' );
while ( Q -- )
{
scanf ( "%s%s", op, s );
decodeWithMask ( mask );
if ( op[0] == 'A' )
{
for ( int i = 0; s[i]; i ++ )
sa_extend ( s[i]-'A' );
}
else
{
int ans = query ( );
printf ( "%d\n", ans );
mask ^= ans;
}
}
}
int main ( )
{
solve ( );
return 0;
}