Description
懒得写背景了,给你一个字符串init,要求你支持两个操作
(1):在当前字符串的后面插入一个字符串
(2):询问字符串s在当前字符串中出现了几次?(作为连续子串)
你必须在线支持这些操作。
毒瘤
显然就是sam求endpos大小,强套LCT。
时隔多年又打了一次维护子树大小。
大致就是维护:
fsum[x]表示虚父亲为x的tsum和。
tsum[x]表示x的splay和,=tsum[child] + fsum[x] + v[x]
总共有几个细节需要注意
- access时相当于实化一条虚边,添加一条虚边。要修改贡献,不必考虑对更上方的影响因为会access到。
- link时要添加虚边,此时假若是从fa[a]=b,则需要对b修改贡献。将b access并splay,就不用考虑对上方的贡献了。
- cut时也要相应的减去贡献。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int QQ,mask,le;
const int N = 6e5 + 10, E = 4e6 + 10;
char s[E],type[10];
void decode(int mask) {
// cout<<"SDFSADF"<<mask<<endl;
for (int i = 0; i < le; i++) {
mask = (mask * 131 + i) % le;
swap(s[i],s[mask]);
}
}
int fail[N * 2],c[N * 2][26],tot,last,v[N * 2],len[N * 2];
int fa[N * 2], fsum[N * 2], rev[N * 2], ch[N * 2][2], tsum[N * 2];
//fsum 自己虚子树大小,tsum splay子树虚子树大小 + v, v 自己权值
void update(int x) {
tsum[x] = tsum[ch[x][0]] + tsum[ch[x][1]] + fsum[x] + v[x];
}
void reverse(int x) {
if (!x) return;
rev[x] ^= 1;
swap(ch[x][0],ch[x][1]);
}
void down(int x) {
if (rev[x]) {
reverse(ch[x][0]);
reverse(ch[x][1]);
rev[x] = 0;
}
}
#define gc(x) ((ch[fa[x]][1] == (x)))
#define isroot(x) ((ch[fa[x]][0] != (x)) && (ch[fa[x]][1] != (x)))
void rotate(int x) {
int y = fa[x], z = gc(x);
ch[y][z] = ch[x][1-z];
if (ch[x][1-z]) fa[ch[x][1-z]] = y;
fa[x] = fa[y];
if (!isroot(y)) ch[fa[y]][gc(y)] = x;
fa[y] = x;
ch[x][1-z] = y;
update(y);
}
int Q[N * 2];
void splay(int x) {
int t = x;
while (!isroot(t)) Q[++Q[0]] = t, t = fa[t];
Q[++Q[0]] = t;
while (Q[0]) down(Q[Q[0]--]);
while (!isroot(x)) {
int y = fa[x];
if (!isroot(y))
if (gc(x) == gc(y))
rotate(y);
else
rotate(x);
rotate(x);
}
update(x);
}
void access(int x) {
for (int i = 0; x; i = x, x = fa[x]) {
splay(x);
fsum[x] -= tsum[i];
fsum[x] += tsum[ch[x][1]];
ch[x][1] = i;
update(x);
}
}
void makeroot(int x) {
access(x);
splay(x);
reverse(x);
}
void link(int a, int b) {
// printf("link %d %d\n",a,b);
makeroot(a);
access(a);
splay(a);
fa[a] = b;
access(b);
splay(b);
fsum[b] += tsum[a];
update(b);
}
void cut(int a, int b) {
// printf("cut %d %d\n",a,b);
makeroot(a);
access(b);
splay(a);
ch[a][1] = 0, fa[b] = 0;
tsum[a] -= tsum[b];
}
void insert(char r) {
r-='A';
int cur = ++tot; tsum[cur] = v[cur] = 1;
len[cur] = len[last] + 1;
for (; last && c[last][r] == 0; last = fail[last])
c[last][r] = cur;
if (last) {
int p = c[last][r];
if (len[p] == len[last] + 1)
link(cur,p), fail[cur] = p;
else {
int nep = ++tot;
memcpy(c[nep],c[p],sizeof c[p]);
fail[nep] = fail[p];
cut(p, fail[p]);
link(nep,fail[p]);
link(nep, p);
link(nep, cur);
fail[p] = fail[cur] = nep;
len[nep] = len[last] + 1;
for (; c[last][r] == p; last = fail[last])
c[last][r] = nep;
}
} else {
link(cur,1), fail[cur] = 1;
}
last = cur;
}
int main() {
//freopen("a.in","r",stdin);
cin>>QQ;
scanf("%s",s);
le = strlen(s);
tot = last = 1;
for (int i = 0; i < le; i++)
insert(s[i]);
for (int ww = 1; ww <= QQ; ww++) {
scanf("%s %s\n",type,s);
le = strlen(s);
decode(mask);
if (type[0] == 'Q') {
int now = 1, got = 0;
for (int i =0; i < le; i++) {
now = c[now][s[i]-'A'];
if (now == 0) {
got = 1;
printf("0\n"); break;
}
}
if (got) continue;
makeroot(1);
access(now);
mask ^= fsum[now] + v[now];
printf("%d\n",fsum[now] + v[now]);
} else {
for (int i = 0; i < le; i++)
insert(s[i]);
}
}
}