【bzoj2555】SubString LCT+后缀自动机

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
*/
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值