bzoj2555: SubString SAM LCT
阿新 • • 發佈:2019-01-03
bzoj2555: SubString
分析
考慮沒有插入操作,就是字尾自動機上跑匹配,然後詢問某個節點Right集合大小。
有插入操作的話,相當於是要動態維護
樹上Right集合大小。
肯定只能上
一種辦法是
維護子樹資訊,略麻煩。
另一種操作是,由於新增節點一定是葉子,所以可以採用不換根的LCT,每次把那個節點到根路徑的輔助樹
出來,在上面打標記即可。
複雜度
程式碼
#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;
}