BZOJ2555: SubString
? 解题记录 ? ? 后缀自动机 ? ? Splay ?    2018-07-24 17:51:37    356    0    0

Description

懒得写背景了,给你一个字符串init,要求你支持两个操作
(1):在当前字符串的后面插入一个字符串
(2):询问字符串s在当前字符串中出现了几次?(作为连续子串)
你必须在线支持这些操作。

Input

第一行一个数Q表示操作个数
第二行一个字符串表示初始字符串init
接下来Q行,每行2个字符串Type,Str
Type是ADD的话表示在后面插入字符串。
Type是QUERY的话表示询问某字符串在当前字符串中出现了几次。
为了体现在线操作,你需要维护一个变量mask,初始值为0 

    

读入串Str之后,使用这个过程将之解码成真正询问的串TrueStr。
询问的时候,对TrueStr询问后输出一行答案Result
然后mask=maskxorResult
插入的时候,将TrueStr插到当前字符串后面即可。
HINT:ADD和QUERY操作的字符串都需要解压
长度 <= 600000,询问次数<= 10000,询问总长度<= 3000000
新加数据一组--2015.05.20

Output

 

Sample Input

2
A
QUERY B
ADD BBABBBBAAB

Sample Output

0

HINT


——有些时候即使是板题,你也写不出来……

相当于动态维护Right集合的大小,也就是要动态维护parent树。

这个操作可以LCT上路径加解决。

不过子树问题可以用Splay进栈出栈序做。

具体的方法是树上的每一个节点有两个点在Splay上。

把这两个点之间的区间splay出来就是子树点。


#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 1.2e6 + 5;
  
int id[maxn][2];
namespace Splay {
    struct node {
        int siz, fa, ch[2], s;
    }t[maxn << 1];
    int root, cnt;
    const int L = 0, R = 1;
    void init() {
        root = 2;
        t[id[0][0] = ++cnt] = (node) {1, 2, 0, 0, 1};
        t[id[0][1] = ++cnt] = (node) {2, 0, 1, 0, 1};
    }
    void push_up(int rt) {
        t[rt].siz = t[t[rt].ch[L]].siz + t[t[rt].ch[R]].siz + t[rt].s;
    }
    void rotate(int rt) {
        int p = t[rt].fa, a = t[p].fa;
        int r = t[p].ch[R] == rt, l = r ^ 1;
        if(a) t[a].ch[t[a].ch[R] == p] = rt;
        t[rt].fa = a, t[p].fa = rt, t[t[rt].ch[l]].fa = p;
        t[p].ch[r] = t[rt].ch[l], t[rt].ch[l] = p;
        push_up(p), push_up(rt);
    }
    void splay(int x, int y) {
        int des = t[y].fa;
        while(t[x].fa != des) {
            int p = t[x].fa, a = t[p].fa;
            if(a != des)
                if((t[a].ch[R] == p) ^ (t[p].ch[R] == x)) rotate(x);
                else rotate(p);
            rotate(x);
        }
        if(y == root) root = x;
    }
    int Qf(int rt, int T) {
        splay(rt, root);
        rt = t[rt].ch[T];
        while(t[rt].ch[T ^ 1])
            rt = t[rt].ch[T ^ 1];
        return rt;
    }
    void insert(int x, int p, int dt) {
        splay(id[p][0], root);
        splay(id[p][1], t[root].ch[R]);
        id[x][0] = ++cnt, id[x][1] = ++cnt;
        t[id[x][0]] = (node) {1, id[x][1], t[id[p][1]].ch[L], 0, dt};
        t[id[x][1]] = (node) {1, id[p][1], id[x][0], 0, dt};
        t[id[p][1]].ch[L] = id[x][1];
        push_up(id[x][0]), push_up(id[x][1]);
        push_up(id[p][0]), push_up(id[p][1]);
        splay(id[x][0], root);
    }
    void rem(int x, int y) {
        int p = Qf(id[x][0], L);
        int s = Qf(id[x][1], R);
        splay(p, root);
        splay(s, t[root].ch[R]);
        int now = t[s].ch[L];
        t[now].fa = 0, t[s].ch[L] = 0;
        push_up(s), push_up(p);
        splay(id[y][0], root);
        splay(id[y][1], t[root].ch[R]);
        int q = id[y][1];
        while(t[q].ch[L]) q = t[q].ch[L];
        t[q].ch[L] = now, t[now].fa = q;
        while(q) push_up(q), q = t[q].fa;
        splay(now, root);
    }
    int query(int x) {
        splay(id[x][0], root);
        splay(id[x][1], t[root].ch[R]);
        return t[t[id[x][1]].ch[L]].siz / 2 + t[id[x][1]].s;
    }
}
  
namespace SAM {
    char rs[maxn];
    int trie[maxn << 1][26], len[maxn << 1], fa[maxn << 1];
    int last = 1, cnt = 1, tot;
    void add(char x) {
        using namespace Splay;
        int id = x - 'A';
        rs[tot] = x;
        int p = last, np = ++cnt;
        last = np, len[np] = (tot++) + 1;
        while(p && !trie[p][id])
            trie[p][id] = np, p = fa[p];
        if(!p) 
            fa[np] = 1, insert(np, 1, 1);
        else {
            int q = trie[p][id];
            if(len[q] == len[p] + 1) 
                fa[np] = q, insert(np, q, 1);
            else {
                int lca = ++cnt;
                len[lca] = len[p] + 1;
                memcpy(trie[lca], trie[q], sizeof(trie[q]));
                fa[lca] = fa[q], insert(lca, fa[q], 0);
                fa[np] = fa[q] = lca;
                insert(np, lca, 1), rem(q, lca);
                while(p && trie[p][id] == q)
                    trie[p][id] = lca, p = fa[p];
            }
        }
    }
}
int mask, m;
const int mxn = 3e6 + 5;
char s[mxn];
string chars;
void gets(int mask)
{
    scanf("%s",s);
    chars=s;
    for (int j=0;j<chars.length();j++) 
    {
        mask=(mask*131+j)%chars.length();
        char t=chars[j];
        chars[j]=chars[mask];
        chars[mask]=t;
    }
}
int main() {
    using namespace Splay;
    using namespace SAM;
    init();
    insert(1, 0, 1);
    scanf("%d", &m);
    scanf("%s", s);
    int l = strlen(s);
    for(register int i = 0; i < l; ++i)
        add(s[i]);
    for(register int i = 1; i <= m; ++i) {
        scanf("%s", s);
        if(s[0] == 'A') {
            gets(mask), l = chars.length();
            for(register int i = 0; i < l; ++i) 
                add(chars[i]);
        } else {
            gets(mask), l = chars.length();
            int now = 1, id, ans;
            for(register int i = 0; i < l; ++i) {
                id = chars[i] - 'A';
                if(trie[now][id]) now = trie[now][id];
                else {now = -1; break;}
            }
            if(~now) printf("%d\n", ans = query(now));
            else printf("0\n"), ans = 0;
            mask ^= ans;
        }
    }
    return 0;
}


上一篇: CodeChef-PrimeDST Prime Distance On Tree

下一篇: 博客每周歌曲 1~4

356 人读过
立即登录, 发表评论.
没有帐号? 立即注册
0 条评论
文档导航