BZOJ2555 SubString

@(XSY)[LCT]

Description

懒得写背景了,给你一个字符串init,要求你支持两个操作

  1. 在当前字符串的后面插入一个字符串
  2. 询问字符串s在当前字符串中出现了几次?(作为连续子串)
  3. 你必须在线支持这些操作。

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

Solution

这题的思路还是非常显而易见的.
由于要求在线处理, 我们对字符串用后缀自动机处理, 建立出parent tree.
根据parent tree的性质, 一个父亲节点所表示的所有substrings的出现位置相同, 并且为其所有子节点的substrings的出现位置的集合的并. 所以我们可以用link-cut-tree维护这一棵parent tree. 在插入一个字符时, 对其所对应的parent tree上到根的路径上的节点全部加一. 查询时直接输出一个点上的值即可.
link-cut-tree太久没有写过了, 非常不熟练. 代码中标注了一些写的时候容易出错的地方.

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>

const int LEN = 1 << 20, ORG = 'A', LIM = 1 << 5;

namespace Zeonfai
{
    inline int getInt()
    {
        int a = 0, sgn = 1;
        char c;
        
        while(! isdigit(c = getchar()))
            if(c == '-')
                sgn *= -1;
        
        while(isdigit(c))
            a = a * 10 + c - '0', c = getchar();
        
        return a * sgn;
    }
    
    inline int getString(char *str)
    {
        char c;
        
        while(! isgraph(c = getchar()));
        
        int len = 0;
        
        while(isgraph(c))
            str[len ++] = c, c = getchar();
        
        return len;
    }
}

struct linkCutTree
{
    struct node
    {
        node *pre, *suc[2];
        int w, tag, isRoot;

        inline node()
        {
            pre = suc[0] = suc[1] = NULL;
            w = tag = 0;
            isRoot = 1;
        }
        
        inline void add(int a)
        {
            if(this == NULL)
                return;
            
            tag += a, w += a;
        }
        
        inline void pushdown()
        {
            if(! isRoot)
                pre->pushdown();
            
            suc[0]->add(tag), suc[1]->add(tag);
            tag = 0;
        }
        
        inline int getRelation()
        {
            if(pre == NULL)
                return -1;
            
            return this == pre->suc[1];
        }
    };
    
    inline void rotate(node *u)
    {
        node *pre = u->pre, *prepre = pre->pre;
        int k = u->getRelation();
        
        if(u->suc[k ^ 1] != NULL)
            u->suc[k ^ 1]->pre = pre;
        
        pre->suc[k] = u->suc[k ^ 1];
        u->suc[k ^ 1] = pre;    
        u->pre = prepre;
        
        if(! pre->isRoot) //Link-cut-tree的Splay不要写错 
            prepre->suc[pre->getRelation()] = u;
        else
            u->isRoot = 1, pre->isRoot = 0;
            
        pre->pre = u;
    }
    
    inline void splay(node *u)
    {
        u->pushdown();
        
        while(! u->isRoot)
        {
            if(! u->pre->isRoot)
                rotate(u->getRelation() == u->pre->getRelation() ? u->pre : u);
        
            rotate(u);
        }
    }
    
    inline void access(node *u)
    {
        splay(u);
        
        while(u->pre != NULL)
        {
            node *pre = u->pre;
            splay(pre);
            
            if(pre->suc[1] != NULL)
                pre->suc[1]->isRoot = 1;
            
            u->isRoot = 0;
            pre->suc[1] = u;
            splay(u);
        }
    }
    
    inline void cut(node *u)
    {
        access(u);
        
        if(u->suc[0] != NULL)
            u->suc[0]->pre = NULL, u->suc[0]->isRoot = 1;
        
        u->suc[0] = NULL;
    }
    
    inline void link(node *u, node *pre)
    {
        cut(u);
        u->pre = pre;
    }
}tr;

struct suffixAutomaton
{
    struct state
    {
        int stp;
        linkCutTree::node *treeNode;
        state *pre, *suc[LIM];

        inline state(int _stp = 0)
        {
            stp = _stp;
            treeNode = new linkCutTree::node;
            pre = NULL;
            memset(suc, NULL, sizeof(suc));
        }
    };

    state *s, *lst;
    
    inline void init()
    {
        s = lst = new state(); //初始化时新建源点 
    }

    inline void add(int c)
    {
        state *p = lst, *u = new state(p->stp + 1);

        for(; p != NULL && p->suc[c] == NULL; p = p->pre)
            p->suc[c] = u;

        if(p == NULL)
            u->pre = s, tr.link(u->treeNode, s->treeNode);
        else
        {
            state *q = p->suc[c];

            if(q->stp == p->stp + 1)
                u->pre = q, tr.link(u->treeNode, q->treeNode);
            else
            {
                state *v = new state(p->stp + 1);
                v->pre = q->pre;
                memcpy(v->suc, q->suc, sizeof(q->suc));
                tr.link(v->treeNode, q->pre->treeNode);
                q->pre = u->pre = v;
                tr.link(q->treeNode, v->treeNode), tr.link(u->treeNode, v->treeNode);
                v->treeNode->w = q->treeNode->w;
                
                for(; p != NULL && p->suc[c] == q; p = p->pre)
                    p->suc[c] = v;
            }
        }

        lst = u;
        tr.access(u->treeNode);
        u->treeNode->add(1);
    }

    inline void insert(char *str, int len)
    {
        for(int i = 0; i < len; ++ i) //插入时不需要新建源点 
            add(str[i] - ORG);
    }
    
    inline int query(char *str, int len)
    {
        state *p = s;
        int i;
        
        for(i = 0; p != NULL && i < len; ++ i)
            p = p->suc[str[i] - 'A'];
        
        if(p != NULL)
        {
            p->treeNode->pushdown();
            return p->treeNode->w;
        }
        
        return 0;
    }
}org;

inline void decodeWithMask(char *str, int len, int mask)
{
    for(int i = 0; i < len; ++ i)
    {
        mask = (mask * 131 + i) % len;
        std::swap(str[i], str[mask]);
    }
}

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("bzoj2555.in", "r", stdin);
    freopen("bzoj2555.out", "w", stdout);
    #endif
    
    using namespace Zeonfai;

    int q = getInt();
    static char str[LEN];
    int len = getString(str);
    org.init();
    org.insert(str, len);
    int mask = 0;
    
    while(q --)
    {
        char opt[1 << 4];
        getString(opt);
        int len = getString(str);
        decodeWithMask(str, len, mask);
        
        if(opt[0] == 'A')
            org.insert(str, len);
        else
        {
            int ans = org.query(str, len);
            mask ^= ans;
            printf("%d\n", ans);
        }
    }
}

转载于:https://www.cnblogs.com/ZeonfaiHo/p/6627009.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值