BZOJ2555——SubString

0、题目很短,就不概括了
给你一个字符串init,要求你支持两个操作
(1):在当前字符串的后面插入一个字符串
(2):询问字符串s在当前字符串中出现了几次?(作为连续子串)
你必须在线支持这些操作。
BZOJ2555——SubString_第1张图片
1、分析:
a)首先我们来看40%的数据,我们可以建立后缀自动机,对于插入串,我们直接暴力的insert,不要怂。。。询问的话我们就在后缀自动机上的tranc上面跑。。然后暴力的统计right集合的数量,遍历这个子树,因为每一次都会更新,所以不能预处理,然后40pts get,时间复杂度 O(n2)
b)也就是正解,我们发现a)做法的主要复杂度在于询问,询问就是求right集合,那么我们怎么快速的维护right集合呢?我们发现这个东西是个树,然后动态加点,然后维护子树和,是不是想到了lct呢?然而lct并不能维护子树的信息,是不是想到了toptree….然而toptree我都不会,怎么能写呢?所以吴大爷说这个是简单版的toptree,其实是lct…..然后我们在lct中多维护一个信息。这个信息表示他的所有虚儿子的子树的和。。那么access的时候我们要更新一下这个信息,还有link操作,为什么link操作也要维护呢?因为link操作连的虚边QAQ….然后每次询问我们可以直接依旧在后缀自动机里面一点一点的向下走,然后我们再查询这个子树,查询之前我们要Access一下,这样答案就是这个点的虚儿子+这个点是不是后缀咯。。。有个问题就是在getans的函数中我把return的p -> vs + p -> w改成p -> s就wa了QAQ,跪求神犇帮我看看
时间复杂度 O(nlogn+n)

#include <stack>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;

inline int read(){
    char ch = getchar(); int x = 0, f = 1;
    while(ch < '0' || ch > '9'){
        if(ch == '-') f = -1;
        ch = getchar();
    }
    while('0' <= ch && ch <= '9'){
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}

namespace LCT{
    struct Node{
        Node *ch[2], *fa;
        int s, vs, w;
        bool rev;

        Node();

        inline int which();

        inline void reverse(){
            if(this){
                rev ^= 1;
                swap(ch[0], ch[1]);
            }
        }

        inline void pd(){
            if(rev){
                ch[0] -> reverse();
                ch[1] -> reverse();
                rev = false;
            }
        }

        inline void maintain(){
            s = vs + w + ch[0] -> s + ch[1] -> s;
        }
    } *null = new Node, tree[1500010], *pos[1500010];
    int tot;

    Node::Node(){
        rev = false;
        s = vs = w = 0;
        ch[0] = ch[1] = fa = null;
    }

    inline int Node::which(){
        if(fa == null || (this != fa -> ch[0] && this != fa -> ch[1])) return -1;
        return this == fa -> ch[1];
    }

    inline void rotate(Node *o){
        Node *p = o -> fa;
        int l = o -> which(), r = l ^ 1;
        o -> fa = p -> fa;
        if(p -> which() != -1) p -> fa -> ch[p -> which()] = o;
        p -> ch[l] = o -> ch[r];
        if(o -> ch[r]) o -> ch[r] -> fa = p;
        o -> ch[r] = p; p -> fa = o;
        o -> ch[r] -> maintain();
        o -> maintain();
    }

    inline void splay(Node *o){
        static stack<Node*> st;
        if(!o) return;
        Node *p = o;
        while(1){
            st.push(p);
            if(p -> which() == -1) break;
            p = p -> fa;
        }
        while(!st.empty()){
            st.top() -> pd(); st.pop();
        }
        while(o -> which() != -1){
            p = o -> fa;
            if(p -> which() != -1){
                if(p -> which() ^ o -> which()) rotate(o);
                else rotate(p);
            }
            rotate(o);
        }
    }

    inline void Access(Node *o){
        Node *y = null;
        while(o != null){
          //  if(o == NULL) printf("fuck\n");
            splay(o);
          //  printf("%d\n", o -> vs);

            o -> vs += o -> ch[1] -> s;
            o -> ch[1] = y;
            o -> vs -= y -> s;
            o -> maintain();
            y = o; o = o -> fa;

        }
    }

    inline void MovetoRoot(Node *o){

        Access(o);

        splay(o);
        o -> reverse();
    }

    inline Node* FindRoot(Node *o){
        Access(o);
        splay(o);
        while(o -> ch[0] != null) o = o -> ch[0];
        return o;
    }

    inline void Link(Node *x, Node *y){
        MovetoRoot(x);
        x -> fa = y;
        y -> vs += x -> s;
        y -> maintain();
    }

    inline void Cut(Node *x, Node *y){
        MovetoRoot(x);
        Access(y);
        splay(y);
        y -> ch[0] = x -> fa = null;
        y -> maintain();
    }
}

using namespace LCT;

struct node{
    int tranc[27], len, fa;
} a[1500010];
int p, q, np, nq;
int tail, cnt;

inline void insert(int k){

    p = tail;
    pos[cnt + 1] = &tree[cnt + 1];
    np = ++ cnt;
    a[np].len = a[tail].len + 1;
    for(p = tail; p && !a[p].tranc[k]; p = a[p].fa) a[p].tranc[k] = np;
    if(!p) a[np].fa = 1;
    else{
        q = a[p].tranc[k];
        if(a[q].len == a[p].len + 1) a[np].fa = q;
        else{
            pos[cnt + 1] = &tree[cnt + 1];
            a[nq = ++ cnt] = a[q];
            a[q].fa = a[np].fa = nq;
            a[nq].len = a[p].len + 1;
            for(; a[p].tranc[k] == q; p = a[p].fa) a[p].tranc[k] = nq;
            Cut(pos[q], pos[a[nq].fa]);
            Link(pos[nq], pos[a[nq].fa]);
            Link(pos[nq], pos[q]);
        }
    }

    tail = np;
    pos[np] -> fa = pos[a[np].fa];

    MovetoRoot(pos[np]);
   // printf("%d\n", k);
    pos[np] -> w = 1;
    pos[np] -> maintain();
}

inline int getans(Node *p){
    MovetoRoot(pos[1]);
    Access(p);
    return p -> w + p -> vs;
}

char s[1000010];

int main(){
    null -> ch[0] = null -> ch[1] = null -> fa = NULL;
    null -> vs = null -> s = null -> w = 0;
    null -> rev = false;
    int n = read();
    scanf("%s", s + 1);
    int len = strlen(s + 1);
    cnt = tail = 1;
    pos[1] = &tree[1]; tot = 1;
    for(int i = 1; i <= len; i ++) insert(s[i] - 'A' + 1);
    char qt[10];
    int mask = 0;
    for(int i = 1; i <= n; i ++){
        scanf("%s%s", qt, s);
        int len = strlen(s);
        for(int _mask = mask, j = 0; j < len; j ++){
            _mask = (_mask * 131 + j) % len;
            swap(s[_mask], s[j]);
        }
        if(qt[0] == 'A'){
           // tail = 1;
            for(int j = 0; j < len; j ++) insert(s[j] - 'A' + 1);

        }
        else{
            int t = 1, ans = 0;
            for(int j = 0; j < len; j ++){
                t = a[t].tranc[s[j] - 'A' + 1];
            }
            if(t) ans = getans(pos[t]);
            printf("%d\n", ans);
            mask ^= ans;
        }
    }
    return 0;
}

你可能感兴趣的:(substring,后缀自动机,bzoj,LCT,2555)