zoukankan      html  css  js  c++  java
  • 【bzoj2555】SubString 后缀自动机+LCT

    题目描述

    懒得写背景了,给你一个字符串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[N][26] , pre[N] , dis[N] , last = 1 , tot = 1;
    int fa[N] , c[2][N] , w[N] , tag[N];
    char opt[10] , str[N];
    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
    " , t = query()) , mask ^= t;
        }
        return 0;
    }
    

     

  • 相关阅读:
    fast incremental backup failed on standby database
    How to find error message from OMS repository
    Examine 11g automatic block Corruption recovery
    C#继承Control实用自定义控件
    手把手教你写SHELL CODE
    编写C#控件的3种方式
    Android中跨越ACTIVITY的全局线程
    DevExpress 皮肤使用方法
    PHP讨论之什么是HOOK?
    C#制作WinForm控件
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6951955.html
Copyright © 2011-2022 走看看