题目链接:BZOJ2555
题目大意
要求支持操作:加入某个字符串,询问某个字符串出现的次数,强制在线。
1. 首先,可用SAM,但是需要更改的
right
集合太多,怎么办?
2. 因为每次加入新字符需要改的
right
都在从
last
到
start
的
parent
树的路径上,所以可以用LCT维护
parent
树的联通性和
right
集大小,要注意一些细节。
上代码
#include <string>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 6e5 + 10;
const int M = 13e5 + 10;
int n;
namespace LCT {
bool rev[M];
int fa[M], ch[M][2], val[M], add[M];
#define lc(a) (ch[a][0])
#define rc(a) (ch[a][1])
#define csk(a) (rc(fa[a]) == a)
#define makeLink(a, b, c) (fa[ch[a][c] = b] = a)
#define isRoot(a) (lc(fa[a]) != a && rc(fa[a]) != a)
inline void addVal(int a, int c) {
add[a] += c, val[a] += c;
}
inline void reverse(int a) {
rev[a] ^= 1, swap(lc(a), rc(a));
}
inline void pushDown(int a) {
if (rev[a]) {
reverse(lc(a)), reverse(rc(a));
rev[a] = false;
}
if (add[a]) {
addVal(lc(a), add[a]), addVal(rc(a), add[a]);
add[a] = 0;
}
}
void pushDownTo(int a) {
if (!isRoot(a))
pushDownTo(fa[a]);
pushDown(a);
}
inline void rotate(int a) {
int c = csk(a), f = fa[a];
makeLink(f, ch[a][c ^ 1], c);
if (isRoot(f)) fa[a] = fa[f];
else makeLink(fa[f], a, csk(f));
makeLink(a, f, c ^ 1);
}
inline void splay(int a) {
pushDownTo(a);
while (!isRoot(a)) {
if (!isRoot(fa[a])) {
if (csk(a) == csk(fa[a])) rotate(fa[a]);
else rotate(a);
} rotate(a);
}
}
inline void access(int a) {
splay(a), rc(a) = 0;
for (int i = fa[a]; i; i = fa[a = i])
splay(i), rc(i) = a;
}
inline void makeRoot(int a) {
access(a), splay(a), reverse(a);
}
inline void link(int a, int b) {
makeRoot(a), fa[a] = b;
}
inline void cut(int a, int b) {
makeRoot(a), access(b), splay(b);
lc(b) = fa[a] = 0;
}
inline int getVal(int a) {
return pushDownTo(a), val[a];
}
inline void modify(int a, int b, int c) {
makeRoot(a), access(b), splay(b), addVal(b, c);
}
}
int cnt, S, last;
int ch[M][26], fail[M], maxl[M];
inline void extend(int c) {
int now = ++cnt, tmp = last;
maxl[last = now] = maxl[tmp] + 1;
for (; tmp && !ch[tmp][c]; tmp = fail[tmp]) ch[tmp][c] = now;
if (!tmp) return LCT::link(now, fail[now] = S);
if (maxl[ch[tmp][c]] == maxl[tmp] + 1)
return LCT::link(now, fail[now] = ch[tmp][c]);
int r = ++cnt, q = ch[tmp][c];
LCT::cut(q, fail[q]), LCT::link(r, fail[q]);
LCT::link(q, r), LCT::link(now, r);
LCT::val[r] = LCT::getVal(q);
maxl[r] = maxl[tmp] + 1;
fail[r] = fail[q], fail[q] = fail[now] = r;
memcpy(ch[r], ch[q], sizeof(ch[q]));
for (; tmp && ch[tmp][c] == q; tmp = fail[tmp]) ch[tmp][c] = r;
}
int len;
char ss[N];
void decode(int a) {
for (int i = 0; i < len; ++i) {
a = (a * 131 + i) % len;
swap(ss[i], ss[a]);
}
}
int calc() {
int now = S;
for (int i = 0; i < len; ++i)
if (!ch[now][ss[i] - 'A']) return 0;
else now = ch[now][ss[i] - 'A'];
return LCT::getVal(now);
}
int main() {
cnt = S = last = 1;
scanf("%d %s", &n, ss), len = strlen(ss);
for (int i = 0; i < len; ++i)
extend(ss[i] - 'A'), LCT::modify(last, S, 1);
char op[10];
int ans = 0, mask = 0;
for (int i = 1; i <= n; ++i)
if (scanf("%s", op), *op == 'Q') {
scanf("%s", ss), len = strlen(ss); decode(mask);
printf("%d\n", ans = calc()), mask ^= ans;
} else {
scanf("%s", ss), len = strlen(ss); decode(mask);
for (int j = 0; j < len; ++j)
extend(ss[j] - 'A'), LCT::modify(last, S, 1);
}
return 0;
}
以上