1. 程式人生 > >bzoj2555: SubString SAM LCT

bzoj2555: SubString SAM LCT

bzoj2555: SubString

題目傳送門

分析

考慮沒有插入操作,就是字尾自動機上跑匹配,然後詢問某個節點Right集合大小。
有插入操作的話,相當於是要動態維護 p a r e n t

parent 樹上Right集合大小。
肯定只能上 L C T LCT
一種辦法是 L C
T LCT
維護子樹資訊,略麻煩。
另一種操作是,由於新增節點一定是葉子,所以可以採用不換根的LCT,每次把那個節點到根路徑的輔助樹 A c c e s
s Access
出來,在上面打標記即可。
複雜度 O ( n l o g n ) O(nlogn)

程式碼

#include<bits/stdc++.h>
#define ls ch[p][0]
#define rs ch[p][1]
const int N = 3e6 + 10;
int s[N], n, mask;
void rc() {
    char c = getchar(); for(;c < 'A' || c > 'Z'; c = getchar()) ; n = 0;
    for(;c >= 'A' && c <= 'Z'; c = getchar()) s[n++] = c - 'A';
}
void decode(int mask) {
    for(int i = 0;i < n; ++i) {
        mask = (mask * 131 + i) % n;
        std::swap(s[i], s[mask]);
    }
}
namespace LCT {
    int sum[N], tag[N], fa[N], st[N], tp, ch[N][2];
    bool Ir(int p) {return ch[fa[p]][0] != p && ch[fa[p]][1] != p;}
    bool wh(int p) {return ch[fa[p]][1] == p;}
    void Tag(int p, int w) {sum[p] += w; tag[p] += w;}
    void Push(int p) {
        if(tag[p]) {
            if(ls) Tag(ls, tag[p]);
            if(rs) Tag(rs, tag[p]);
            tag[p] = 0;
        }
    }
    void Down(int p) {
        st[tp = 1] = p;
        for(int i = p; !Ir(i); i = fa[i]) st[++tp] = fa[i];
        for(int i = tp; i; --i) Push(st[i]);
    }
    void Rotate(int p) {
        int f = fa[p], g = fa[f], c = wh(p);
        if(!Ir(f)) ch[g][wh(f)] = p; fa[p] = g;
        ch[f][c] = ch[p][c ^ 1]; if(ch[f][c]) fa[ch[f][c]] = f;
        ch[p][c ^ 1] = f; fa[f] = p;
    }
    void Splay(int p) {
        Down(p);
        for(;!Ir(p); Rotate(p))
            if(!Ir(fa[p])) Rotate(wh(fa[p]) == wh(p) ? fa[p] : p);
    }
    void Access(int x) {
        for(int pr = 0, p = x;p; pr = p, p = fa[p])
            Splay(p), rs = pr;
        Splay(x);
    }
    void Cut(int p) {
        Access(p); Tag(ls, -sum[p]);
        fa[ls] = 0; ls = 0;
    }
    void Link(int p, int f) {
        fa[p] = f; Access(f);
        Tag(f, sum[p]);
    }
    int Get(int p) {return Down(p), sum[p];}
}
struct Sam {
    int last, sz, fa[N], ch[N][26], mx[N], top;
    Sam() {last = ++top;}
    void Link(int p, int f) {fa[p] = f; LCT::Link(p, f);}
    void Extend(int c) {
        int p = last, np = last = ++top; 
        mx[np] = mx[p] + 1; LCT::sum[np] = 1;
        for(;p && !ch[p][c]; p = fa[p]) ch[p][c] = np;
        if(!p) Link(np, 1);
        else {
            int q = ch[p][c];
            if(mx[q] == mx[p] + 1) Link(np, q);
            else {
                int nq = ++top; mx[nq] = mx[p] + 1;
                memcpy(ch[nq], ch[q], sizeof(ch[nq]));
                LCT::Cut(q); Link(nq, fa[q]);
                Link(q, nq); Link(np, nq);
                for(;ch[p][c] == q; p = fa[p]) ch[p][c] = nq;
            }
        }
    }
    void Ins() {
        for(int i = 0;i < n; ++i) 
            Extend(s[i]);
    }
    int Work() {
        rc(); decode(mask);
        int u = 1;
        for(int i = 0;i < n; ++i)
            if(!(u = ch[u][s[i]])) return 0;
        int r = LCT::Get(u); mask ^= r;
        return r;
    }
}sam;
int main() {
    int q; scanf("%d", &q);
    rc(); sam.Ins();
    for(;q--;) {
        rc(); 
        if(!s[0]) rc(), decode(mask), sam.Ins();
        else printf("%d\n", sam.Work());
    }
    return 0;
}