P5212 SubString LCT+SAM
阿新 • • 發佈:2019-02-24
static end 匹配 要求 init 一行 this getchar char 。
,詢問總長度\(\leq 3 \times 10^6\)
$ \color{#0066ff}{ 題目描述 }$
給定一個字符串init
,要求支持兩個操作
- 在當前字符串的後面插入一個字符串
- 詢問字符串ss在當前字符串中出現了幾次?(作為連續子串)
強制在線。
\(\color{#0066ff}{輸入格式}\)
第一行一個整數\(Q\)表示操作個數
第二行一個字符串表示初始字符串init
接下來Q行,每行2個字符串Type
,Str
Type
是ADD
,表示在後面插入字符串。Type
是QUERY
,表示詢問某字符串在當前字符串中出現了幾次。
為了體現在線操作,你需要維護一個變量mask
,初始值為00
讀入串Str
之後,使用這個過程將之解碼成真正詢問的串TrueStr
詢問的時候,對TrueStr
詢問後輸出一行答案Result
然後\(mask=mask \bigoplus Result\)
插入的時候,將TrueStr
插到當前字符串後面即可。
註意:ADD和QUERY操作的字符串都需要解壓
\(\color{#0066ff}{輸出格式}\)
對於每一個QUERY
操作,輸出詢問的字符串在當前字符串中出現了幾次。
\(\color{#0066ff}{輸入樣例}\)
2
A
QUERY B
ADD BBABBBBAAB
\(\color{#0066ff}{輸出樣例}\)
0
\(\color{#0066ff}{數據範圍與提示}\)
\(∣S∣≤6×10^5,Q \leq 10^4\)
為防止評測過慢,對於測試點2 3 5 6 8 11 時限為3s,其余為1s
\(\color{#0066ff}{題解}\)
每次插入字符,還要匹配, 顯然SAM再合適不過
匹配的時候,找到那個點\(O(len)\),那麽答案就是parent樹的子樹大小
但是這個樹是動態的。。,於是。。。。LCT啊。。
LCT維護子樹和即可
// luogu-judger-enable-o2 #include<bits/stdc++.h> #define LL long long LL in() { char ch; LL x = 0, f = 1; while(!isdigit(ch = getchar()))(ch == '-') && (f = -f); for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48)); return x * f; } const int maxn = 6e6 + 1; const int maxm = 1.2e6 + 1; struct LCT { protected: struct node { node *ch[2], *fa; int tot, siz, val, rev; node(int tot = 0, int siz = 0, int val = 0, int rev = 0): tot(tot), siz(siz), val(val), rev(rev) {} void trn() { std::swap(ch[0], ch[1]), rev ^= 1; } void dwn() { if(!rev) return; if(ch[0]) ch[0]->trn(); if(ch[1]) ch[1]->trn(); rev = 0; } void upd() { tot = siz + val; if(ch[0]) tot += ch[0]->tot; if(ch[1]) tot += ch[1]->tot; } bool isr() { return fa->ch[1] == this; } bool ntr() { return fa && (fa->ch[1] == this || fa->ch[0] == this); } }pool[maxm]; void rot(node *x) { node *y = x->fa, *z = y->fa; bool k = x->isr(); node *w = x->ch[!k]; if(y->ntr()) z->ch[y->isr()] = x; (x->ch[!k] = y)->ch[k] = w; (y->fa = x)->fa = z; if(w) w->fa = y; y->upd(), x->upd(); } void splay(node *o) { static node *st[maxm]; int top; st[top = 1] = o; while(st[top]->ntr()) st[top + 1] = st[top]->fa, top++; while(top) st[top--]->dwn(); while(o->ntr()) { if(o->fa->ntr()) rot(o->isr() ^ o->fa->isr()? o : o->fa); rot(o); } } void access(node *x) { for(node *y = NULL; x; x = (y = x)->fa) { splay(x); if(x->ch[1]) x->siz += x->ch[1]->tot; if((x->ch[1] = y)) x->siz -= x->ch[1]->tot; x->upd(); } } void makeroot(node *x) { access(x), splay(x), x->trn(); } void link(node *x, node *y) { makeroot(x), access(y), splay(y); (x->fa = y)->siz += x->tot; y->upd(); } void cut(node *x, node *y) { makeroot(y), access(x), splay(x); assert(x->ch[0] == y); x->ch[0] = y->fa = NULL, x->upd(); } public: friend struct SAM; }c; struct SAM { protected: struct node { node *ch[26], *fa; int len, siz; node(int len = 0, int siz = 0): len(len), siz(siz) {} }pool[maxm]; node *root, *tail, *lst; LCT::node *id(node *x) { return c.pool + (x - pool); } void extend(int s) { node *o = new(tail++) node(lst->len + 1, 1), *v = lst; id(o)->val = 1, id(o)->upd(); for(; v && !v->ch[s]; v = v->fa) v->ch[s] = o; if(!v) o->fa = root, c.link(id(o), id(root)); else if(v->len + 1 == v->ch[s]->len) o->fa = v->ch[s], c.link(id(o), id(v->ch[s])); else { node *n = new(tail++) node(v->len + 1), *d = v->ch[s]; std::copy(d->ch, d->ch + 26, n->ch); id(n)->upd(); c.cut(id(d), id(d->fa)); c.link(id(n), id(d->fa)); c.link(id(d), id(n)); c.link(id(o), id(n)); n->fa = d->fa, d->fa = o->fa = n; for(; v && v->ch[s] == d; v = v->fa) v->ch[s] = n; } lst = o; } void clr() { tail = pool; root = lst = new(tail++) node(); } public: SAM() { clr(); } void ins(char *s) { for(char *p = s; *p; p++) extend(*p - 'A'); } int getans(char *s) { node *o = root; for(char *p = s; *p; p++) { int pos = *p - 'A'; if(o->ch[pos]) o = o->ch[pos]; else return 0; } c.makeroot(id(root)); c.access(id(o)); c.splay(id(o)); return id(o)->val + id(o)->siz; } }s; char ls[maxn]; int n, len; void doit(int ans) { for(int i = 0; i < len; i++) { ans = (ans * 131 + i) % len; std::swap(ls[i], ls[ans]); } } int main() { n = in(); scanf("%s", ls); s.ins(ls); int mask = 0, ans; while(n --> 0) { scanf("%s", ls); if(ls[0] == 'A') { scanf("%s", ls); len = strlen(ls); doit(mask); s.ins(ls); } else { scanf("%s", ls); len = strlen(ls); doit(mask); printf("%d\n", ans = s.getans(ls)); mask ^= ans; } } return 0; }
P5212 SubString LCT+SAM