BZOJ 2555: SubString

2555: SubString

Time Limit: 30 Sec   Memory Limit: 512 MB
Submit: 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

2

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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值